From 0a7aebadfbb3534284546aa3ca8612314c08f136 Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Tue, 26 Jun 2018 16:56:45 +0200 Subject: Update ANGLE to chromium/3280 Change-Id: I0802c0d7486f772d361f87a544d6c5af937f4ca1 Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/AUTHORS | 9 +- src/3rdparty/angle/CONTRIBUTORS | 20 + src/3rdparty/angle/LICENSE | 64 +- src/3rdparty/angle/SYSTEMINFO_LICENSE | 22 - src/3rdparty/angle/TRACEEVENT_LICENSE | 27 - src/3rdparty/angle/id/commit.h | 14 + src/3rdparty/angle/include/EGL/egl.h | 24 +- src/3rdparty/angle/include/EGL/eglext.h | 464 +- src/3rdparty/angle/include/EGL/eglext_angle.h | 170 + src/3rdparty/angle/include/EGL/eglplatform.h | 31 +- src/3rdparty/angle/include/GLES2/gl2.h | 14 +- src/3rdparty/angle/include/GLES2/gl2ext.h | 544 +- src/3rdparty/angle/include/GLES2/gl2ext_angle.h | 551 ++ src/3rdparty/angle/include/GLES3/gl3ext.h | 24 - src/3rdparty/angle/include/GLSLANG/ShaderLang.h | 667 +- src/3rdparty/angle/include/GLSLANG/ShaderVars.h | 161 +- src/3rdparty/angle/include/KHR/khrplatform.h | 9 +- src/3rdparty/angle/include/angle_gl.h | 5 - src/3rdparty/angle/include/export.h | 8 +- src/3rdparty/angle/include/platform/Platform.h | 411 +- .../angle/include/platform/WorkaroundsD3D.h | 130 + src/3rdparty/angle/src/common/BitSetIterator.h | 156 - src/3rdparty/angle/src/common/Color.h | 53 + src/3rdparty/angle/src/common/Color.inl | 37 + src/3rdparty/angle/src/common/MemoryBuffer.cpp | 105 +- src/3rdparty/angle/src/common/MemoryBuffer.h | 55 +- src/3rdparty/angle/src/common/Optional.h | 33 +- src/3rdparty/angle/src/common/angleutils.cpp | 62 +- src/3rdparty/angle/src/common/angleutils.h | 131 +- src/3rdparty/angle/src/common/bitset_utils.h | 498 ++ src/3rdparty/angle/src/common/debug.cpp | 226 +- src/3rdparty/angle/src/common/debug.h | 266 +- src/3rdparty/angle/src/common/event_tracer.cpp | 37 +- src/3rdparty/angle/src/common/event_tracer.h | 14 +- src/3rdparty/angle/src/common/mathutil.cpp | 20 +- src/3rdparty/angle/src/common/mathutil.h | 571 +- src/3rdparty/angle/src/common/matrix_utils.h | 37 + src/3rdparty/angle/src/common/platform.h | 47 +- src/3rdparty/angle/src/common/string_utils.cpp | 77 + src/3rdparty/angle/src/common/string_utils.h | 38 +- src/3rdparty/angle/src/common/system_utils.h | 27 + .../angle/src/common/system_utils_linux.cpp | 89 + src/3rdparty/angle/src/common/system_utils_mac.cpp | 94 + src/3rdparty/angle/src/common/system_utils_win.cpp | 79 + .../angle/src/common/third_party/base/README.angle | 27 + .../third_party/base/anglebase/base_export.h | 13 + .../base/anglebase/containers/mru_cache.h | 275 + .../common/third_party/base/anglebase/logging.h | 26 + .../src/common/third_party/base/anglebase/macros.h | 17 + .../third_party/base/anglebase/numerics/OWNERS | 3 + .../base/anglebase/numerics/safe_conversions.h | 179 + .../anglebase/numerics/safe_conversions_impl.h | 274 + .../base/anglebase/numerics/safe_math.h | 329 + .../base/anglebase/numerics/safe_math_impl.h | 575 ++ .../anglebase/numerics/safe_numerics_unittest.cc | 771 +++ .../src/common/third_party/base/anglebase/sha1.cc | 245 + .../src/common/third_party/base/anglebase/sha1.h | 36 + .../third_party/base/anglebase/sys_byteorder.h | 49 + .../angle/src/common/third_party/smhasher/LICENSE | 23 + .../src/common/third_party/smhasher/README.angle | 14 + .../common/third_party/smhasher/src/PMurHash.cpp | 320 + .../src/common/third_party/smhasher/src/PMurHash.h | 59 + src/3rdparty/angle/src/common/tls.cpp | 4 +- .../angle/src/common/uniform_type_info_autogen.cpp | 275 + src/3rdparty/angle/src/common/utilities.cpp | 338 +- src/3rdparty/angle/src/common/utilities.h | 97 +- src/3rdparty/angle/src/common/vector_utils.h | 523 ++ .../angle/src/compiler/fuzz/translator_fuzzer.cpp | 179 + .../src/compiler/preprocessor/DiagnosticsBase.cpp | 214 +- .../src/compiler/preprocessor/DiagnosticsBase.h | 17 +- .../compiler/preprocessor/DirectiveHandlerBase.cpp | 2 +- .../compiler/preprocessor/DirectiveHandlerBase.h | 6 +- .../src/compiler/preprocessor/DirectiveParser.cpp | 630 +- .../src/compiler/preprocessor/DirectiveParser.h | 24 +- .../src/compiler/preprocessor/ExpressionParser.h | 8 +- .../src/compiler/preprocessor/ExpressionParser.y | 85 +- .../angle/src/compiler/preprocessor/Input.cpp | 31 +- .../angle/src/compiler/preprocessor/Input.h | 26 +- .../angle/src/compiler/preprocessor/Lexer.cpp | 2 +- .../angle/src/compiler/preprocessor/Lexer.h | 4 +- .../angle/src/compiler/preprocessor/Macro.cpp | 35 +- .../angle/src/compiler/preprocessor/Macro.h | 12 +- .../src/compiler/preprocessor/MacroExpander.cpp | 297 +- .../src/compiler/preprocessor/MacroExpander.h | 55 +- .../src/compiler/preprocessor/Preprocessor.cpp | 72 +- .../angle/src/compiler/preprocessor/Preprocessor.h | 20 +- .../src/compiler/preprocessor/SourceLocation.h | 12 +- .../angle/src/compiler/preprocessor/Token.cpp | 21 +- .../angle/src/compiler/preprocessor/Token.h | 29 +- .../angle/src/compiler/preprocessor/Tokenizer.h | 17 +- .../angle/src/compiler/preprocessor/Tokenizer.l | 55 +- .../angle/src/compiler/preprocessor/numeric_lex.h | 18 +- .../angle/src/compiler/preprocessor/pp_utils.h | 18 - .../src/compiler/translator/ASTMetadataHLSL.cpp | 155 +- .../src/compiler/translator/ASTMetadataHLSL.h | 17 +- .../translator/AddAndTrueToLoopCondition.cpp | 59 + .../translator/AddAndTrueToLoopCondition.h | 20 + .../translator/AddDefaultReturnStatements.cpp | 58 + .../translator/AddDefaultReturnStatements.h | 22 + .../translator/ArrayReturnValueToOutParameter.cpp | 227 +- .../translator/ArrayReturnValueToOutParameter.h | 12 +- .../angle/src/compiler/translator/BaseTypes.h | 958 ++- .../BreakVariableAliasingInInnerLoops.cpp | 107 + .../translator/BreakVariableAliasingInInnerLoops.h | 23 + .../translator/BuiltInFunctionEmulator.cpp | 308 +- .../compiler/translator/BuiltInFunctionEmulator.h | 192 +- .../translator/BuiltInFunctionEmulatorGLSL.cpp | 166 +- .../translator/BuiltInFunctionEmulatorGLSL.h | 21 +- .../translator/BuiltInFunctionEmulatorHLSL.cpp | 551 +- .../translator/BuiltInFunctionEmulatorHLSL.h | 11 + .../angle/src/compiler/translator/Cache.cpp | 41 +- src/3rdparty/angle/src/compiler/translator/Cache.h | 36 +- .../angle/src/compiler/translator/CallDAG.cpp | 261 +- .../angle/src/compiler/translator/CallDAG.h | 16 +- .../src/compiler/translator/ClampPointSize.cpp | 47 + .../angle/src/compiler/translator/ClampPointSize.h | 22 + .../angle/src/compiler/translator/CodeGen.cpp | 81 +- .../src/compiler/translator/CollectVariables.cpp | 869 +++ .../src/compiler/translator/CollectVariables.h | 37 + .../angle/src/compiler/translator/Common.h | 73 +- .../angle/src/compiler/translator/Compiler.cpp | 1111 +-- .../angle/src/compiler/translator/Compiler.h | 221 +- .../src/compiler/translator/ConstantUnion.cpp | 681 ++ .../angle/src/compiler/translator/ConstantUnion.h | 399 +- ...DeclareAndInitBuiltinsForInstancedMultiview.cpp | 221 + .../DeclareAndInitBuiltinsForInstancedMultiview.h | 48 + .../translator/DeferGlobalInitializers.cpp | 147 + .../compiler/translator/DeferGlobalInitializers.h | 32 + .../src/compiler/translator/DetectCallDepth.cpp | 185 - .../src/compiler/translator/DetectCallDepth.h | 78 - .../compiler/translator/DetectDiscontinuity.cpp | 191 - .../src/compiler/translator/DetectDiscontinuity.h | 71 - .../angle/src/compiler/translator/Diagnostics.cpp | 105 +- .../angle/src/compiler/translator/Diagnostics.h | 46 +- .../src/compiler/translator/DirectiveHandler.cpp | 139 +- .../src/compiler/translator/DirectiveHandler.h | 14 +- .../translator/EmulateGLFragColorBroadcast.cpp | 129 + .../translator/EmulateGLFragColorBroadcast.h | 31 + .../src/compiler/translator/EmulatePrecision.cpp | 868 ++- .../src/compiler/translator/EmulatePrecision.h | 25 +- .../translator/ExpandIntegerPowExpressions.cpp | 153 + .../translator/ExpandIntegerPowExpressions.h | 29 + .../src/compiler/translator/ExtensionBehavior.cpp | 96 + .../src/compiler/translator/ExtensionBehavior.h | 65 +- .../src/compiler/translator/ExtensionGLSL.cpp | 5 + .../angle/src/compiler/translator/ExtensionGLSL.h | 7 +- .../angle/src/compiler/translator/FindMain.cpp | 38 + .../angle/src/compiler/translator/FindMain.h | 23 + .../src/compiler/translator/FindSymbolNode.cpp | 58 + .../angle/src/compiler/translator/FindSymbolNode.h | 27 + .../src/compiler/translator/FlagStd140Structs.cpp | 88 +- .../src/compiler/translator/FlagStd140Structs.h | 37 +- .../src/compiler/translator/ForLoopUnroll.cpp | 97 - .../angle/src/compiler/translator/ForLoopUnroll.h | 53 - .../angle/src/compiler/translator/HashNames.cpp | 72 + .../angle/src/compiler/translator/HashNames.h | 14 +- .../src/compiler/translator/ImageFunctionHLSL.cpp | 304 + .../src/compiler/translator/ImageFunctionHLSL.h | 76 + .../angle/src/compiler/translator/InfoSink.cpp | 38 +- .../angle/src/compiler/translator/InfoSink.h | 78 +- .../angle/src/compiler/translator/Initialize.cpp | 1252 +++- .../angle/src/compiler/translator/Initialize.h | 23 +- .../src/compiler/translator/InitializeDll.cpp | 15 +- .../angle/src/compiler/translator/InitializeDll.h | 6 +- .../src/compiler/translator/InitializeGlobals.h | 2 +- .../compiler/translator/InitializeParseContext.cpp | 42 - .../compiler/translator/InitializeParseContext.h | 17 - .../compiler/translator/InitializeVariables.cpp | 325 +- .../src/compiler/translator/InitializeVariables.h | 76 +- .../angle/src/compiler/translator/IntermNode.cpp | 3832 ++++++----- .../angle/src/compiler/translator/IntermNode.h | 847 ++- .../translator/IntermNodePatternMatcher.cpp | 157 + .../compiler/translator/IntermNodePatternMatcher.h | 75 + .../src/compiler/translator/IntermNode_util.cpp | 254 + .../src/compiler/translator/IntermNode_util.h | 60 + .../src/compiler/translator/IntermTraverse.cpp | 630 +- .../angle/src/compiler/translator/IntermTraverse.h | 355 + .../angle/src/compiler/translator/Intermediate.cpp | 508 -- .../angle/src/compiler/translator/Intermediate.h | 75 - .../compiler/translator/IsASTDepthBelowLimit.cpp | 51 + .../src/compiler/translator/IsASTDepthBelowLimit.h | 20 + .../angle/src/compiler/translator/LoopInfo.cpp | 211 - .../angle/src/compiler/translator/LoopInfo.h | 80 - src/3rdparty/angle/src/compiler/translator/MMap.h | 56 - .../angle/src/compiler/translator/NodeSearch.h | 19 +- .../angle/src/compiler/translator/Operator.cpp | 554 +- .../angle/src/compiler/translator/Operator.h | 126 +- .../angle/src/compiler/translator/OutputESSL.cpp | 17 +- .../angle/src/compiler/translator/OutputESSL.h | 23 +- .../angle/src/compiler/translator/OutputGLSL.cpp | 80 +- .../angle/src/compiler/translator/OutputGLSL.h | 17 +- .../src/compiler/translator/OutputGLSLBase.cpp | 1846 +++-- .../angle/src/compiler/translator/OutputGLSLBase.h | 76 +- .../angle/src/compiler/translator/OutputHLSL.cpp | 3606 +++++----- .../angle/src/compiler/translator/OutputHLSL.h | 186 +- .../angle/src/compiler/translator/OutputTree.cpp | 682 ++ .../angle/src/compiler/translator/OutputTree.h | 22 + .../src/compiler/translator/OutputVulkanGLSL.cpp | 80 + .../src/compiler/translator/OutputVulkanGLSL.h | 34 + .../angle/src/compiler/translator/ParamType.h | 102 + .../angle/src/compiler/translator/ParseContext.cpp | 6236 +++++++++++------ .../angle/src/compiler/translator/ParseContext.h | 767 ++- .../angle/src/compiler/translator/PoolAlloc.cpp | 227 +- .../angle/src/compiler/translator/PoolAlloc.h | 220 +- .../angle/src/compiler/translator/Pragma.h | 9 +- .../compiler/translator/PruneEmptyDeclarations.cpp | 81 - .../compiler/translator/PruneEmptyDeclarations.h | 15 - .../angle/src/compiler/translator/PruneNoOps.cpp | 156 + .../angle/src/compiler/translator/PruneNoOps.h | 24 + .../src/compiler/translator/QualifierAlive.cpp | 58 - .../angle/src/compiler/translator/QualifierAlive.h | 12 - .../src/compiler/translator/QualifierTypes.cpp | 784 +++ .../angle/src/compiler/translator/QualifierTypes.h | 191 + .../translator/RecordConstantPrecision.cpp | 94 +- .../compiler/translator/RecordConstantPrecision.h | 23 +- .../compiler/translator/RegenerateStructNames.cpp | 34 +- .../compiler/translator/RegenerateStructNames.h | 20 +- .../translator/RemoveArrayLengthMethod.cpp | 83 + .../compiler/translator/RemoveArrayLengthMethod.h | 29 + .../compiler/translator/RemoveDynamicIndexing.cpp | 319 +- .../compiler/translator/RemoveDynamicIndexing.h | 12 +- .../translator/RemoveEmptySwitchStatements.cpp | 56 + .../translator/RemoveEmptySwitchStatements.h | 18 + .../translator/RemoveInvariantDeclaration.cpp | 43 + .../translator/RemoveInvariantDeclaration.h | 18 + .../RemoveNoOpCasesFromEndOfSwitchStatements.cpp | 116 + .../RemoveNoOpCasesFromEndOfSwitchStatements.h | 21 + .../angle/src/compiler/translator/RemovePow.cpp | 36 +- .../angle/src/compiler/translator/RemovePow.h | 5 +- .../translator/RemoveSwitchFallThrough.cpp | 187 +- .../compiler/translator/RemoveSwitchFallThrough.h | 42 +- .../translator/RemoveUnreferencedVariables.cpp | 358 + .../translator/RemoveUnreferencedVariables.h | 24 + .../angle/src/compiler/translator/RenameFunction.h | 36 - .../src/compiler/translator/RewriteDoWhile.cpp | 62 +- .../angle/src/compiler/translator/RewriteDoWhile.h | 9 +- .../src/compiler/translator/RewriteElseBlocks.cpp | 112 +- .../src/compiler/translator/RewriteElseBlocks.h | 8 +- .../translator/RewriteTexelFetchOffset.cpp | 154 + .../compiler/translator/RewriteTexelFetchOffset.h | 28 + .../translator/RewriteUnaryMinusOperatorFloat.cpp | 94 + .../translator/RewriteUnaryMinusOperatorFloat.h | 19 + .../translator/RewriteUnaryMinusOperatorInt.cpp | 112 + .../translator/RewriteUnaryMinusOperatorInt.h | 20 + .../compiler/translator/RunAtTheEndOfShader.cpp | 112 + .../src/compiler/translator/RunAtTheEndOfShader.h | 23 + .../ScalarizeVecAndMatConstructorArgs.cpp | 275 +- .../translator/ScalarizeVecAndMatConstructorArgs.h | 49 +- .../angle/src/compiler/translator/SearchSymbol.cpp | 3 +- .../angle/src/compiler/translator/SearchSymbol.h | 4 +- .../translator/SeparateArrayInitialization.cpp | 76 +- .../translator/SeparateArrayInitialization.h | 6 +- .../compiler/translator/SeparateDeclarations.cpp | 52 +- .../src/compiler/translator/SeparateDeclarations.h | 7 +- .../SeparateExpressionsReturningArrays.cpp | 145 +- .../SeparateExpressionsReturningArrays.h | 12 +- .../angle/src/compiler/translator/Severity.h | 22 + .../angle/src/compiler/translator/ShaderLang.cpp | 426 +- .../angle/src/compiler/translator/ShaderVars.cpp | 397 +- .../translator/SimplifyArrayAssignment.cpp | 38 - .../compiler/translator/SimplifyArrayAssignment.h | 25 - .../compiler/translator/SimplifyLoopConditions.cpp | 300 + .../compiler/translator/SimplifyLoopConditions.h | 25 + .../compiler/translator/SplitSequenceOperator.cpp | 171 + .../compiler/translator/SplitSequenceOperator.h | 28 + .../src/compiler/translator/StructureHLSL.cpp | 448 +- .../angle/src/compiler/translator/StructureHLSL.h | 41 +- .../angle/src/compiler/translator/SymbolTable.cpp | 448 +- .../angle/src/compiler/translator/SymbolTable.h | 494 +- .../src/compiler/translator/SymbolUniqueId.cpp | 28 + .../angle/src/compiler/translator/SymbolUniqueId.h | 36 + .../compiler/translator/TextureFunctionHLSL.cpp | 1322 ++++ .../src/compiler/translator/TextureFunctionHLSL.h | 76 + .../src/compiler/translator/TranslatorESSL.cpp | 146 +- .../angle/src/compiler/translator/TranslatorESSL.h | 15 +- .../src/compiler/translator/TranslatorGLSL.cpp | 214 +- .../angle/src/compiler/translator/TranslatorGLSL.h | 17 +- .../src/compiler/translator/TranslatorHLSL.cpp | 119 +- .../angle/src/compiler/translator/TranslatorHLSL.h | 21 +- .../src/compiler/translator/TranslatorVulkan.cpp | 173 + .../src/compiler/translator/TranslatorVulkan.h | 34 + .../angle/src/compiler/translator/Types.cpp | 1045 ++- src/3rdparty/angle/src/compiler/translator/Types.h | 675 +- .../src/compiler/translator/UnfoldShortCircuit.cpp | 185 - .../src/compiler/translator/UnfoldShortCircuit.h | 38 - .../compiler/translator/UnfoldShortCircuitAST.cpp | 44 +- .../compiler/translator/UnfoldShortCircuitAST.h | 12 +- .../compiler/translator/UnfoldShortCircuitToIf.cpp | 318 +- .../compiler/translator/UnfoldShortCircuitToIf.h | 13 +- .../angle/src/compiler/translator/UniformHLSL.cpp | 434 +- .../angle/src/compiler/translator/UniformHLSL.h | 85 +- .../translator/UseInterfaceBlockFields.cpp | 105 + .../compiler/translator/UseInterfaceBlockFields.h | 30 + .../angle/src/compiler/translator/UtilsHLSL.cpp | 794 ++- .../angle/src/compiler/translator/UtilsHLSL.h | 85 +- .../translator/ValidateGlobalInitializer.cpp | 62 +- .../translator/ValidateGlobalInitializer.h | 11 +- .../compiler/translator/ValidateLimitations.cpp | 393 +- .../src/compiler/translator/ValidateLimitations.h | 58 +- .../compiler/translator/ValidateMaxParameters.cpp | 29 + .../compiler/translator/ValidateMaxParameters.h | 21 + .../src/compiler/translator/ValidateOutputs.cpp | 116 +- .../src/compiler/translator/ValidateOutputs.h | 34 +- .../src/compiler/translator/ValidateSwitch.cpp | 179 +- .../angle/src/compiler/translator/ValidateSwitch.h | 52 +- .../translator/ValidateVaryingLocations.cpp | 174 + .../compiler/translator/ValidateVaryingLocations.h | 25 + .../angle/src/compiler/translator/VariableInfo.cpp | 673 -- .../angle/src/compiler/translator/VariableInfo.h | 77 - .../src/compiler/translator/VariablePacker.cpp | 394 +- .../angle/src/compiler/translator/VariablePacker.h | 39 +- .../translator/VectorizeVectorScalarArithmetic.cpp | 284 + .../translator/VectorizeVectorScalarArithmetic.h | 25 + .../angle/src/compiler/translator/VersionGLSL.cpp | 145 +- .../angle/src/compiler/translator/VersionGLSL.h | 14 +- .../translator/WrapSwitchStatementsInBlocks.cpp | 132 + .../translator/WrapSwitchStatementsInBlocks.h | 22 + .../angle/src/compiler/translator/blocklayout.cpp | 191 +- .../angle/src/compiler/translator/blocklayout.h | 75 +- .../src/compiler/translator/blocklayoutHLSL.cpp | 63 +- .../src/compiler/translator/blocklayoutHLSL.h | 32 +- .../src/compiler/translator/compilerdebug.cpp | 37 - .../angle/src/compiler/translator/compilerdebug.h | 53 - .../translator/depgraph/DependencyGraph.cpp | 95 - .../compiler/translator/depgraph/DependencyGraph.h | 199 - .../translator/depgraph/DependencyGraphBuilder.cpp | 255 - .../translator/depgraph/DependencyGraphBuilder.h | 199 - .../translator/depgraph/DependencyGraphOutput.cpp | 64 - .../translator/depgraph/DependencyGraphOutput.h | 31 - .../depgraph/DependencyGraphTraverse.cpp | 69 - .../emulated_builtin_function_data_hlsl.json | 1382 ++++ .../emulated_builtin_functions_hlsl_autogen.cpp | 859 +++ .../angle/src/compiler/translator/glslang.h | 16 +- .../angle/src/compiler/translator/glslang.l | 183 +- .../angle/src/compiler/translator/glslang.y | 1027 ++- .../angle/src/compiler/translator/intermOut.cpp | 626 -- .../angle/src/compiler/translator/length_limits.h | 7 +- .../angle/src/compiler/translator/parseConst.cpp | 264 - .../timing/RestrictFragmentShaderTiming.cpp | 130 - .../timing/RestrictFragmentShaderTiming.h | 39 - .../timing/RestrictVertexShaderTiming.cpp | 17 - .../translator/timing/RestrictVertexShaderTiming.h | 32 - .../angle/src/compiler/translator/util.cpp | 780 ++- src/3rdparty/angle/src/compiler/translator/util.h | 60 +- .../angle/src/gpu_info_util/SystemInfo.cpp | 171 + src/3rdparty/angle/src/gpu_info_util/SystemInfo.h | 73 + .../angle/src/gpu_info_util/SystemInfo_internal.h | 38 + .../angle/src/gpu_info_util/SystemInfo_libpci.cpp | 132 + .../angle/src/gpu_info_util/SystemInfo_linux.cpp | 144 + .../angle/src/gpu_info_util/SystemInfo_mac.mm | 170 + .../angle/src/gpu_info_util/SystemInfo_win.cpp | 251 + .../angle/src/gpu_info_util/SystemInfo_x11.cpp | 53 + src/3rdparty/angle/src/id/commit.h | 3 - src/3rdparty/angle/src/image_util/copyimage.cpp | 22 + src/3rdparty/angle/src/image_util/copyimage.h | 36 + src/3rdparty/angle/src/image_util/copyimage.inl | 34 + src/3rdparty/angle/src/image_util/generatemip.h | 34 + src/3rdparty/angle/src/image_util/generatemip.inl | 268 + src/3rdparty/angle/src/image_util/imageformats.cpp | 1722 +++++ src/3rdparty/angle/src/image_util/imageformats.h | 700 ++ src/3rdparty/angle/src/image_util/loadimage.cpp | 1323 ++++ src/3rdparty/angle/src/image_util/loadimage.h | 658 ++ src/3rdparty/angle/src/image_util/loadimage.inl | 163 + .../angle/src/image_util/loadimage_etc.cpp | 1729 +++++ src/3rdparty/angle/src/libANGLE/AttributeMap.cpp | 85 +- src/3rdparty/angle/src/libANGLE/AttributeMap.h | 22 +- src/3rdparty/angle/src/libANGLE/BinaryStream.h | 97 +- src/3rdparty/angle/src/libANGLE/Buffer.cpp | 187 +- src/3rdparty/angle/src/libANGLE/Buffer.h | 100 +- src/3rdparty/angle/src/libANGLE/Caps.cpp | 940 ++- src/3rdparty/angle/src/libANGLE/Caps.h | 291 +- src/3rdparty/angle/src/libANGLE/Compiler.cpp | 143 +- src/3rdparty/angle/src/libANGLE/Compiler.h | 20 +- src/3rdparty/angle/src/libANGLE/Config.cpp | 36 +- src/3rdparty/angle/src/libANGLE/Config.h | 11 +- src/3rdparty/angle/src/libANGLE/Constants.h | 40 +- src/3rdparty/angle/src/libANGLE/Context.cpp | 5714 ++++++++++++---- src/3rdparty/angle/src/libANGLE/Context.h | 1039 ++- src/3rdparty/angle/src/libANGLE/ContextState.cpp | 839 +++ src/3rdparty/angle/src/libANGLE/ContextState.h | 164 + src/3rdparty/angle/src/libANGLE/Data.cpp | 56 - src/3rdparty/angle/src/libANGLE/Data.h | 72 - src/3rdparty/angle/src/libANGLE/Debug.cpp | 24 + src/3rdparty/angle/src/libANGLE/Debug.h | 9 + src/3rdparty/angle/src/libANGLE/Device.cpp | 21 +- src/3rdparty/angle/src/libANGLE/Display.cpp | 812 ++- src/3rdparty/angle/src/libANGLE/Display.h | 124 +- src/3rdparty/angle/src/libANGLE/Error.cpp | 58 +- src/3rdparty/angle/src/libANGLE/Error.h | 205 +- src/3rdparty/angle/src/libANGLE/Error.inl | 32 +- src/3rdparty/angle/src/libANGLE/ErrorStrings.h | 173 + src/3rdparty/angle/src/libANGLE/Fence.cpp | 48 +- src/3rdparty/angle/src/libANGLE/Fence.h | 16 +- src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 2109 +++++- src/3rdparty/angle/src/libANGLE/Framebuffer.h | 319 +- .../angle/src/libANGLE/FramebufferAttachment.cpp | 227 +- .../angle/src/libANGLE/FramebufferAttachment.h | 186 +- .../angle/src/libANGLE/HandleAllocator.cpp | 34 +- src/3rdparty/angle/src/libANGLE/HandleAllocator.h | 8 +- .../angle/src/libANGLE/HandleRangeAllocator.cpp | 229 + .../angle/src/libANGLE/HandleRangeAllocator.h | 60 + src/3rdparty/angle/src/libANGLE/Image.cpp | 205 +- src/3rdparty/angle/src/libANGLE/Image.h | 66 +- src/3rdparty/angle/src/libANGLE/ImageIndex.cpp | 130 +- src/3rdparty/angle/src/libANGLE/ImageIndex.h | 14 +- .../angle/src/libANGLE/IndexRangeCache.cpp | 8 + src/3rdparty/angle/src/libANGLE/IndexRangeCache.h | 3 + .../angle/src/libANGLE/LoggingAnnotator.cpp | 44 + src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h | 31 + .../angle/src/libANGLE/MemoryProgramCache.cpp | 772 +++ .../angle/src/libANGLE/MemoryProgramCache.h | 130 + src/3rdparty/angle/src/libANGLE/PackedGLEnums.h | 111 + .../angle/src/libANGLE/PackedGLEnums_autogen.cpp | 174 + .../angle/src/libANGLE/PackedGLEnums_autogen.h | 84 + src/3rdparty/angle/src/libANGLE/Path.cpp | 78 + src/3rdparty/angle/src/libANGLE/Path.h | 71 + src/3rdparty/angle/src/libANGLE/Platform.cpp | 56 +- src/3rdparty/angle/src/libANGLE/Program.cpp | 2897 ++++---- src/3rdparty/angle/src/libANGLE/Program.h | 641 +- .../angle/src/libANGLE/ProgramLinkedResources.cpp | 1040 +++ .../angle/src/libANGLE/ProgramLinkedResources.h | 274 + .../angle/src/libANGLE/ProgramPipeline.cpp | 65 + src/3rdparty/angle/src/libANGLE/ProgramPipeline.h | 65 + src/3rdparty/angle/src/libANGLE/Query.h | 3 +- src/3rdparty/angle/src/libANGLE/RefCountObject.cpp | 39 - src/3rdparty/angle/src/libANGLE/RefCountObject.h | 88 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp | 147 +- src/3rdparty/angle/src/libANGLE/Renderbuffer.h | 43 +- .../angle/src/libANGLE/ResourceManager.cpp | 603 +- src/3rdparty/angle/src/libANGLE/ResourceManager.h | 298 +- src/3rdparty/angle/src/libANGLE/ResourceMap.h | 305 + src/3rdparty/angle/src/libANGLE/Sampler.cpp | 73 +- src/3rdparty/angle/src/libANGLE/Sampler.h | 19 +- src/3rdparty/angle/src/libANGLE/Shader.cpp | 373 +- src/3rdparty/angle/src/libANGLE/Shader.h | 216 +- src/3rdparty/angle/src/libANGLE/SizedMRUCache.h | 174 + src/3rdparty/angle/src/libANGLE/State.cpp | 1260 +++- src/3rdparty/angle/src/libANGLE/State.h | 348 +- src/3rdparty/angle/src/libANGLE/Stream.cpp | 271 + src/3rdparty/angle/src/libANGLE/Stream.h | 143 + src/3rdparty/angle/src/libANGLE/Surface.cpp | 369 +- src/3rdparty/angle/src/libANGLE/Surface.h | 163 +- src/3rdparty/angle/src/libANGLE/Texture.cpp | 1509 +++-- src/3rdparty/angle/src/libANGLE/Texture.h | 359 +- src/3rdparty/angle/src/libANGLE/Thread.cpp | 91 + src/3rdparty/angle/src/libANGLE/Thread.h | 51 + .../angle/src/libANGLE/TransformFeedback.cpp | 159 +- .../angle/src/libANGLE/TransformFeedback.h | 61 +- src/3rdparty/angle/src/libANGLE/Uniform.cpp | 185 +- src/3rdparty/angle/src/libANGLE/Uniform.h | 100 +- src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp | 408 ++ src/3rdparty/angle/src/libANGLE/VaryingPacking.h | 184 + src/3rdparty/angle/src/libANGLE/Version.h | 15 +- src/3rdparty/angle/src/libANGLE/Version.inl | 38 +- src/3rdparty/angle/src/libANGLE/VertexArray.cpp | 235 +- src/3rdparty/angle/src/libANGLE/VertexArray.h | 188 +- .../angle/src/libANGLE/VertexAttribute.cpp | 122 +- src/3rdparty/angle/src/libANGLE/VertexAttribute.h | 84 +- .../angle/src/libANGLE/VertexAttribute.inl | 47 +- src/3rdparty/angle/src/libANGLE/Workarounds.h | 29 + src/3rdparty/angle/src/libANGLE/WorkerThread.cpp | 157 + src/3rdparty/angle/src/libANGLE/WorkerThread.h | 284 + src/3rdparty/angle/src/libANGLE/angletypes.cpp | 162 +- src/3rdparty/angle/src/libANGLE/angletypes.h | 307 +- src/3rdparty/angle/src/libANGLE/angletypes.inl | 47 +- .../angle/src/libANGLE/entry_points_enum_autogen.h | 336 + .../src/libANGLE/es3_copy_conversion_formats.json | 44 + .../libANGLE/es3_copy_conversion_table_autogen.cpp | 171 + .../src/libANGLE/es3_format_type_combinations.json | 171 + src/3rdparty/angle/src/libANGLE/features.h | 12 + .../angle/src/libANGLE/format_map_autogen.cpp | 1570 +++++ .../angle/src/libANGLE/format_map_data.json | 142 + src/3rdparty/angle/src/libANGLE/formatutils.cpp | 1365 ++-- src/3rdparty/angle/src/libANGLE/formatutils.h | 141 +- src/3rdparty/angle/src/libANGLE/histogram_macros.h | 67 +- .../angle/src/libANGLE/packed_gl_enums.json | 35 + src/3rdparty/angle/src/libANGLE/params.cpp | 68 + src/3rdparty/angle/src/libANGLE/params.h | 228 + .../angle/src/libANGLE/queryconversions.cpp | 206 +- src/3rdparty/angle/src/libANGLE/queryconversions.h | 87 +- src/3rdparty/angle/src/libANGLE/queryutils.cpp | 1916 ++++++ src/3rdparty/angle/src/libANGLE/queryutils.h | 162 + .../angle/src/libANGLE/renderer/BufferImpl.h | 49 +- .../angle/src/libANGLE/renderer/BufferImpl_mock.h | 32 +- .../angle/src/libANGLE/renderer/ContextImpl.cpp | 119 + .../angle/src/libANGLE/renderer/ContextImpl.h | 186 + .../angle/src/libANGLE/renderer/DisplayImpl.cpp | 25 +- .../angle/src/libANGLE/renderer/DisplayImpl.h | 60 +- .../angle/src/libANGLE/renderer/EGLImplFactory.h | 68 + .../angle/src/libANGLE/renderer/FenceSyncImpl.h | 35 - src/3rdparty/angle/src/libANGLE/renderer/Format.h | 105 + .../src/libANGLE/renderer/Format_ID_autogen.inl | 147 + .../src/libANGLE/renderer/Format_table_autogen.cpp | 434 ++ .../renderer/FramebufferAttachmentObjectImpl.h | 54 + .../angle/src/libANGLE/renderer/FramebufferImpl.h | 65 +- .../src/libANGLE/renderer/FramebufferImpl_mock.h | 57 +- .../angle/src/libANGLE/renderer/GLImplFactory.h | 93 + src/3rdparty/angle/src/libANGLE/renderer/Image.h | 77 - .../angle/src/libANGLE/renderer/ImageImpl.h | 16 +- .../angle/src/libANGLE/renderer/ImageImpl_mock.h | 10 +- .../angle/src/libANGLE/renderer/ImplFactory.h | 74 - .../angle/src/libANGLE/renderer/PathImpl.h | 36 + .../angle/src/libANGLE/renderer/ProgramImpl.cpp | 152 - .../angle/src/libANGLE/renderer/ProgramImpl.h | 66 +- .../angle/src/libANGLE/renderer/ProgramImpl_mock.h | 27 +- .../src/libANGLE/renderer/ProgramPipelineImpl.h | 32 + .../src/libANGLE/renderer/RenderbufferImpl.cpp | 21 - .../angle/src/libANGLE/renderer/RenderbufferImpl.h | 24 +- .../src/libANGLE/renderer/RenderbufferImpl_mock.h | 15 +- .../angle/src/libANGLE/renderer/Renderer.cpp | 62 - .../angle/src/libANGLE/renderer/Renderer.h | 121 - .../angle/src/libANGLE/renderer/SamplerImpl.h | 20 +- .../angle/src/libANGLE/renderer/ShaderImpl.h | 12 +- .../src/libANGLE/renderer/StreamProducerImpl.h | 39 + .../angle/src/libANGLE/renderer/SurfaceImpl.cpp | 8 +- .../angle/src/libANGLE/renderer/SurfaceImpl.h | 35 +- .../angle/src/libANGLE/renderer/SyncImpl.h | 34 + .../angle/src/libANGLE/renderer/TextureImpl.cpp | 63 + .../angle/src/libANGLE/renderer/TextureImpl.h | 136 +- .../angle/src/libANGLE/renderer/TextureImpl_mock.h | 116 +- .../src/libANGLE/renderer/TransformFeedbackImpl.h | 9 +- .../libANGLE/renderer/TransformFeedbackImpl_mock.h | 8 +- .../angle/src/libANGLE/renderer/VertexArrayImpl.h | 14 +- .../angle/src/libANGLE/renderer/Workarounds.h | 74 - .../src/libANGLE/renderer/angle_format_data.json | 24 + .../src/libANGLE/renderer/angle_format_map.json | 132 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.cpp | 208 +- .../angle/src/libANGLE/renderer/d3d/BufferD3D.h | 54 +- .../src/libANGLE/renderer/d3d/CompilerD3D.cpp | 10 + .../angle/src/libANGLE/renderer/d3d/CompilerD3D.h | 4 +- .../angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp | 27 +- .../angle/src/libANGLE/renderer/d3d/DeviceD3D.h | 2 +- .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 195 +- .../angle/src/libANGLE/renderer/d3d/DisplayD3D.h | 43 +- .../src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 714 +- .../angle/src/libANGLE/renderer/d3d/DynamicHLSL.h | 123 +- .../src/libANGLE/renderer/d3d/EGLImageD3D.cpp | 89 +- .../angle/src/libANGLE/renderer/d3d/EGLImageD3D.h | 27 +- .../src/libANGLE/renderer/d3d/FramebufferD3D.cpp | 305 +- .../src/libANGLE/renderer/d3d/FramebufferD3D.h | 83 +- .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 86 +- .../angle/src/libANGLE/renderer/d3d/HLSLCompiler.h | 12 +- .../angle/src/libANGLE/renderer/d3d/ImageD3D.cpp | 30 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.h | 45 +- .../src/libANGLE/renderer/d3d/IndexBuffer.cpp | 27 +- .../angle/src/libANGLE/renderer/d3d/IndexBuffer.h | 4 +- .../src/libANGLE/renderer/d3d/IndexDataManager.cpp | 250 +- .../src/libANGLE/renderer/d3d/IndexDataManager.h | 42 +- .../src/libANGLE/renderer/d3d/NativeWindowD3D.cpp | 23 + .../src/libANGLE/renderer/d3d/NativeWindowD3D.h | 38 + .../angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2199 +++--- .../angle/src/libANGLE/renderer/d3d/ProgramD3D.h | 329 +- .../src/libANGLE/renderer/d3d/RenderTargetD3D.h | 6 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.cpp | 77 +- .../src/libANGLE/renderer/d3d/RenderbufferD3D.h | 25 +- .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 703 +- .../angle/src/libANGLE/renderer/d3d/RendererD3D.h | 391 +- .../angle/src/libANGLE/renderer/d3d/SamplerD3D.h | 2 +- .../angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp | 100 +- .../angle/src/libANGLE/renderer/d3d/ShaderD3D.h | 44 +- .../libANGLE/renderer/d3d/ShaderExecutableD3D.cpp | 16 +- .../libANGLE/renderer/d3d/ShaderExecutableD3D.h | 7 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 274 +- .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.h | 97 +- .../src/libANGLE/renderer/d3d/SwapChainD3D.cpp | 34 + .../angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 55 +- .../angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 3108 ++++++--- .../angle/src/libANGLE/renderer/d3d/TextureD3D.h | 864 ++- .../src/libANGLE/renderer/d3d/TextureStorage.cpp | 39 - .../src/libANGLE/renderer/d3d/TextureStorage.h | 44 +- .../libANGLE/renderer/d3d/TransformFeedbackD3D.cpp | 46 - .../libANGLE/renderer/d3d/TransformFeedbackD3D.h | 35 - .../src/libANGLE/renderer/d3d/VaryingPacking.cpp | 397 -- .../src/libANGLE/renderer/d3d/VaryingPacking.h | 175 - .../src/libANGLE/renderer/d3d/VertexBuffer.cpp | 347 +- .../angle/src/libANGLE/renderer/d3d/VertexBuffer.h | 116 +- .../libANGLE/renderer/d3d/VertexDataManager.cpp | 750 ++- .../src/libANGLE/renderer/d3d/VertexDataManager.h | 108 +- .../src/libANGLE/renderer/d3d/WorkaroundsD3D.h | 66 - .../angle/src/libANGLE/renderer/d3d/copyimage.cpp | 22 - .../angle/src/libANGLE/renderer/d3d/copyimage.h | 35 - .../angle/src/libANGLE/renderer/d3d/copyimage.inl | 32 - .../src/libANGLE/renderer/d3d/d3d11/Blit11.cpp | 2486 ++++--- .../angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h | 230 +- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 1379 ++-- .../src/libANGLE/renderer/d3d/d3d11/Buffer11.h | 174 +- .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 1152 ++-- .../src/libANGLE/renderer/d3d/d3d11/Clear11.h | 105 +- .../src/libANGLE/renderer/d3d/d3d11/Context11.cpp | 405 ++ .../src/libANGLE/renderer/d3d/d3d11/Context11.h | 155 + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 47 +- .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 6 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 107 +- .../src/libANGLE/renderer/d3d/d3d11/Fence11.h | 11 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 461 +- .../libANGLE/renderer/d3d/d3d11/Framebuffer11.h | 78 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.cpp | 591 +- .../src/libANGLE/renderer/d3d/d3d11/Image11.h | 67 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp | 62 +- .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.h | 23 +- .../renderer/d3d/d3d11/InputLayoutCache.cpp | 464 +- .../libANGLE/renderer/d3d/d3d11/InputLayoutCache.h | 142 +- .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 97 - .../libANGLE/renderer/d3d/d3d11/NativeWindow11.h | 38 + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 205 +- .../libANGLE/renderer/d3d/d3d11/PixelTransfer11.h | 34 +- .../renderer/d3d/d3d11/ProgramPipeline11.cpp | 24 + .../renderer/d3d/d3d11/ProgramPipeline11.h | 27 + .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 363 +- .../src/libANGLE/renderer/d3d/d3d11/Query11.h | 47 +- .../renderer/d3d/d3d11/RenderStateCache.cpp | 521 +- .../libANGLE/renderer/d3d/d3d11/RenderStateCache.h | 137 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp | 359 +- .../libANGLE/renderer/d3d/d3d11/RenderTarget11.h | 90 +- .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 4140 ++++++------ .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 573 +- .../renderer/d3d/d3d11/ResourceManager11.cpp | 533 ++ .../renderer/d3d/d3d11/ResourceManager11.h | 366 + .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 111 +- .../renderer/d3d/d3d11/ShaderExecutable11.h | 45 +- .../libANGLE/renderer/d3d/d3d11/StateManager11.cpp | 2817 ++++++-- .../libANGLE/renderer/d3d/d3d11/StateManager11.h | 484 +- .../renderer/d3d/d3d11/StreamProducerNV12.cpp | 102 + .../renderer/d3d/d3d11/StreamProducerNV12.h | 44 + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 756 ++- .../src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 123 +- .../renderer/d3d/d3d11/TextureStorage11.cpp | 3713 ++++++----- .../libANGLE/renderer/d3d/d3d11/TextureStorage11.h | 555 +- .../renderer/d3d/d3d11/TransformFeedback11.cpp | 124 + .../renderer/d3d/d3d11/TransformFeedback11.h | 60 + .../src/libANGLE/renderer/d3d/d3d11/Trim11.cpp | 9 +- .../angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h | 4 +- .../libANGLE/renderer/d3d/d3d11/VertexArray11.cpp | 413 ++ .../libANGLE/renderer/d3d/d3d11/VertexArray11.h | 82 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp | 149 +- .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.h | 25 +- .../src/libANGLE/renderer/d3d/d3d11/copyvertex.inl | 45 +- .../renderer/d3d/d3d11/dxgi_format_data.json | 118 + .../renderer/d3d/d3d11/dxgi_format_map_autogen.cpp | 516 ++ .../renderer/d3d/d3d11/dxgi_support_data.json | 623 +- .../renderer/d3d/d3d11/dxgi_support_table.cpp | 1902 +++++- .../renderer/d3d/d3d11/dxgi_support_table.h | 5 + .../libANGLE/renderer/d3d/d3d11/formatutils11.cpp | 1142 ++-- .../libANGLE/renderer/d3d/d3d11/formatutils11.h | 56 +- .../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 | 2667 +++++--- .../libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 375 +- .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 644 +- .../renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl | 131 + .../d3d/d3d11/shaders/Passthrough2D11.hlsl | 11 + .../d3d/d3d11/shaders/ResolveDepthStencil.hlsl | 56 + .../shaders/compiled/passthroughrgba2dms11ps.h | 155 + .../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 | 1199 ++-- .../renderer/d3d/d3d11/texture_format_map.json | 78 + .../renderer/d3d/d3d11/texture_format_table.cpp | 35 + .../renderer/d3d/d3d11/texture_format_table.h | 89 +- .../d3d/d3d11/texture_format_table_autogen.cpp | 3037 +++++---- .../d3d/d3d11/texture_format_table_utils.h | 85 + .../renderer/d3d/d3d11/win32/NativeWindow.cpp | 220 - .../d3d/d3d11/win32/NativeWindow11Win32.cpp | 217 + .../renderer/d3d/d3d11/win32/NativeWindow11Win32.h | 53 + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 67 +- .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 48 +- .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 131 +- .../d3d/d3d11/winrt/InspectableNativeWindow.h | 38 +- .../d3d/d3d11/winrt/NativeWindow11WinRT.cpp | 126 + .../renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h | 51 + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 63 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 10 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp | 410 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h | 84 +- .../src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp | 82 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h | 46 +- .../src/libANGLE/renderer/d3d/d3d9/Context9.cpp | 303 + .../src/libANGLE/renderer/d3d/d3d9/Context9.h | 151 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h | 4 +- .../src/libANGLE/renderer/d3d/d3d9/Fence9.cpp | 19 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h | 2 +- .../libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp | 201 +- .../src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h | 38 +- .../src/libANGLE/renderer/d3d/d3d9/Image9.cpp | 303 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Image9.h | 50 +- .../libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp | 33 +- .../src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h | 16 +- .../libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp | 39 + .../src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h | 35 + .../src/libANGLE/renderer/d3d/d3d9/Query9.cpp | 76 +- .../angle/src/libANGLE/renderer/d3d/d3d9/Query9.h | 20 +- .../libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp | 3 +- .../src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h | 6 +- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 2164 +++--- .../src/libANGLE/renderer/d3d/d3d9/Renderer9.h | 407 +- .../src/libANGLE/renderer/d3d/d3d9/ShaderCache.h | 10 +- .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 6 +- .../libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h | 2 +- .../libANGLE/renderer/d3d/d3d9/StateManager9.cpp | 98 +- .../src/libANGLE/renderer/d3d/d3d9/StateManager9.h | 13 +- .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp | 123 +- .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.h | 30 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp | 219 +- .../libANGLE/renderer/d3d/d3d9/TextureStorage9.h | 84 +- .../src/libANGLE/renderer/d3d/d3d9/VertexArray9.h | 24 +- .../libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp | 94 +- .../src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h | 18 +- .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 46 +- .../renderer/d3d/d3d9/VertexDeclarationCache.h | 1 + .../libANGLE/renderer/d3d/d3d9/formatutils9.cpp | 321 +- .../src/libANGLE/renderer/d3d/d3d9/formatutils9.h | 26 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 104 +- .../libANGLE/renderer/d3d/d3d9/renderer9_utils.h | 11 +- .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps | 34 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs | 18 +- .../src/libANGLE/renderer/d3d/formatutilsD3D.cpp | 147 - .../src/libANGLE/renderer/d3d/formatutilsD3D.h | 28 +- .../angle/src/libANGLE/renderer/d3d/generatemip.h | 28 - .../src/libANGLE/renderer/d3d/generatemip.inl | 266 - .../angle/src/libANGLE/renderer/d3d/imageformats.h | 1999 ------ .../angle/src/libANGLE/renderer/d3d/loadimage.cpp | 697 -- .../angle/src/libANGLE/renderer/d3d/loadimage.h | 201 - .../angle/src/libANGLE/renderer/d3d/loadimage.inl | 156 - .../src/libANGLE/renderer/d3d/loadimageSSE2.cpp | 125 - .../src/libANGLE/renderer/d3d/loadimage_etc.cpp | 1435 ---- .../src/libANGLE/renderer/d3d/loadimage_etc.h | 140 - .../angle/src/libANGLE/renderer/driver_utils.cpp | 120 + .../angle/src/libANGLE/renderer/driver_utils.h | 73 + .../src/libANGLE/renderer/load_functions_data.json | 602 ++ .../src/libANGLE/renderer/load_functions_table.h | 22 + .../renderer/load_functions_table_autogen.cpp | 2459 +++++++ .../angle/src/libANGLE/renderer/renderer_utils.cpp | 549 ++ .../angle/src/libANGLE/renderer/renderer_utils.h | 254 + src/3rdparty/angle/src/libANGLE/signal_utils.h | 187 + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 2019 +++++- src/3rdparty/angle/src/libANGLE/validationEGL.h | 119 +- src/3rdparty/angle/src/libANGLE/validationES.cpp | 6645 +++++++++++++----- src/3rdparty/angle/src/libANGLE/validationES.h | 573 +- src/3rdparty/angle/src/libANGLE/validationES2.cpp | 7047 ++++++++++++++++---- src/3rdparty/angle/src/libANGLE/validationES2.h | 607 +- src/3rdparty/angle/src/libANGLE/validationES3.cpp | 3580 +++++++--- src/3rdparty/angle/src/libANGLE/validationES3.h | 415 +- src/3rdparty/angle/src/libANGLE/validationES31.cpp | 1786 +++++ src/3rdparty/angle/src/libANGLE/validationES31.h | 325 + src/3rdparty/angle/src/libEGL/libEGL.cpp | 117 + src/3rdparty/angle/src/libEGL/libEGL.def | 125 +- src/3rdparty/angle/src/libEGL/libEGL_mingw32.def | 125 +- src/3rdparty/angle/src/libEGL/libEGLd.def | 125 +- src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def | 48 - .../angle/src/libGLESv2/entry_points_egl.cpp | 1516 ++--- .../angle/src/libGLESv2/entry_points_egl_ext.cpp | 784 ++- .../angle/src/libGLESv2/entry_points_egl_ext.h | 67 +- .../angle/src/libGLESv2/entry_points_gles_2_0.cpp | 4155 ------------ .../angle/src/libGLESv2/entry_points_gles_2_0.h | 163 - .../libGLESv2/entry_points_gles_2_0_autogen.cpp | 2612 ++++++++ .../src/libGLESv2/entry_points_gles_2_0_autogen.h | 297 + .../src/libGLESv2/entry_points_gles_2_0_ext.cpp | 2922 ++++++-- .../src/libGLESv2/entry_points_gles_2_0_ext.h | 610 +- .../angle/src/libGLESv2/entry_points_gles_3_0.cpp | 3057 --------- .../angle/src/libGLESv2/entry_points_gles_3_0.h | 125 - .../libGLESv2/entry_points_gles_3_0_autogen.cpp | 2084 ++++++ .../src/libGLESv2/entry_points_gles_3_0_autogen.h | 284 + .../src/libGLESv2/entry_points_gles_3_0_ext.cpp | 14 - .../src/libGLESv2/entry_points_gles_3_0_ext.h | 23 - .../libGLESv2/entry_points_gles_3_1_autogen.cpp | 1430 ++++ .../src/libGLESv2/entry_points_gles_3_1_autogen.h | 228 + src/3rdparty/angle/src/libGLESv2/global_state.cpp | 250 +- src/3rdparty/angle/src/libGLESv2/global_state.h | 28 +- src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 1356 +++- src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 105 +- .../angle/src/libGLESv2/libGLESv2_mingw32.def | 714 +- src/3rdparty/angle/src/libGLESv2/libGLESv2d.def | 105 +- .../angle/src/libGLESv2/libGLESv2d_mingw32.def | 316 - src/3rdparty/angle/src/libGLESv2/proc_table.h | 24 + .../angle/src/libGLESv2/proc_table_autogen.cpp | 548 ++ .../angle/src/libGLESv2/proc_table_data.json | 662 ++ .../third_party/compiler/ArrayBoundsClamper.cpp | 10 +- .../src/third_party/compiler/ArrayBoundsClamper.h | 10 +- .../angle/src/third_party/libXNVCtrl/LICENSE | 22 + .../angle/src/third_party/libXNVCtrl/NVCtrl.c | 1240 ++++ .../angle/src/third_party/libXNVCtrl/NVCtrl.h | 4365 ++++++++++++ .../angle/src/third_party/libXNVCtrl/NVCtrlLib.h | 707 ++ .../angle/src/third_party/libXNVCtrl/README.angle | 14 + .../angle/src/third_party/libXNVCtrl/nv_control.h | 652 ++ .../angle/src/third_party/murmurhash/LICENSE | 2 - .../src/third_party/murmurhash/MurmurHash3.cpp | 335 - .../angle/src/third_party/murmurhash/MurmurHash3.h | 37 - .../src/third_party/systeminfo/SystemInfo.cpp | 2 +- .../src/third_party/trace_event/trace_event.h | 52 +- 794 files changed, 168320 insertions(+), 77109 deletions(-) delete mode 100644 src/3rdparty/angle/SYSTEMINFO_LICENSE delete mode 100644 src/3rdparty/angle/TRACEEVENT_LICENSE create mode 100644 src/3rdparty/angle/id/commit.h create mode 100644 src/3rdparty/angle/include/EGL/eglext_angle.h create mode 100644 src/3rdparty/angle/include/GLES2/gl2ext_angle.h delete mode 100644 src/3rdparty/angle/include/GLES3/gl3ext.h create mode 100644 src/3rdparty/angle/include/platform/WorkaroundsD3D.h delete mode 100644 src/3rdparty/angle/src/common/BitSetIterator.h create mode 100644 src/3rdparty/angle/src/common/Color.h create mode 100644 src/3rdparty/angle/src/common/Color.inl create mode 100644 src/3rdparty/angle/src/common/bitset_utils.h create mode 100644 src/3rdparty/angle/src/common/system_utils.h create mode 100644 src/3rdparty/angle/src/common/system_utils_linux.cpp create mode 100644 src/3rdparty/angle/src/common/system_utils_mac.cpp create mode 100644 src/3rdparty/angle/src/common/system_utils_win.cpp create mode 100644 src/3rdparty/angle/src/common/third_party/base/README.angle create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h create mode 100644 src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h create mode 100644 src/3rdparty/angle/src/common/third_party/smhasher/LICENSE create mode 100644 src/3rdparty/angle/src/common/third_party/smhasher/README.angle create mode 100644 src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp create mode 100644 src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.h create mode 100644 src/3rdparty/angle/src/common/uniform_type_info_autogen.cpp create mode 100644 src/3rdparty/angle/src/common/vector_utils.h create mode 100644 src/3rdparty/angle/src/compiler/fuzz/translator_fuzzer.cpp delete mode 100644 src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h create mode 100644 src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.h create mode 100644 src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.h create mode 100644 src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ClampPointSize.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ClampPointSize.h create mode 100644 src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/CollectVariables.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ConstantUnion.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h create mode 100644 src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/FindMain.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/FindMain.h create mode 100644 src/3rdparty/angle/src/compiler/translator/FindSymbolNode.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/FindSymbolNode.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h create mode 100644 src/3rdparty/angle/src/compiler/translator/HashNames.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h create mode 100644 src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.h create mode 100644 src/3rdparty/angle/src/compiler/translator/IntermNode_util.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/IntermNode_util.h create mode 100644 src/3rdparty/angle/src/compiler/translator/IntermTraverse.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/Intermediate.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/Intermediate.h create mode 100644 src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/LoopInfo.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/MMap.h create mode 100644 src/3rdparty/angle/src/compiler/translator/OutputTree.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/OutputTree.h create mode 100644 src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ParamType.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h create mode 100644 src/3rdparty/angle/src/compiler/translator/PruneNoOps.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/PruneNoOps.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/QualifierAlive.h create mode 100644 src/3rdparty/angle/src/compiler/translator/QualifierTypes.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/QualifierTypes.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/RenameFunction.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Severity.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.h create mode 100644 src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h create mode 100644 src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/VariableInfo.h create mode 100644 src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.h create mode 100644 src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/compilerdebug.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/compilerdebug.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/emulated_builtin_function_data_hlsl.json create mode 100644 src/3rdparty/angle/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/intermOut.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/parseConst.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo.h create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp create mode 100644 src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp delete mode 100644 src/3rdparty/angle/src/id/commit.h create mode 100644 src/3rdparty/angle/src/image_util/copyimage.cpp create mode 100644 src/3rdparty/angle/src/image_util/copyimage.h create mode 100644 src/3rdparty/angle/src/image_util/copyimage.inl create mode 100644 src/3rdparty/angle/src/image_util/generatemip.h create mode 100644 src/3rdparty/angle/src/image_util/generatemip.inl create mode 100644 src/3rdparty/angle/src/image_util/imageformats.cpp create mode 100644 src/3rdparty/angle/src/image_util/imageformats.h create mode 100644 src/3rdparty/angle/src/image_util/loadimage.cpp create mode 100644 src/3rdparty/angle/src/image_util/loadimage.h create mode 100644 src/3rdparty/angle/src/image_util/loadimage.inl create mode 100644 src/3rdparty/angle/src/image_util/loadimage_etc.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ContextState.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ContextState.h delete mode 100644 src/3rdparty/angle/src/libANGLE/Data.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/Data.h create mode 100644 src/3rdparty/angle/src/libANGLE/ErrorStrings.h create mode 100644 src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h create mode 100644 src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h create mode 100644 src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums.h create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h create mode 100644 src/3rdparty/angle/src/libANGLE/Path.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Path.h create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ProgramPipeline.h delete mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceMap.h create mode 100644 src/3rdparty/angle/src/libANGLE/SizedMRUCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/Stream.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Stream.h create mode 100644 src/3rdparty/angle/src/libANGLE/Thread.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Thread.h create mode 100644 src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VaryingPacking.h create mode 100644 src/3rdparty/angle/src/libANGLE/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/WorkerThread.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/WorkerThread.h create mode 100644 src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h create mode 100644 src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json create mode 100644 src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json create mode 100644 src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/format_map_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/packed_gl_enums.json create mode 100644 src/3rdparty/angle/src/libANGLE/params.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/params.h create mode 100644 src/3rdparty/angle/src/libANGLE/queryutils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/queryutils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Image.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/gen_load_functions_table.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h delete 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/shaders/MultiplyAlpha.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h delete 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_map.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/signal_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES31.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES31.h delete mode 100644 src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def create mode 100644 src/3rdparty/angle/src/libGLESv2/proc_table.h create mode 100644 src/3rdparty/angle/src/libGLESv2/proc_table_autogen.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/proc_table_data.json create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/LICENSE create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.c create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.h create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrlLib.h create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/README.angle create mode 100644 src/3rdparty/angle/src/third_party/libXNVCtrl/nv_control.h delete mode 100644 src/3rdparty/angle/src/third_party/murmurhash/LICENSE delete mode 100644 src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp delete mode 100644 src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h (limited to 'src/3rdparty') diff --git a/src/3rdparty/angle/AUTHORS b/src/3rdparty/angle/AUTHORS index 8de8fbddf6..5dacdf8fbd 100644 --- a/src/3rdparty/angle/AUTHORS +++ b/src/3rdparty/angle/AUTHORS @@ -1,4 +1,4 @@ -# This is the official list of The ANGLE Project Authors +# This is the official list of The ANGLE Project Authors # for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. @@ -26,6 +26,7 @@ Microsoft Open Technologies, Inc. NVIDIA Corporation Opera Software ASA The Qt Company Ltd. +Advanced Micro Devices, Inc. Jacek Caban Mark Callow @@ -42,3 +43,9 @@ Yuri O'Donnell Josh Soref Maks Naumov Jinyoung Hur +Sebastian Bergstein +James Ross-Gowan +Nickolay Artamonov +Ihsan Akmal +Andrei Volykhin +Jérôme Duval diff --git a/src/3rdparty/angle/CONTRIBUTORS b/src/3rdparty/angle/CONTRIBUTORS index 71e13b7a15..a767773b33 100644 --- a/src/3rdparty/angle/CONTRIBUTORS +++ b/src/3rdparty/angle/CONTRIBUTORS @@ -41,6 +41,7 @@ Google Inc. Justin Schuh Scott Graham Corentin Wallez + Kai Ninomiya Adobe Systems Inc. Alexandru Chiculita @@ -64,12 +65,21 @@ Intel Corporation Andy Chen Josh Triplett Sudarsana Nagineni + Jiajia Qin + Jiawei Shao + Jie Chen + Qiankun Miao + Bryan Bernhart + Yunchao He + Xinghua Cao + Brandon Jones Klarälvdalens Datakonsult AB Milian Wolff Mozilla Corp. Ehsan Akhgari + Edwin Flores Jeff Gilbert Mike Hommey Benoit Jacob @@ -85,6 +95,10 @@ David Kilzer Jacek Caban Tibor den Ouden Régis Fénéon +Sebastian Bergstein +James Ross-Gowan +Andrei Volykhin +Jérôme Duval Microsoft Corporation Cooper Partin @@ -101,7 +115,13 @@ NVIDIA Corporation Arun Patole Qingqing Deng Kimmo Kinnunen + Sami Väisänen + Martin Radev Opera Software ASA Daniel Bratell Tomasz Moniuszko + David Landell + +Advanced Micro Devices, Inc. + Russ Lind diff --git a/src/3rdparty/angle/LICENSE b/src/3rdparty/angle/LICENSE index dc322e998d..bdacb32e36 100644 --- a/src/3rdparty/angle/LICENSE +++ b/src/3rdparty/angle/LICENSE @@ -1,32 +1,32 @@ -Copyright (C) 2002-2013 The ANGLE Project Authors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. - Ltd., nor the names of their contributors may be used to endorse - or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +// Copyright (C) 2002-2013 The ANGLE Project Authors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. +// Ltd., nor the names of their contributors may be used to endorse +// or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. diff --git a/src/3rdparty/angle/SYSTEMINFO_LICENSE b/src/3rdparty/angle/SYSTEMINFO_LICENSE deleted file mode 100644 index c12444e3bc..0000000000 --- a/src/3rdparty/angle/SYSTEMINFO_LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (C) 2009 Apple Inc. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/3rdparty/angle/TRACEEVENT_LICENSE b/src/3rdparty/angle/TRACEEVENT_LICENSE deleted file mode 100644 index 34d6cd9268..0000000000 --- a/src/3rdparty/angle/TRACEEVENT_LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2013 The Chromium Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/3rdparty/angle/id/commit.h b/src/3rdparty/angle/id/commit.h new file mode 100644 index 0000000000..4c89a657c5 --- /dev/null +++ b/src/3rdparty/angle/id/commit.h @@ -0,0 +1,14 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// commit.h: +// This is a default commit hash header, when git is not available. +// + +#define ANGLE_COMMIT_HASH "unknown hash" +#define ANGLE_COMMIT_HASH_SIZE 12 +#define ANGLE_COMMIT_DATE "unknown date" + +#define ANGLE_DISABLE_PROGRAM_BINARY_LOAD diff --git a/src/3rdparty/angle/include/EGL/egl.h b/src/3rdparty/angle/include/EGL/egl.h index 9f9e021804..29f30d94de 100644 --- a/src/3rdparty/angle/include/EGL/egl.h +++ b/src/3rdparty/angle/include/EGL/egl.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013-2015 The Khronos Group Inc. +** Copyright (c) 2013-2017 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the @@ -31,14 +31,14 @@ extern "C" { ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at -** http://www.opengl.org/registry/ +** http://www.opengl.org/registry/egl ** -** Khronos $Revision: 31566 $ on $Date: 2015-06-23 08:48:48 -0700 (Tue, 23 Jun 2015) $ +** Khronos $Revision$ on $Date$ */ #include -/* Generated on date 20150623 */ +/* Generated on date 20161230 */ /* Generated C header for: * API: egl @@ -78,7 +78,7 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void); #define EGL_CONFIG_ID 0x3028 #define EGL_CORE_NATIVE_ENGINE 0x305B #define EGL_DEPTH_SIZE 0x3025 -#define EGL_DONT_CARE ((EGLint)-1) +#define EGL_DONT_CARE EGL_CAST(EGLint,-1) #define EGL_DRAW 0x3059 #define EGL_EXTENSIONS 0x3055 #define EGL_FALSE 0 @@ -95,9 +95,9 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void); #define EGL_NONE 0x3038 #define EGL_NON_CONFORMANT_CONFIG 0x3051 #define EGL_NOT_INITIALIZED 0x3001 -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) +#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0) #define EGL_PBUFFER_BIT 0x0001 #define EGL_PIXMAP_BIT 0x0002 #define EGL_READ 0x305A @@ -197,7 +197,7 @@ typedef void *EGLClientBuffer; #define EGL_RGB_BUFFER 0x308E #define EGL_SINGLE_BUFFER 0x3085 #define EGL_SWAP_BEHAVIOR 0x3093 -#define EGL_UNKNOWN ((EGLint)-1) +#define EGL_UNKNOWN EGL_CAST(EGLint,-1) #define EGL_VERTICAL_RESOLUTION 0x3091 EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api); EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void); @@ -224,7 +224,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void); #ifndef EGL_VERSION_1_4 #define EGL_VERSION_1_4 1 -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) #define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 #define EGL_MULTISAMPLE_RESOLVE 0x3099 #define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A @@ -266,7 +266,7 @@ typedef void *EGLImage; #define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull #define EGL_TIMEOUT_EXPIRED 0x30F5 #define EGL_CONDITION_SATISFIED 0x30F6 -#define EGL_NO_SYNC ((EGLSync)0) +#define EGL_NO_SYNC EGL_CAST(EGLSync,0) #define EGL_SYNC_FENCE 0x30F9 #define EGL_GL_COLORSPACE 0x309D #define EGL_GL_COLORSPACE_SRGB 0x3089 @@ -283,7 +283,7 @@ typedef void *EGLImage; #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 #define EGL_IMAGE_PRESERVED 0x30D2 -#define EGL_NO_IMAGE ((EGLImage)0) +#define EGL_NO_IMAGE EGL_CAST(EGLImage,0) EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync); EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); diff --git a/src/3rdparty/angle/include/EGL/eglext.h b/src/3rdparty/angle/include/EGL/eglext.h index 83490b8567..79f6ccd418 100644 --- a/src/3rdparty/angle/include/EGL/eglext.h +++ b/src/3rdparty/angle/include/EGL/eglext.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013-2015 The Khronos Group Inc. +** Copyright (c) 2013-2017 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the @@ -31,14 +31,14 @@ extern "C" { ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at -** http://www.opengl.org/registry/ +** http://www.khronos.org/registry/egl ** -** Khronos $Revision: 31566 $ on $Date: 2015-06-23 08:48:48 -0700 (Tue, 23 Jun 2015) $ +** Khronos $Git commit SHA1: a732b061e7 $ on $Git commit date: 2017-06-17 23:27:53 +0100 $ */ #include -#define EGL_EGLEXT_VERSION 20150623 +#define EGL_EGLEXT_VERSION 20170627 /* Generated C header for: * API: egl @@ -77,6 +77,13 @@ EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, #define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 #endif /* EGL_KHR_config_attribs */ +#ifndef EGL_KHR_context_flush_control +#define EGL_KHR_context_flush_control 1 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 +#endif /* EGL_KHR_context_flush_control */ + #ifndef EGL_KHR_create_context #define EGL_KHR_create_context 1 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 @@ -99,6 +106,42 @@ EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, #define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 #endif /* EGL_KHR_create_context_no_error */ +#ifndef EGL_KHR_debug +#define EGL_KHR_debug 1 +typedef void *EGLLabelKHR; +typedef void *EGLObjectKHR; +typedef void (EGLAPIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +#define EGL_OBJECT_THREAD_KHR 0x33B0 +#define EGL_OBJECT_DISPLAY_KHR 0x33B1 +#define EGL_OBJECT_CONTEXT_KHR 0x33B2 +#define EGL_OBJECT_SURFACE_KHR 0x33B3 +#define EGL_OBJECT_IMAGE_KHR 0x33B4 +#define EGL_OBJECT_SYNC_KHR 0x33B5 +#define EGL_OBJECT_STREAM_KHR 0x33B6 +#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9 +#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA +#define EGL_DEBUG_MSG_WARN_KHR 0x33BB +#define EGL_DEBUG_MSG_INFO_KHR 0x33BC +#define EGL_DEBUG_CALLBACK_KHR 0x33B8 +typedef EGLint (EGLAPIENTRYP PFNEGLDEBUGMESSAGECONTROLKHRPROC) (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEBUGKHRPROC) (EGLint attribute, EGLAttrib *value); +typedef EGLint (EGLAPIENTRYP PFNEGLLABELOBJECTKHRPROC) (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLint EGLAPIENTRY eglDebugMessageControlKHR (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDebugKHR (EGLint attribute, EGLAttrib *value); +EGLAPI EGLint EGLAPIENTRY eglLabelObjectKHR (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label); +#endif +#endif /* EGL_KHR_debug */ + +#ifndef EGL_KHR_display_reference +#define EGL_KHR_display_reference 1 +#define EGL_TRACK_REFERENCES_KHR 0x3352 +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC) (EGLDisplay dpy, EGLint name, EGLAttrib *value); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribKHR (EGLDisplay dpy, EGLint name, EGLAttrib *value); +#endif +#endif /* EGL_KHR_display_reference */ + #ifndef EGL_KHR_fence_sync #define EGL_KHR_fence_sync 1 typedef khronos_utime_nanoseconds_t EGLTimeKHR; @@ -161,7 +204,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sy #define EGL_KHR_image 1 typedef void *EGLImageKHR; #define EGL_NATIVE_PIXMAP_KHR 0x30B0 -#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0) typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); #ifdef EGL_EGLEXT_PROTOTYPES @@ -223,6 +266,16 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface s #endif #endif /* EGL_KHR_lock_surface3 */ +#ifndef EGL_KHR_mutable_render_buffer +#define EGL_KHR_mutable_render_buffer 1 +#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000 +#endif /* EGL_KHR_mutable_render_buffer */ + +#ifndef EGL_KHR_no_config_context +#define EGL_KHR_no_config_context 1 +#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) +#endif /* EGL_KHR_no_config_context */ + #ifndef EGL_KHR_partial_update #define EGL_KHR_partial_update 1 #define EGL_BUFFER_AGE_KHR 0x313D @@ -265,7 +318,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface #define EGL_SYNC_REUSABLE_KHR 0x30FA #define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 #define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull -#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) +#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR,0) typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); @@ -278,7 +331,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, typedef void *EGLStreamKHR; typedef khronos_uint64_t EGLuint64KHR; #ifdef KHRONOS_SUPPORT_INT64 -#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) +#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR,0) #define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 #define EGL_PRODUCER_FRAME_KHR 0x3212 #define EGL_CONSUMER_FRAME_KHR 0x3213 @@ -306,6 +359,24 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR #endif /* KHRONOS_SUPPORT_INT64 */ #endif /* EGL_KHR_stream */ +#ifndef EGL_KHR_stream_attrib +#define EGL_KHR_stream_attrib 1 +#ifdef KHRONOS_SUPPORT_INT64 +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBKHRPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribKHR (EGLDisplay dpy, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +#endif +#endif /* KHRONOS_SUPPORT_INT64 */ +#endif /* EGL_KHR_stream_attrib */ + #ifndef EGL_KHR_stream_consumer_gltexture #define EGL_KHR_stream_consumer_gltexture 1 #ifdef EGL_KHR_stream @@ -325,7 +396,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLSt #define EGL_KHR_stream_cross_process_fd 1 typedef int EGLNativeFileDescriptorKHR; #ifdef EGL_KHR_stream -#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1)) +#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR,-1) typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); #ifdef EGL_EGLEXT_PROTOTYPES @@ -402,11 +473,28 @@ EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobF #endif #endif /* EGL_ANDROID_blob_cache */ +#ifndef EGL_ANDROID_create_native_client_buffer +#define EGL_ANDROID_create_native_client_buffer 1 +#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 +#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 +#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 +#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 +typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC) (const EGLint *attrib_list); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLClientBuffer EGLAPIENTRY eglCreateNativeClientBufferANDROID (const EGLint *attrib_list); +#endif +#endif /* EGL_ANDROID_create_native_client_buffer */ + #ifndef EGL_ANDROID_framebuffer_target #define EGL_ANDROID_framebuffer_target 1 #define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 #endif /* EGL_ANDROID_framebuffer_target */ +#ifndef EGL_ANDROID_front_buffer_auto_refresh +#define EGL_ANDROID_front_buffer_auto_refresh 1 +#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C +#endif /* EGL_ANDROID_front_buffer_auto_refresh */ + #ifndef EGL_ANDROID_image_native_buffer #define EGL_ANDROID_image_native_buffer 1 #define EGL_NATIVE_BUFFER_ANDROID 0x3140 @@ -424,6 +512,15 @@ EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR #endif #endif /* EGL_ANDROID_native_fence_sync */ +#ifndef EGL_ANDROID_presentation_time +#define EGL_ANDROID_presentation_time 1 +typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; +typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time); +#endif +#endif /* EGL_ANDROID_presentation_time */ + #ifndef EGL_ANDROID_recordable #define EGL_ANDROID_recordable 1 #define EGL_RECORDABLE_ANDROID 0x3142 @@ -440,11 +537,6 @@ EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR #define EGL_D3D11_DEVICE_ANGLE 0x33A1 #endif /* EGL_ANGLE_device_d3d */ -#ifndef EGL_ANGLE_keyed_mutex -#define EGL_ANGLE_keyed_mutex 1 -#define EGL_DXGI_KEYED_MUTEX_ANGLE 0x33A2 -#endif /* EGL_ANGLE_keyed_mutex */ - #ifndef EGL_ANGLE_query_surface_pointer #define EGL_ANGLE_query_surface_pointer 1 typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); @@ -453,87 +545,30 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu #endif #endif /* EGL_ANGLE_query_surface_pointer */ -#ifndef EGL_ANGLE_software_display -#define EGL_ANGLE_software_display 1 -#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1) -#endif /* EGL_ANGLE_software_display */ - -#ifndef EGL_ANGLE_direct3d_display -#define EGL_ANGLE_direct3d_display 1 -#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2) -#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3) -#endif /* EGL_ANGLE_direct3d_display */ - #ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle #define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1 #endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */ -#ifndef EGL_ANGLE_direct_composition -#define EGL_ANGLE_direct_composition 1 -#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5 -#endif /* EGL_ANGLE_direct_composition */ - -#ifndef EGL_ANGLE_platform_angle -#define EGL_ANGLE_platform_angle 1 -#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 -#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 -#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 -#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206 -#endif /* EGL_ANGLE_platform_angle */ - -#ifndef EGL_ANGLE_platform_angle_d3d -#define EGL_ANGLE_platform_angle_d3d 1 -#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 -#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 -#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A -#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B -#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C -#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F -#endif /* EGL_ANGLE_platform_angle_d3d */ - -#ifndef EGL_ANGLE_platform_angle_opengl -#define EGL_ANGLE_platform_angle_opengl 1 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D -#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E -#endif /* EGL_ANGLE_platform_angle_opengl */ - #ifndef EGL_ANGLE_window_fixed_size #define EGL_ANGLE_window_fixed_size 1 #define EGL_FIXED_SIZE_ANGLE 0x3201 #endif /* EGL_ANGLE_window_fixed_size */ -#ifndef EGL_ANGLE_x11_visual -#define EGL_ANGLE_x11_visual -#define EGL_X11_VISUAL_ID_ANGLE 0x33A3 -#endif /* EGL_ANGLE_x11_visual */ - -#ifndef EGL_ANGLE_flexible_surface_compatibility -#define EGL_ANGLE_flexible_surface_compatibility 1 -#define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 -#endif /* EGL_ANGLE_flexible_surface_compatibility */ - -#ifndef EGL_ANGLE_surface_orientation -#define EGL_ANGLE_surface_orientation -#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7 -#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8 -#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001 -#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002 -#endif /* EGL_ANGLE_surface_orientation */ - -#ifndef EGL_ANGLE_experimental_present_path -#define EGL_ANGLE_experimental_present_path -#define EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4 -#define EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9 -#define EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE 0x33AA -#endif /* EGL_ANGLE_experimental_present_path */ +#ifndef EGL_ARM_implicit_external_sync +#define EGL_ARM_implicit_external_sync 1 +#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A +#endif /* EGL_ARM_implicit_external_sync */ #ifndef EGL_ARM_pixmap_multisample_discard #define EGL_ARM_pixmap_multisample_discard 1 #define EGL_DISCARD_SAMPLES_ARM 0x3286 #endif /* EGL_ARM_pixmap_multisample_discard */ +#ifndef EGL_EXT_bind_to_front +#define EGL_EXT_bind_to_front 1 +#define EGL_FRONT_BUFFER_EXT 0x3464 +#endif /* EGL_EXT_bind_to_front */ + #ifndef EGL_EXT_buffer_age #define EGL_EXT_buffer_age 1 #define EGL_BUFFER_AGE_EXT 0x313D @@ -543,6 +578,30 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu #define EGL_EXT_client_extensions 1 #endif /* EGL_EXT_client_extensions */ +#ifndef EGL_EXT_compositor +#define EGL_EXT_compositor 1 +#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460 +#define EGL_EXTERNAL_REF_ID_EXT 0x3461 +#define EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462 +#define EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463 +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC) (const EGLint *external_ref_ids, EGLint num_entries); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC) (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC) (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC) (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC) (EGLint external_win_id); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETSIZEEXTPROC) (EGLint external_win_id, EGLint width, EGLint height); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSWAPPOLICYEXTPROC) (EGLint external_win_id, EGLint policy); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextListEXT (const EGLint *external_ref_ids, EGLint num_entries); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextAttributesEXT (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowListEXT (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowAttributesEXT (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorBindTexWindowEXT (EGLint external_win_id); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetSizeEXT (EGLint external_win_id, EGLint width, EGLint height); +EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSwapPolicyEXT (EGLint external_win_id, EGLint policy); +#endif +#endif /* EGL_EXT_compositor */ + #ifndef EGL_EXT_create_context_robustness #define EGL_EXT_create_context_robustness 1 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF @@ -554,7 +613,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu #ifndef EGL_EXT_device_base #define EGL_EXT_device_base 1 typedef void *EGLDeviceEXT; -#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)(0)) +#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0) #define EGL_BAD_DEVICE_EXT 0x322B #define EGL_DEVICE_EXT 0x322C typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value); @@ -569,16 +628,6 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint a #endif #endif /* EGL_EXT_device_base */ -#ifndef EGL_ANGLE_device_creation -#define EGL_ANGLE_device_creation 1 -typedef EGLDeviceEXT (EGLAPIENTRYP PFNEGLCREATEDEVICEANGLEPROC) (EGLint device_type, void *native_device, const EGLAttrib *attrib_list); -typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASEDEVICEANGLEPROC) (EGLDeviceEXT device); -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLDeviceEXT EGLAPIENTRY eglCreateDeviceANGLE (EGLint device_type, void *native_device, const EGLAttrib *attrib_list); -EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE (EGLDeviceEXT device); -#endif -#endif /* EGL_ANGLE_device_creation */ - #ifndef EGL_EXT_device_drm #define EGL_EXT_device_drm 1 #define EGL_DRM_DEVICE_FILE_EXT 0x3233 @@ -597,6 +646,36 @@ EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE (EGLDeviceEXT device); #define EGL_EXT_device_query 1 #endif /* EGL_EXT_device_query */ +#ifndef EGL_EXT_gl_colorspace_bt2020_linear +#define EGL_EXT_gl_colorspace_bt2020_linear 1 +#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F +#endif /* EGL_EXT_gl_colorspace_bt2020_linear */ + +#ifndef EGL_EXT_gl_colorspace_bt2020_pq +#define EGL_EXT_gl_colorspace_bt2020_pq 1 +#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340 +#endif /* EGL_EXT_gl_colorspace_bt2020_pq */ + +#ifndef EGL_EXT_gl_colorspace_display_p3 +#define EGL_EXT_gl_colorspace_display_p3 1 +#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363 +#endif /* EGL_EXT_gl_colorspace_display_p3 */ + +#ifndef EGL_EXT_gl_colorspace_display_p3_linear +#define EGL_EXT_gl_colorspace_display_p3_linear 1 +#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362 +#endif /* EGL_EXT_gl_colorspace_display_p3_linear */ + +#ifndef EGL_EXT_gl_colorspace_scrgb +#define EGL_EXT_gl_colorspace_scrgb 1 +#define EGL_GL_COLORSPACE_SCRGB_EXT 0x3351 +#endif /* EGL_EXT_gl_colorspace_scrgb */ + +#ifndef EGL_EXT_gl_colorspace_scrgb_linear +#define EGL_EXT_gl_colorspace_scrgb_linear 1 +#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350 +#endif /* EGL_EXT_gl_colorspace_scrgb_linear */ + #ifndef EGL_EXT_image_dma_buf_import #define EGL_EXT_image_dma_buf_import 1 #define EGL_LINUX_DMA_BUF_EXT 0x3270 @@ -623,6 +702,34 @@ EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE (EGLDeviceEXT device); #define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285 #endif /* EGL_EXT_image_dma_buf_import */ +#ifndef EGL_EXT_image_dma_buf_import_modifiers +#define EGL_EXT_image_dma_buf_import_modifiers 1 +#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +#endif +#endif /* EGL_EXT_image_dma_buf_import_modifiers */ + +#ifndef EGL_EXT_image_implicit_sync_control +#define EGL_EXT_image_implicit_sync_control 1 +#define EGL_IMPORT_SYNC_TYPE_EXT 0x3470 +#define EGL_IMPORT_IMPLICIT_SYNC_EXT 0x3471 +#define EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472 +#endif /* EGL_EXT_image_implicit_sync_control */ + #ifndef EGL_EXT_multiview_window #define EGL_EXT_multiview_window 1 #define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134 @@ -632,8 +739,8 @@ EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE (EGLDeviceEXT device); #define EGL_EXT_output_base 1 typedef void *EGLOutputLayerEXT; typedef void *EGLOutputPortEXT; -#define EGL_NO_OUTPUT_LAYER_EXT ((EGLOutputLayerEXT)0) -#define EGL_NO_OUTPUT_PORT_EXT ((EGLOutputPortEXT)0) +#define EGL_NO_OUTPUT_LAYER_EXT EGL_CAST(EGLOutputLayerEXT,0) +#define EGL_NO_OUTPUT_PORT_EXT EGL_CAST(EGLOutputPortEXT,0) #define EGL_BAD_OUTPUT_LAYER_EXT 0x322D #define EGL_BAD_OUTPUT_PORT_EXT 0x322E #define EGL_SWAP_INTERVAL_EXT 0x322F @@ -670,6 +777,13 @@ EGLAPI const char *EGLAPIENTRY eglQueryOutputPortStringEXT (EGLDisplay dpy, EGLO #define EGL_OPENWF_PORT_ID_EXT 0x3239 #endif /* EGL_EXT_output_openwf */ +#ifndef EGL_EXT_pixel_format_float +#define EGL_EXT_pixel_format_float 1 +#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339 +#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A +#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B +#endif /* EGL_EXT_pixel_format_float */ + #ifndef EGL_EXT_platform_base #define EGL_EXT_platform_base 1 typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); @@ -698,9 +812,13 @@ EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, #define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6 #endif /* EGL_EXT_platform_x11 */ +#ifndef EGL_EXT_protected_content +#define EGL_EXT_protected_content 1 +#define EGL_PROTECTED_CONTENT_EXT 0x32C0 +#endif /* EGL_EXT_protected_content */ + #ifndef EGL_EXT_protected_surface #define EGL_EXT_protected_surface 1 -#define EGL_PROTECTED_CONTENT_EXT 0x32C0 #endif /* EGL_EXT_protected_surface */ #ifndef EGL_EXT_stream_consumer_egloutput @@ -711,6 +829,27 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerOutputEXT (EGLDisplay dpy, EGLStr #endif #endif /* EGL_EXT_stream_consumer_egloutput */ +#ifndef EGL_EXT_surface_CTA861_3_metadata +#define EGL_EXT_surface_CTA861_3_metadata 1 +#define EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360 +#define EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361 +#endif /* EGL_EXT_surface_CTA861_3_metadata */ + +#ifndef EGL_EXT_surface_SMPTE2086_metadata +#define EGL_EXT_surface_SMPTE2086_metadata 1 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346 +#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347 +#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348 +#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349 +#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A +#define EGL_METADATA_SCALING_EXT 50000 +#endif /* EGL_EXT_surface_SMPTE2086_metadata */ + #ifndef EGL_EXT_swap_buffers_with_damage #define EGL_EXT_swap_buffers_with_damage 1 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); @@ -779,6 +918,12 @@ EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfi #define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 #endif /* EGL_IMG_context_priority */ +#ifndef EGL_IMG_image_plane_attribs +#define EGL_IMG_image_plane_attribs 1 +#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105 +#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106 +#endif /* EGL_IMG_image_plane_attribs */ + #ifndef EGL_MESA_drm_image #define EGL_MESA_drm_image 1 #define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 @@ -811,6 +956,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImage #define EGL_PLATFORM_GBM_MESA 0x31D7 #endif /* EGL_MESA_platform_gbm */ +#ifndef EGL_MESA_platform_surfaceless +#define EGL_MESA_platform_surfaceless 1 +#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD +#endif /* EGL_MESA_platform_surfaceless */ + #ifndef EGL_NOK_swap_region #define EGL_NOK_swap_region 1 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects); @@ -894,6 +1044,129 @@ EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface sur #endif #endif /* EGL_NV_post_sub_buffer */ +#ifndef EGL_NV_robustness_video_memory_purge +#define EGL_NV_robustness_video_memory_purge 1 +#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C +#endif /* EGL_NV_robustness_video_memory_purge */ + +#ifndef EGL_NV_stream_consumer_gltexture_yuv +#define EGL_NV_stream_consumer_gltexture_yuv 1 +#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C +#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D +#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list); +#endif +#endif /* EGL_NV_stream_consumer_gltexture_yuv */ + +#ifndef EGL_NV_stream_cross_display +#define EGL_NV_stream_cross_display 1 +#define EGL_STREAM_CROSS_DISPLAY_NV 0x334E +#endif /* EGL_NV_stream_cross_display */ + +#ifndef EGL_NV_stream_cross_object +#define EGL_NV_stream_cross_object 1 +#define EGL_STREAM_CROSS_OBJECT_NV 0x334D +#endif /* EGL_NV_stream_cross_object */ + +#ifndef EGL_NV_stream_cross_partition +#define EGL_NV_stream_cross_partition 1 +#define EGL_STREAM_CROSS_PARTITION_NV 0x323F +#endif /* EGL_NV_stream_cross_partition */ + +#ifndef EGL_NV_stream_cross_process +#define EGL_NV_stream_cross_process 1 +#define EGL_STREAM_CROSS_PROCESS_NV 0x3245 +#endif /* EGL_NV_stream_cross_process */ + +#ifndef EGL_NV_stream_cross_system +#define EGL_NV_stream_cross_system 1 +#define EGL_STREAM_CROSS_SYSTEM_NV 0x334F +#endif /* EGL_NV_stream_cross_system */ + +#ifndef EGL_NV_stream_fifo_next +#define EGL_NV_stream_fifo_next 1 +#define EGL_PENDING_FRAME_NV 0x3329 +#define EGL_STREAM_TIME_PENDING_NV 0x332A +#endif /* EGL_NV_stream_fifo_next */ + +#ifndef EGL_NV_stream_fifo_synchronous +#define EGL_NV_stream_fifo_synchronous 1 +#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336 +#endif /* EGL_NV_stream_fifo_synchronous */ + +#ifndef EGL_NV_stream_frame_limits +#define EGL_NV_stream_frame_limits 1 +#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337 +#define EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338 +#endif /* EGL_NV_stream_frame_limits */ + +#ifndef EGL_NV_stream_metadata +#define EGL_NV_stream_metadata 1 +#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250 +#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251 +#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252 +#define EGL_PRODUCER_METADATA_NV 0x3253 +#define EGL_CONSUMER_METADATA_NV 0x3254 +#define EGL_PENDING_METADATA_NV 0x3328 +#define EGL_METADATA0_SIZE_NV 0x3255 +#define EGL_METADATA1_SIZE_NV 0x3256 +#define EGL_METADATA2_SIZE_NV 0x3257 +#define EGL_METADATA3_SIZE_NV 0x3258 +#define EGL_METADATA0_TYPE_NV 0x3259 +#define EGL_METADATA1_TYPE_NV 0x325A +#define EGL_METADATA2_TYPE_NV 0x325B +#define EGL_METADATA3_TYPE_NV 0x325C +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBNVPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribNV (EGLDisplay dpy, EGLint attribute, EGLAttrib *value); +EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data); +#endif +#endif /* EGL_NV_stream_metadata */ + +#ifndef EGL_NV_stream_remote +#define EGL_NV_stream_remote 1 +#define EGL_STREAM_STATE_INITIALIZING_NV 0x3240 +#define EGL_STREAM_TYPE_NV 0x3241 +#define EGL_STREAM_PROTOCOL_NV 0x3242 +#define EGL_STREAM_ENDPOINT_NV 0x3243 +#define EGL_STREAM_LOCAL_NV 0x3244 +#define EGL_STREAM_PRODUCER_NV 0x3247 +#define EGL_STREAM_CONSUMER_NV 0x3248 +#define EGL_STREAM_PROTOCOL_FD_NV 0x3246 +#endif /* EGL_NV_stream_remote */ + +#ifndef EGL_NV_stream_reset +#define EGL_NV_stream_reset 1 +#define EGL_SUPPORT_RESET_NV 0x3334 +#define EGL_SUPPORT_REUSE_NV 0x3335 +typedef EGLBoolean (EGLAPIENTRYP PFNEGLRESETSTREAMNVPROC) (EGLDisplay dpy, EGLStreamKHR stream); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglResetStreamNV (EGLDisplay dpy, EGLStreamKHR stream); +#endif +#endif /* EGL_NV_stream_reset */ + +#ifndef EGL_NV_stream_socket +#define EGL_NV_stream_socket 1 +#define EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B +#define EGL_SOCKET_HANDLE_NV 0x324C +#define EGL_SOCKET_TYPE_NV 0x324D +#endif /* EGL_NV_stream_socket */ + +#ifndef EGL_NV_stream_socket_inet +#define EGL_NV_stream_socket_inet 1 +#define EGL_SOCKET_TYPE_INET_NV 0x324F +#endif /* EGL_NV_stream_socket_inet */ + +#ifndef EGL_NV_stream_socket_unix +#define EGL_NV_stream_socket_unix 1 +#define EGL_SOCKET_TYPE_UNIX_NV 0x324E +#endif /* EGL_NV_stream_socket_unix */ + #ifndef EGL_NV_stream_sync #define EGL_NV_stream_sync 1 #define EGL_SYNC_NEW_FRAME_NV 0x321F @@ -920,7 +1193,7 @@ typedef khronos_utime_nanoseconds_t EGLTimeNV; #define EGL_SYNC_TYPE_NV 0x30ED #define EGL_SYNC_CONDITION_NV 0x30EE #define EGL_SYNC_FENCE_NV 0x30EF -#define EGL_NO_SYNC_NV ((EGLSyncNV)0) +#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV,0) typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync); @@ -961,6 +1234,9 @@ EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void); #define EGL_NATIVE_SURFACE_TIZEN 0x32A1 #endif /* EGL_TIZEN_image_native_surface */ +/* ANGLE EGL extensions */ +#include "eglext_angle.h" + #ifdef __cplusplus } #endif diff --git a/src/3rdparty/angle/include/EGL/eglext_angle.h b/src/3rdparty/angle/include/EGL/eglext_angle.h new file mode 100644 index 0000000000..95f0902838 --- /dev/null +++ b/src/3rdparty/angle/include/EGL/eglext_angle.h @@ -0,0 +1,170 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// eglext_angle.h: ANGLE modifications to the eglext.h header file. +// Currently we don't include this file directly, we patch eglext.h +// to include it implicitly so it is visible throughout our code. + +#ifndef INCLUDE_EGL_EGLEXT_ANGLE_ +#define INCLUDE_EGL_EGLEXT_ANGLE_ + +// clang-format off + +#ifndef EGL_ANGLE_robust_resource_initialization +#define EGL_ANGLE_robust_resource_initialization 1 +#define EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453 +#endif /* EGL_ANGLE_robust_resource_initialization */ + +#ifndef EGL_ANGLE_keyed_mutex +#define EGL_ANGLE_keyed_mutex 1 +#define EGL_DXGI_KEYED_MUTEX_ANGLE 0x33A2 +#endif /* EGL_ANGLE_keyed_mutex */ + +#ifndef EGL_ANGLE_d3d_texture_client_buffer +#define EGL_ANGLE_d3d_texture_client_buffer 1 +#define EGL_D3D_TEXTURE_ANGLE 0x33A3 +#endif /* EGL_ANGLE_d3d_texture_client_buffer */ + +#ifndef EGL_ANGLE_software_display +#define EGL_ANGLE_software_display 1 +#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1) +#endif /* EGL_ANGLE_software_display */ + +#ifndef EGL_ANGLE_direct3d_display +#define EGL_ANGLE_direct3d_display 1 +#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2) +#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3) +#endif /* EGL_ANGLE_direct3d_display */ + +#ifndef EGL_ANGLE_direct_composition +#define EGL_ANGLE_direct_composition 1 +#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5 +#endif /* EGL_ANGLE_direct_composition */ + +#ifndef EGL_ANGLE_platform_angle +#define EGL_ANGLE_platform_angle 1 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206 +#define EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451 +#endif /* EGL_ANGLE_platform_angle */ + +#ifndef EGL_ANGLE_platform_angle_d3d +#define EGL_ANGLE_platform_angle_d3d 1 +#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C +#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F +#endif /* EGL_ANGLE_platform_angle_d3d */ + +#ifndef EGL_ANGLE_platform_angle_opengl +#define EGL_ANGLE_platform_angle_opengl 1 +#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D +#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E +#endif /* EGL_ANGLE_platform_angle_opengl */ + +#ifndef EGL_ANGLE_platform_angle_null +#define EGL_ANGLE_platform_angle_null 1 +#define EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE 0x33AE +#endif /* EGL_ANGLE_platform_angle_null */ + +#ifndef EGL_ANGLE_platform_angle_vulkan +#define EGL_ANGLE_platform_angle_vulkan 1 +#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450 +#endif /* EGL_ANGLE_platform_angle_vulkan */ + +#ifndef EGL_ANGLE_x11_visual +#define EGL_ANGLE_x11_visual +#define EGL_X11_VISUAL_ID_ANGLE 0x33A3 +#endif /* EGL_ANGLE_x11_visual */ + +#ifndef EGL_ANGLE_flexible_surface_compatibility +#define EGL_ANGLE_flexible_surface_compatibility 1 +#define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 +#endif /* EGL_ANGLE_flexible_surface_compatibility */ + +#ifndef EGL_ANGLE_surface_orientation +#define EGL_ANGLE_surface_orientation +#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7 +#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8 +#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001 +#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002 +#endif /* EGL_ANGLE_surface_orientation */ + +#ifndef EGL_ANGLE_experimental_present_path +#define EGL_ANGLE_experimental_present_path +#define EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4 +#define EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9 +#define EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE 0x33AA +#endif /* EGL_ANGLE_experimental_present_path */ + +#ifndef EGL_ANGLE_stream_producer_d3d_texture_nv12 +#define EGL_ANGLE_stream_producer_d3d_texture_nv12 +#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB +typedef EGLBoolean(EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERD3DTEXTURENV12ANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +typedef EGLBoolean(EGLAPIENTRYP PFNEGLSTREAMPOSTD3DTEXTURENV12ANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglCreateStreamProducerD3DTextureNV12ANGLE(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list); +#endif +#endif /* EGL_ANGLE_stream_producer_d3d_texture_nv12 */ + +#ifndef EGL_ANGLE_create_context_webgl_compatibility +#define EGL_ANGLE_create_context_webgl_compatibility 1 +#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC +#endif /* EGL_ANGLE_create_context_webgl_compatibility */ + +#ifndef EGL_ANGLE_display_texture_share_group +#define EGL_ANGLE_display_texture_share_group 1 +#define EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE 0x3AAF +#endif /* EGL_ANGLE_display_texture_share_group */ + +#ifndef EGL_CHROMIUM_create_context_bind_generates_resource +#define EGL_CHROMIUM_create_context_bind_generates_resource 1 +#define EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM 0x3AAD +#endif /* EGL_CHROMIUM_create_context_bind_generates_resource */ + +#ifndef EGL_ANGLE_create_context_client_arrays +#define EGL_ANGLE_create_context_client_arrays 1 +#define EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE 0x3452 +#endif /* EGL_ANGLE_create_context_client_arrays */ + +#ifndef EGL_ANGLE_device_creation +#define EGL_ANGLE_device_creation 1 +typedef EGLDeviceEXT(EGLAPIENTRYP PFNEGLCREATEDEVICEANGLEPROC) (EGLint device_type, void *native_device, const EGLAttrib *attrib_list); +typedef EGLBoolean(EGLAPIENTRYP PFNEGLRELEASEDEVICEANGLEPROC) (EGLDeviceEXT device); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLDeviceEXT EGLAPIENTRY eglCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE(EGLDeviceEXT device); +#endif +#endif /* EGL_ANGLE_device_creation */ + +#ifndef EGL_ANGLE_program_cache_control +#define EGL_ANGLE_program_cache_control 1 +#define EGL_PROGRAM_CACHE_SIZE_ANGLE 0x3455 +#define EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE 0x3456 +#define EGL_PROGRAM_CACHE_RESIZE_ANGLE 0x3457 +#define EGL_PROGRAM_CACHE_TRIM_ANGLE 0x3458 +#define EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE 0x3459 +typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHEGETATTRIBANGLEPROC) (EGLDisplay dpy, EGLenum attrib); +typedef void (EGLAPIENTRYP PFNEGLPROGRAMCACHEQUERYANGLEPROC) (EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize); +typedef void (EGLAPIENTRYP PFNEGPROGRAMCACHELPOPULATEANGLEPROC) (EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize); +typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHERESIZEANGLEPROC) (EGLDisplay dpy, EGLint limit, EGLenum mode); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLint EGLAPIENTRY eglProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib); +EGLAPI void EGLAPIENTRY eglProgramCacheQueryANGLE(EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize); +EGLAPI void EGLAPIENTRY eglProgramCachePopulateANGLE(EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize); +EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode); +#endif +#endif /* EGL_ANGLE_program_cache_control */ + +// clang-format on + +#endif // INCLUDE_EGL_EGLEXT_ANGLE_ diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h index 6d550da9cd..333448be34 100644 --- a/src/3rdparty/angle/include/EGL/eglplatform.h +++ b/src/3rdparty/angle/include/EGL/eglplatform.h @@ -2,7 +2,7 @@ #define __eglplatform_h_ /* -** Copyright (c) 2007-2013 The Khronos Group Inc. +** Copyright (c) 2007-2016 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the @@ -83,7 +83,8 @@ typedef HWND EGLNativeWindowType; typedef IInspectable* EGLNativeWindowType; #endif -#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ +#elif defined(__APPLE__) || defined(__WINSCW__) || defined(__SYMBIAN32__) || \ + defined(__Fuchsia__) || defined(__HAIKU__) typedef int EGLNativeDisplayType; typedef void *EGLNativeWindowType; @@ -105,6 +106,12 @@ typedef intptr_t EGLNativeDisplayType; typedef intptr_t EGLNativeWindowType; typedef intptr_t EGLNativePixmapType; +#elif defined(WL_EGL_PLATFORM) + +typedef struct wl_display *EGLNativeDisplayType; +typedef struct wl_egl_pixmap *EGLNativePixmapType; +typedef struct wl_egl_window *EGLNativeWindowType; + #elif defined(__unix__) /* X11 (tentative) */ @@ -115,18 +122,6 @@ typedef Display *EGLNativeDisplayType; typedef Pixmap EGLNativePixmapType; typedef Window EGLNativeWindowType; -#elif defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) ) - -#if defined(__OBJC__) -@class CALayer; -#else -class CALayer; -#endif - -typedef void *EGLNativeDisplayType; -typedef void *EGLNativePixmapType; -typedef CALayer *EGLNativeWindowType; - #else #error "Platform not recognized" #endif @@ -146,4 +141,12 @@ typedef EGLNativeWindowType NativeWindowType; */ typedef khronos_int32_t EGLint; + +/* C++ / C typecast macros for special EGL handle values */ +#if defined(__cplusplus) +#define EGL_CAST(type, value) (static_cast(value)) +#else +#define EGL_CAST(type, value) ((type) (value)) +#endif + #endif /* __eglplatform_h */ diff --git a/src/3rdparty/angle/include/GLES2/gl2.h b/src/3rdparty/angle/include/GLES2/gl2.h index 027e1f7136..975c3dc495 100644 --- a/src/3rdparty/angle/include/GLES2/gl2.h +++ b/src/3rdparty/angle/include/GLES2/gl2.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013-2015 The Khronos Group Inc. +** Copyright (c) 2013-2017 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the @@ -31,9 +31,7 @@ extern "C" { ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at -** http://www.opengl.org/registry/ -** -** Khronos $Revision: 31811 $ on $Date: 2015-08-10 00:01:11 -0700 (Mon, 10 Aug 2015) $ +** https://github.com/KhronosGroup/OpenGL-Registry */ #include @@ -42,7 +40,11 @@ extern "C" { #define GL_APIENTRYP GL_APIENTRY* #endif -/* Generated on date 20150809 */ +#ifndef GL_GLES_PROTOTYPES +#define GL_GLES_PROTOTYPES 1 +#endif + +/* Generated on date 20170325 */ /* Generated C header for: * API: gles2 @@ -520,7 +522,7 @@ typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GL typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); -#ifdef GL_GLEXT_PROTOTYPES +#if GL_GLES_PROTOTYPES GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); diff --git a/src/3rdparty/angle/include/GLES2/gl2ext.h b/src/3rdparty/angle/include/GLES2/gl2ext.h index 51886a2dcb..4def3ced4b 100644 --- a/src/3rdparty/angle/include/GLES2/gl2ext.h +++ b/src/3rdparty/angle/include/GLES2/gl2ext.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013-2015 The Khronos Group Inc. +** Copyright (c) 2013-2017 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the @@ -31,16 +31,14 @@ extern "C" { ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at -** http://www.opengl.org/registry/ -** -** Khronos $Revision: 31902 $ on $Date: 2015-09-03 15:44:53 -0700 (Thu, 03 Sep 2015) $ +** https://github.com/KhronosGroup/OpenGL-Registry */ #ifndef GL_APIENTRYP #define GL_APIENTRYP GL_APIENTRY* #endif -/* Generated on date 20150903 */ +/* Generated on date 20170613 */ /* Generated C header for: * API: gles2 @@ -225,6 +223,10 @@ GL_APICALL void GL_APIENTRY glGetnUniformuivKHR (GLuint program, GLint location, #define GL_KHR_texture_compression_astc_ldr 1 #endif /* GL_KHR_texture_compression_astc_ldr */ +#ifndef GL_KHR_texture_compression_astc_sliced_3d +#define GL_KHR_texture_compression_astc_sliced_3d 1 +#endif /* GL_KHR_texture_compression_astc_sliced_3d */ + #ifndef GL_OES_EGL_image #define GL_OES_EGL_image 1 typedef void *GLeglImageOES; @@ -748,6 +750,34 @@ GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); #define GL_INT_10_10_10_2_OES 0x8DF7 #endif /* GL_OES_vertex_type_10_10_10_2 */ +#ifndef GL_OES_viewport_array +#define GL_OES_viewport_array 1 +#define GL_MAX_VIEWPORTS_OES 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS_OES 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE_OES 0x825D +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES 0x825F +typedef void (GL_APIENTRYP PFNGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (GL_APIENTRYP PFNGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v); +typedef void (GL_APIENTRYP PFNGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (GL_APIENTRYP PFNGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f); +typedef void (GL_APIENTRYP PFNGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glViewportArrayvOES (GLuint first, GLsizei count, const GLfloat *v); +GL_APICALL void GL_APIENTRY glViewportIndexedfOES (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GL_APICALL void GL_APIENTRY glViewportIndexedfvOES (GLuint index, const GLfloat *v); +GL_APICALL void GL_APIENTRY glScissorArrayvOES (GLuint first, GLsizei count, const GLint *v); +GL_APICALL void GL_APIENTRY glScissorIndexedOES (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glScissorIndexedvOES (GLuint index, const GLint *v); +GL_APICALL void GL_APIENTRY glDepthRangeArrayfvOES (GLuint first, GLsizei count, const GLfloat *v); +GL_APICALL void GL_APIENTRY glDepthRangeIndexedfOES (GLuint index, GLfloat n, GLfloat f); +GL_APICALL void GL_APIENTRY glGetFloati_vOES (GLenum target, GLuint index, GLfloat *data); +#endif +#endif /* GL_OES_viewport_array */ + #ifndef GL_AMD_compressed_3DC_texture #define GL_AMD_compressed_3DC_texture 1 #define GL_3DC_X_AMD 0x87F9 @@ -1021,6 +1051,10 @@ GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei #define GL_SHADER_BINARY_DMP 0x9250 #endif /* GL_DMP_shader_binary */ +#ifndef GL_EXT_EGL_image_array +#define GL_EXT_EGL_image_array 1 +#endif /* GL_EXT_EGL_image_array */ + #ifndef GL_EXT_YUV_target #define GL_EXT_YUV_target 1 #define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT 0x8BE7 @@ -1082,6 +1116,31 @@ GL_APICALL void GL_APIENTRY glBufferStorageEXT (GLenum target, GLsizeiptr size, #endif #endif /* GL_EXT_buffer_storage */ +#ifndef GL_EXT_clear_texture +#define GL_EXT_clear_texture 1 +typedef void (GL_APIENTRYP PFNGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (GL_APIENTRYP PFNGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glClearTexImageEXT (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +GL_APICALL void GL_APIENTRY glClearTexSubImageEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +#endif +#endif /* GL_EXT_clear_texture */ + +#ifndef GL_EXT_clip_cull_distance +#define GL_EXT_clip_cull_distance 1 +#define GL_MAX_CLIP_DISTANCES_EXT 0x0D32 +#define GL_MAX_CULL_DISTANCES_EXT 0x82F9 +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT 0x82FA +#define GL_CLIP_DISTANCE0_EXT 0x3000 +#define GL_CLIP_DISTANCE1_EXT 0x3001 +#define GL_CLIP_DISTANCE2_EXT 0x3002 +#define GL_CLIP_DISTANCE3_EXT 0x3003 +#define GL_CLIP_DISTANCE4_EXT 0x3004 +#define GL_CLIP_DISTANCE5_EXT 0x3005 +#define GL_CLIP_DISTANCE6_EXT 0x3006 +#define GL_CLIP_DISTANCE7_EXT 0x3007 +#endif /* GL_EXT_clip_cull_distance */ + #ifndef GL_EXT_color_buffer_float #define GL_EXT_color_buffer_float 1 #endif /* GL_EXT_color_buffer_float */ @@ -1096,6 +1155,10 @@ GL_APICALL void GL_APIENTRY glBufferStorageEXT (GLenum target, GLsizeiptr size, #define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 #endif /* GL_EXT_color_buffer_half_float */ +#ifndef GL_EXT_conservative_depth +#define GL_EXT_conservative_depth 1 +#endif /* GL_EXT_conservative_depth */ + #ifndef GL_EXT_copy_image #define GL_EXT_copy_image 1 typedef void (GL_APIENTRYP PFNGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); @@ -1267,6 +1330,27 @@ GL_APICALL void GL_APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei cou #endif #endif /* GL_EXT_draw_instanced */ +#ifndef GL_EXT_draw_transform_feedback +#define GL_EXT_draw_transform_feedback 1 +typedef void (GL_APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKEXTPROC) (GLenum mode, GLuint id); +typedef void (GL_APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDEXTPROC) (GLenum mode, GLuint id, GLsizei instancecount); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDrawTransformFeedbackEXT (GLenum mode, GLuint id); +GL_APICALL void GL_APIENTRY glDrawTransformFeedbackInstancedEXT (GLenum mode, GLuint id, GLsizei instancecount); +#endif +#endif /* GL_EXT_draw_transform_feedback */ + +#ifndef GL_EXT_external_buffer +#define GL_EXT_external_buffer 1 +typedef void *GLeglClientBufferEXT; +typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEEXTERNALEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +typedef void (GL_APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glBufferStorageExternalEXT (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +GL_APICALL void GL_APIENTRY glNamedBufferStorageExternalEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); +#endif +#endif /* GL_EXT_external_buffer */ + #ifndef GL_EXT_float_blend #define GL_EXT_float_blend 1 #endif /* GL_EXT_float_blend */ @@ -1345,6 +1429,85 @@ GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr #endif #endif /* GL_EXT_map_buffer_range */ +#ifndef GL_EXT_memory_object +#define GL_EXT_memory_object 1 +#define GL_TEXTURE_TILING_EXT 0x9580 +#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 +#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B +#define GL_NUM_TILING_TYPES_EXT 0x9582 +#define GL_TILING_TYPES_EXT 0x9583 +#define GL_OPTIMAL_TILING_EXT 0x9584 +#define GL_LINEAR_TILING_EXT 0x9585 +#define GL_NUM_DEVICE_UUIDS_EXT 0x9596 +#define GL_DEVICE_UUID_EXT 0x9597 +#define GL_DRIVER_UUID_EXT 0x9598 +#define GL_UUID_SIZE_EXT 16 +typedef void (GL_APIENTRYP PFNGLGETUNSIGNEDBYTEVEXTPROC) (GLenum pname, GLubyte *data); +typedef void (GL_APIENTRYP PFNGLGETUNSIGNEDBYTEI_VEXTPROC) (GLenum target, GLuint index, GLubyte *data); +typedef void (GL_APIENTRYP PFNGLDELETEMEMORYOBJECTSEXTPROC) (GLsizei n, const GLuint *memoryObjects); +typedef GLboolean (GL_APIENTRYP PFNGLISMEMORYOBJECTEXTPROC) (GLuint memoryObject); +typedef void (GL_APIENTRYP PFNGLCREATEMEMORYOBJECTSEXTPROC) (GLsizei n, GLuint *memoryObjects); +typedef void (GL_APIENTRYP PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, const GLint *params); +typedef void (GL_APIENTRYP PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLBUFFERSTORAGEMEMEXTPROC) (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM2DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM3DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +typedef void (GL_APIENTRYP PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetUnsignedBytevEXT (GLenum pname, GLubyte *data); +GL_APICALL void GL_APIENTRY glGetUnsignedBytei_vEXT (GLenum target, GLuint index, GLubyte *data); +GL_APICALL void GL_APIENTRY glDeleteMemoryObjectsEXT (GLsizei n, const GLuint *memoryObjects); +GL_APICALL GLboolean GL_APIENTRY glIsMemoryObjectEXT (GLuint memoryObject); +GL_APICALL void GL_APIENTRY glCreateMemoryObjectsEXT (GLsizei n, GLuint *memoryObjects); +GL_APICALL void GL_APIENTRY glMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, const GLint *params); +GL_APICALL void GL_APIENTRY glGetMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glTexStorageMem2DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTexStorageMem2DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTexStorageMem3DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTexStorageMem3DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glBufferStorageMemEXT (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTextureStorageMem2DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTextureStorageMem2DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTextureStorageMem3DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glTextureStorageMem3DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); +GL_APICALL void GL_APIENTRY glNamedBufferStorageMemEXT (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); +#endif +#endif /* GL_EXT_memory_object */ + +#ifndef GL_EXT_memory_object_fd +#define GL_EXT_memory_object_fd 1 +#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 +typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYFDEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, GLint fd); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glImportMemoryFdEXT (GLuint memory, GLuint64 size, GLenum handleType, GLint fd); +#endif +#endif /* GL_EXT_memory_object_fd */ + +#ifndef GL_EXT_memory_object_win32 +#define GL_EXT_memory_object_win32 1 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 +#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 +#define GL_DEVICE_LUID_EXT 0x9599 +#define GL_DEVICE_NODE_MASK_EXT 0x959A +#define GL_LUID_SIZE_EXT 8 +#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 +#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A +#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B +#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C +typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, void *handle); +typedef void (GL_APIENTRYP PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, const void *name); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glImportMemoryWin32HandleEXT (GLuint memory, GLuint64 size, GLenum handleType, void *handle); +GL_APICALL void GL_APIENTRY glImportMemoryWin32NameEXT (GLuint memory, GLuint64 size, GLenum handleType, const void *name); +#endif +#endif /* GL_EXT_memory_object_win32 */ + #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); @@ -1408,6 +1571,15 @@ GL_APICALL void GL_APIENTRY glGetIntegeri_vEXT (GLenum target, GLuint index, GLi #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A #endif /* GL_EXT_occlusion_query_boolean */ +#ifndef GL_EXT_polygon_offset_clamp +#define GL_EXT_polygon_offset_clamp 1 +#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp); +#endif +#endif /* GL_EXT_polygon_offset_clamp */ + #ifndef GL_EXT_post_depth_coverage #define GL_EXT_post_depth_coverage 1 #endif /* GL_EXT_post_depth_coverage */ @@ -1421,6 +1593,12 @@ GL_APICALL void GL_APIENTRY glPrimitiveBoundingBoxEXT (GLfloat minX, GLfloat min #endif #endif /* GL_EXT_primitive_bounding_box */ +#ifndef GL_EXT_protected_textures +#define GL_EXT_protected_textures 1 +#define GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT 0x00000010 +#define GL_TEXTURE_PROTECTED_EXT 0x8BFA +#endif /* GL_EXT_protected_textures */ + #ifndef GL_EXT_pvrtc_sRGB #define GL_EXT_pvrtc_sRGB 1 #define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 @@ -1495,6 +1673,53 @@ GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #endif /* GL_EXT_sRGB_write_control */ +#ifndef GL_EXT_semaphore +#define GL_EXT_semaphore 1 +#define GL_LAYOUT_GENERAL_EXT 0x958D +#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E +#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F +#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 +#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 +#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 +#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 +typedef void (GL_APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores); +typedef void (GL_APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores); +typedef GLboolean (GL_APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore); +typedef void (GL_APIENTRYP PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, const GLuint64 *params); +typedef void (GL_APIENTRYP PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, GLuint64 *params); +typedef void (GL_APIENTRYP PFNGLWAITSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts); +typedef void (GL_APIENTRYP PFNGLSIGNALSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGenSemaphoresEXT (GLsizei n, GLuint *semaphores); +GL_APICALL void GL_APIENTRY glDeleteSemaphoresEXT (GLsizei n, const GLuint *semaphores); +GL_APICALL GLboolean GL_APIENTRY glIsSemaphoreEXT (GLuint semaphore); +GL_APICALL void GL_APIENTRY glSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, const GLuint64 *params); +GL_APICALL void GL_APIENTRY glGetSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, GLuint64 *params); +GL_APICALL void GL_APIENTRY glWaitSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts); +GL_APICALL void GL_APIENTRY glSignalSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts); +#endif +#endif /* GL_EXT_semaphore */ + +#ifndef GL_EXT_semaphore_fd +#define GL_EXT_semaphore_fd 1 +typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREFDEXTPROC) (GLuint semaphore, GLenum handleType, GLint fd); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glImportSemaphoreFdEXT (GLuint semaphore, GLenum handleType, GLint fd); +#endif +#endif /* GL_EXT_semaphore_fd */ + +#ifndef GL_EXT_semaphore_win32 +#define GL_EXT_semaphore_win32 1 +#define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 +#define GL_D3D12_FENCE_VALUE_EXT 0x9595 +typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) (GLuint semaphore, GLenum handleType, void *handle); +typedef void (GL_APIENTRYP PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) (GLuint semaphore, GLenum handleType, const void *name); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glImportSemaphoreWin32HandleEXT (GLuint semaphore, GLenum handleType, void *handle); +GL_APICALL void GL_APIENTRY glImportSemaphoreWin32NameEXT (GLuint semaphore, GLenum handleType, const void *name); +#endif +#endif /* GL_EXT_semaphore_win32 */ + #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 #define GL_ACTIVE_PROGRAM_EXT 0x8259 @@ -1600,6 +1825,10 @@ GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLin #define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 #endif /* GL_EXT_shader_framebuffer_fetch */ +#ifndef GL_EXT_shader_group_vote +#define GL_EXT_shader_group_vote 1 +#endif /* GL_EXT_shader_group_vote */ + #ifndef GL_EXT_shader_implicit_conversions #define GL_EXT_shader_implicit_conversions 1 #endif /* GL_EXT_shader_implicit_conversions */ @@ -1612,6 +1841,10 @@ GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLin #define GL_EXT_shader_io_blocks 1 #endif /* GL_EXT_shader_io_blocks */ +#ifndef GL_EXT_shader_non_constant_global_initializers +#define GL_EXT_shader_non_constant_global_initializers 1 +#endif /* GL_EXT_shader_non_constant_global_initializers */ + #ifndef GL_EXT_shader_pixel_local_storage #define GL_EXT_shader_pixel_local_storage 1 #define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 @@ -1619,6 +1852,21 @@ GL_APICALL void GL_APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLin #define GL_SHADER_PIXEL_LOCAL_STORAGE_EXT 0x8F64 #endif /* GL_EXT_shader_pixel_local_storage */ +#ifndef GL_EXT_shader_pixel_local_storage2 +#define GL_EXT_shader_pixel_local_storage2 1 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT 0x9650 +#define GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT 0x9651 +#define GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT 0x9652 +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size); +typedef GLsizei (GL_APIENTRYP PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target); +typedef void (GL_APIENTRYP PFNGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferPixelLocalStorageSizeEXT (GLuint target, GLsizei size); +GL_APICALL GLsizei GL_APIENTRY glGetFramebufferPixelLocalStorageSizeEXT (GLuint target); +GL_APICALL void GL_APIENTRY glClearPixelLocalStorageuiEXT (GLsizei offset, GLsizei n, const GLuint *values); +#endif +#endif /* GL_EXT_shader_pixel_local_storage2 */ + #ifndef GL_EXT_shader_texture_lod #define GL_EXT_shader_texture_lod 1 #endif /* GL_EXT_shader_texture_lod */ @@ -1652,6 +1900,10 @@ GL_APICALL void GL_APIENTRY glTexPageCommitmentEXT (GLenum target, GLint level, #endif #endif /* GL_EXT_sparse_texture */ +#ifndef GL_EXT_sparse_texture2 +#define GL_EXT_sparse_texture2 1 +#endif /* GL_EXT_sparse_texture2 */ + #ifndef GL_EXT_tessellation_point_size #define GL_EXT_tessellation_point_size 1 #endif /* GL_EXT_tessellation_point_size */ @@ -1755,6 +2007,11 @@ GL_APICALL void GL_APIENTRY glTexBufferRangeEXT (GLenum target, GLenum internalf #endif #endif /* GL_EXT_texture_buffer */ +#ifndef GL_EXT_texture_compression_astc_decode_mode +#define GL_EXT_texture_compression_astc_decode_mode 1 +#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69 +#endif /* GL_EXT_texture_compression_astc_decode_mode */ + #ifndef GL_EXT_texture_compression_dxt1 #define GL_EXT_texture_compression_dxt1 1 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 @@ -1884,11 +2141,67 @@ GL_APICALL void GL_APIENTRY glTextureViewEXT (GLuint texture, GLenum target, GLu #define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4 #endif /* GL_EXT_unpack_subimage */ +#ifndef GL_EXT_win32_keyed_mutex +#define GL_EXT_win32_keyed_mutex 1 +typedef GLboolean (GL_APIENTRYP PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key, GLuint timeout); +typedef GLboolean (GL_APIENTRYP PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL GLboolean GL_APIENTRY glAcquireKeyedMutexWin32EXT (GLuint memory, GLuint64 key, GLuint timeout); +GL_APICALL GLboolean GL_APIENTRY glReleaseKeyedMutexWin32EXT (GLuint memory, GLuint64 key); +#endif +#endif /* GL_EXT_win32_keyed_mutex */ + +#ifndef GL_EXT_window_rectangles +#define GL_EXT_window_rectangles 1 +#define GL_INCLUSIVE_EXT 0x8F10 +#define GL_EXCLUSIVE_EXT 0x8F11 +#define GL_WINDOW_RECTANGLE_EXT 0x8F12 +#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 +#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 +#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 +typedef void (GL_APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box); +#endif +#endif /* GL_EXT_window_rectangles */ + #ifndef GL_FJ_shader_binary_GCCSO #define GL_FJ_shader_binary_GCCSO 1 #define GL_GCCSO_SHADER_BINARY_FJ 0x9260 #endif /* GL_FJ_shader_binary_GCCSO */ +#ifndef GL_IMG_bindless_texture +#define GL_IMG_bindless_texture 1 +typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTUREHANDLEIMGPROC) (GLuint texture); +typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEIMGPROC) (GLuint texture, GLuint sampler); +typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64IMGPROC) (GLint location, GLuint64 value); +typedef void (GL_APIENTRYP PFNGLUNIFORMHANDLEUI64VIMGPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64IMGPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VIMGPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL GLuint64 GL_APIENTRY glGetTextureHandleIMG (GLuint texture); +GL_APICALL GLuint64 GL_APIENTRY glGetTextureSamplerHandleIMG (GLuint texture, GLuint sampler); +GL_APICALL void GL_APIENTRY glUniformHandleui64IMG (GLint location, GLuint64 value); +GL_APICALL void GL_APIENTRY glUniformHandleui64vIMG (GLint location, GLsizei count, const GLuint64 *value); +GL_APICALL void GL_APIENTRY glProgramUniformHandleui64IMG (GLuint program, GLint location, GLuint64 value); +GL_APICALL void GL_APIENTRY glProgramUniformHandleui64vIMG (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +#endif +#endif /* GL_IMG_bindless_texture */ + +#ifndef GL_IMG_framebuffer_downsample +#define GL_IMG_framebuffer_downsample 1 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG 0x913C +#define GL_NUM_DOWNSAMPLE_SCALES_IMG 0x913D +#define GL_DOWNSAMPLE_SCALES_IMG 0x913E +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG 0x913F +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DDOWNSAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERDOWNSAMPLEIMGPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferTexture2DDownsampleIMG (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale); +GL_APICALL void GL_APIENTRY glFramebufferTextureLayerDownsampleIMG (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale); +#endif +#endif /* GL_IMG_framebuffer_downsample */ + #ifndef GL_IMG_multisampled_render_to_texture #define GL_IMG_multisampled_render_to_texture 1 #define GL_RENDERBUFFER_SAMPLES_IMG 0x9133 @@ -1933,6 +2246,18 @@ GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum target, #define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138 #endif /* GL_IMG_texture_compression_pvrtc2 */ +#ifndef GL_IMG_texture_filter_cubic +#define GL_IMG_texture_filter_cubic 1 +#define GL_CUBIC_IMG 0x9139 +#define GL_CUBIC_MIPMAP_NEAREST_IMG 0x913A +#define GL_CUBIC_MIPMAP_LINEAR_IMG 0x913B +#endif /* GL_IMG_texture_filter_cubic */ + +#ifndef GL_INTEL_conservative_rasterization +#define GL_INTEL_conservative_rasterization 1 +#define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE +#endif /* GL_INTEL_conservative_rasterization */ + #ifndef GL_INTEL_framebuffer_CMAA #define GL_INTEL_framebuffer_CMAA 1 typedef void (GL_APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void); @@ -1987,6 +2312,14 @@ GL_APICALL void GL_APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint quer #endif #endif /* GL_INTEL_performance_query */ +#ifndef GL_MESA_shader_integer_functions +#define GL_MESA_shader_integer_functions 1 +#endif /* GL_MESA_shader_integer_functions */ + +#ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers +#define GL_NVX_blend_equation_advanced_multi_draw_buffers 1 +#endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */ + #ifndef GL_NV_bindless_texture #define GL_NV_bindless_texture 1 typedef GLuint64 (GL_APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); @@ -2109,6 +2442,17 @@ GL_APICALL void GL_APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybit #endif #endif /* GL_NV_conservative_raster */ +#ifndef GL_NV_conservative_raster_pre_snap_triangles +#define GL_NV_conservative_raster_pre_snap_triangles 1 +#define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D +#define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E +#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F +typedef void (GL_APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param); +#endif +#endif /* GL_NV_conservative_raster_pre_snap_triangles */ + #ifndef GL_NV_copy_buffer #define GL_NV_copy_buffer 1 #define GL_COPY_READ_BUFFER_NV 0x8F36 @@ -2194,6 +2538,23 @@ GL_APICALL void GL_APIENTRY glDrawElementsInstancedNV (GLenum mode, GLsizei coun #endif #endif /* GL_NV_draw_instanced */ +#ifndef GL_NV_draw_vulkan_image +#define GL_NV_draw_vulkan_image 1 +typedef void (GL_APIENTRY *GLVULKANPROCNV)(void); +typedef void (GL_APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +typedef GLVULKANPROCNV (GL_APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name); +typedef void (GL_APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); +typedef void (GL_APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); +typedef void (GL_APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +GL_APICALL GLVULKANPROCNV GL_APIENTRY glGetVkProcAddrNV (const GLchar *name); +GL_APICALL void GL_APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore); +GL_APICALL void GL_APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore); +GL_APICALL void GL_APIENTRY glSignalVkFenceNV (GLuint64 vkFence); +#endif +#endif /* GL_NV_draw_vulkan_image */ + #ifndef GL_NV_explicit_attrib_location #define GL_NV_explicit_attrib_location 1 #endif /* GL_NV_explicit_attrib_location */ @@ -2296,6 +2657,109 @@ GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleNV (GLenum target, G #define GL_NV_geometry_shader_passthrough 1 #endif /* GL_NV_geometry_shader_passthrough */ +#ifndef GL_NV_gpu_shader5 +#define GL_NV_gpu_shader5 1 +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64EXT; +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +#define GL_PATCHES 0x000E +typedef void (GL_APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); +typedef void (GL_APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); +typedef void (GL_APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (GL_APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (GL_APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); +typedef void (GL_APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (GL_APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (GL_APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (GL_APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); +GL_APICALL void GL_APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); +GL_APICALL void GL_APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GL_APICALL void GL_APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GL_APICALL void GL_APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); +GL_APICALL void GL_APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); +GL_APICALL void GL_APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GL_APICALL void GL_APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GL_APICALL void GL_APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); +GL_APICALL void GL_APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); +GL_APICALL void GL_APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GL_APICALL void GL_APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GL_APICALL void GL_APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GL_APICALL void GL_APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); +GL_APICALL void GL_APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GL_APICALL void GL_APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GL_APICALL void GL_APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GL_APICALL void GL_APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GL_APICALL void GL_APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_NV_gpu_shader5 */ + #ifndef GL_NV_image_formats #define GL_NV_image_formats 1 #endif /* GL_NV_image_formats */ @@ -2702,6 +3166,10 @@ GL_APICALL void GL_APIENTRY glResolveDepthValuesNV (void); #define GL_NV_sample_mask_override_coverage 1 #endif /* GL_NV_sample_mask_override_coverage */ +#ifndef GL_NV_shader_atomic_fp16_vector +#define GL_NV_shader_atomic_fp16_vector 1 +#endif /* GL_NV_shader_atomic_fp16_vector */ + #ifndef GL_NV_shader_noperspective_interpolation #define GL_NV_shader_noperspective_interpolation 1 #endif /* GL_NV_shader_noperspective_interpolation */ @@ -2768,11 +3236,32 @@ GL_APICALL GLboolean GL_APIENTRY glIsEnablediNV (GLenum target, GLuint index); #define GL_NV_viewport_array2 1 #endif /* GL_NV_viewport_array2 */ +#ifndef GL_NV_viewport_swizzle +#define GL_NV_viewport_swizzle 1 +#define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350 +#define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351 +#define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352 +#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353 +#define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354 +#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355 +#define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356 +#define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357 +#define GL_VIEWPORT_SWIZZLE_X_NV 0x9358 +#define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359 +#define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A +#define GL_VIEWPORT_SWIZZLE_W_NV 0x935B +typedef void (GL_APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); +#endif +#endif /* GL_NV_viewport_swizzle */ + #ifndef GL_OVR_multiview #define GL_OVR_multiview 1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 #define GL_MAX_VIEWS_OVR 0x9631 +#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); @@ -2783,6 +3272,14 @@ GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLe #define GL_OVR_multiview2 1 #endif /* GL_OVR_multiview2 */ +#ifndef GL_OVR_multiview_multisampled_render_to_texture +#define GL_OVR_multiview_multisampled_render_to_texture 1 +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferTextureMultisampleMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews); +#endif +#endif /* GL_OVR_multiview_multisampled_render_to_texture */ + #ifndef GL_QCOM_alpha_test #define GL_QCOM_alpha_test 1 #define GL_ALPHA_TEST_QCOM 0x0BC0 @@ -2863,11 +3360,32 @@ GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLe #endif #endif /* GL_QCOM_extended_get2 */ +#ifndef GL_QCOM_framebuffer_foveated +#define GL_QCOM_framebuffer_foveated 1 +#define GL_FOVEATION_ENABLE_BIT_QCOM 0x00000001 +#define GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM 0x00000002 +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFOVEATIONCONFIGQCOMPROC) (GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFOVEATIONPARAMETERSQCOMPROC) (GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferFoveationConfigQCOM (GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures); +GL_APICALL void GL_APIENTRY glFramebufferFoveationParametersQCOM (GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea); +#endif +#endif /* GL_QCOM_framebuffer_foveated */ + #ifndef GL_QCOM_perfmon_global_mode #define GL_QCOM_perfmon_global_mode 1 #define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 #endif /* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_shader_framebuffer_fetch_noncoherent +#define GL_QCOM_shader_framebuffer_fetch_noncoherent 1 +#define GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM 0x96A2 +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIERQCOMPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferFetchBarrierQCOM (void); +#endif +#endif /* GL_QCOM_shader_framebuffer_fetch_noncoherent */ + #ifndef GL_QCOM_tiled_rendering #define GL_QCOM_tiled_rendering 1 #define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 @@ -2920,20 +3438,8 @@ GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); #define GL_SHADER_BINARY_VIV 0x8FC4 #endif /* GL_VIV_shader_binary */ -#ifndef GL_ANGLE_lossy_etc_decode -#define GL_ANGLE_lossy_etc_decode 1 -#define GL_ETC1_RGB8_LOSSY_DECODE_ANGLE 0x9690 -#define GL_COMPRESSED_R11_LOSSY_DECODE_EAC_ANGLE 0x9691 -#define GL_COMPRESSED_SIGNED_R11_LOSSY_DECODE_EAC_ANGLE 0x9692 -#define GL_COMPRESSED_RG11_LOSSY_DECODE_EAC_ANGLE 0x9693 -#define GL_COMPRESSED_SIGNED_RG11_LOSSY_DECODE_EAC_ANGLE 0x9694 -#define GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE 0x9695 -#define GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE 0x9696 -#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE 0x9697 -#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE 0x9698 -#define GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE 0x9699 -#define GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE 0x969A -#endif /* GL_ANGLE_lossy_etc_decode */ +/* ANGLE GLES2 extensions */ +#include "gl2ext_angle.h" #ifdef __cplusplus } diff --git a/src/3rdparty/angle/include/GLES2/gl2ext_angle.h b/src/3rdparty/angle/include/GLES2/gl2ext_angle.h new file mode 100644 index 0000000000..fc5a4bf35d --- /dev/null +++ b/src/3rdparty/angle/include/GLES2/gl2ext_angle.h @@ -0,0 +1,551 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// gl2ext_angle.h: ANGLE modifications to the gl2ext.h header file. +// Currently we don't include this file directly, we patch gl2ext.h +// to include it implicitly so it is visible throughout our code. + +#ifndef INCLUDE_GLES2_GL2EXT_ANGLE_H_ +#define INCLUDE_GLES2_GL2EXT_ANGLE_H_ + +// clang-format off + +#ifndef GL_ANGLE_client_arrays +#define GL_ANGLE_client_arrays 1 +#define GL_CLIENT_ARRAYS_ANGLE 0x93AA +#endif /* GL_ANGLE_client_arrays */ + +#ifndef GL_ANGLE_request_extension +#define GL_ANGLE_request_extension 1 +#define GL_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8 +#define GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8 +typedef void (GL_APIENTRYP PFNGLREQUESTEXTENSIONANGLEPROC) (const GLchar *name); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRequestExtensionANGLE (const GLchar *name); +#endif +#endif /* GL_ANGLE_webgl_compatibility */ + +#ifndef GL_ANGLE_robust_resource_initialization +#define GL_ANGLE_robust_resource_initialization 1 +#define GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x93AB +#endif /* GL_ANGLE_robust_resource_initialization */ + +#ifndef GL_CHROMIUM_framebuffer_mixed_samples +#define GL_CHROMIUM_frambuffer_mixed_samples 1 +#define GL_COVERAGE_MODULATION_CHROMIUM 0x9332 +typedef void (GL_APIENTRYP PFNGLCOVERAGEMODULATIONCHROMIUMPROC) (GLenum components); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glCoverageModulationCHROMIUM(GLenum components); +#endif +#endif /* GL_CHROMIUM_framebuffer_mixed_samples */ + +#ifndef GL_CHROMIUM_bind_generates_resource +#define GL_CHROMIUM_bind_generates_resource 1 +#define GL_BIND_GENERATES_RESOURCE_CHROMIUM 0x9244 +#endif /* GL_CHROMIUM_bind_generates_resource */ + +// needed by NV_path_rendering (and thus CHROMIUM_path_rendering) +// but CHROMIUM_path_rendering only needs MatrixLoadfEXT, MatrixLoadIdentityEXT +#ifndef GL_EXT_direct_state_access +#define GL_EXT_direct_state_access 1 +typedef void(GL_APIENTRYP PFNGLMATRIXLOADFEXTPROC)(GLenum matrixMode, const GLfloat *m); +typedef void(GL_APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC)(GLenum matrixMode); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glMatrixLoadfEXT(GLenum matrixMode, const GLfloat *m); +GL_APICALL void GL_APIENTRY glMatrixLoadIdentityEXT(GLenum matrixMode); +#endif +#endif /* GL_EXT_direct_state_access */ + +#ifndef GL_CHROMIUM_path_rendering +#define GL_CHROMIUM_path_rendering 1 +#define GL_PATH_MODELVIEW_CHROMIUM 0x1700 +#define GL_PATH_PROJECTION_CHROMIUM 0x1701 +#define GL_CLOSE_PATH_CHROMIUM 0x00 +#define GL_MOVE_TO_CHROMIUM 0x02 +#define GL_LINE_TO_CHROMIUM 0x04 +#define GL_QUADRATIC_CURVE_TO_CHROMIUM 0x0A +#define GL_CUBIC_CURVE_TO_CHROMIUM 0x0C +#define GL_CONIC_CURVE_TO_CHROMIUM 0x1A +#define GL_PATH_MODELVIEW_MATRIX_CHROMIUM 0x0BA6 +#define GL_PATH_PROJECTION_MATRIX_CHROMIUM 0x0BA7 +#define GL_PATH_STROKE_WIDTH_CHROMIUM 0x9075 +#define GL_PATH_END_CAPS_CHROMIUM 0x9076 +#define GL_PATH_JOIN_STYLE_CHROMIUM 0x9079 +#define GL_PATH_MITER_LIMIT_CHROMIUM 0x907a +#define GL_PATH_STROKE_BOUND_CHROMIUM 0x9086 +#define GL_FLAT_CHROMIUM 0x1D00 +#define GL_SQUARE_CHROMIUM 0x90a3 +#define GL_ROUND_CHROMIUM 0x90a4 +#define GL_BEVEL_CHROMIUM 0x90A6 +#define GL_MITER_REVERT_CHROMIUM 0x90A7 +#define GL_COUNT_UP_CHROMIUM 0x9088 +#define GL_COUNT_DOWN_CHROMIUM 0x9089 +#define GL_CONVEX_HULL_CHROMIUM 0x908B +#define GL_BOUNDING_BOX_CHROMIUM 0x908D +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM 0x909C +#define GL_EYE_LINEAR_CHROMIUM 0x2400 +#define GL_OBJECT_LINEAR_CHROMIUM 0x2401 +#define GL_CONSTANT_CHROMIUM 0x8576 +#define GL_TRANSLATE_X_CHROMIUM 0x908E +#define GL_TRANSLATE_Y_CHROMIUM 0x908F +#define GL_TRANSLATE_2D_CHROMIUM 0x9090 +#define GL_TRANSLATE_3D_CHROMIUM 0x9091 +#define GL_AFFINE_2D_CHROMIUM 0x9092 +#define GL_AFFINE_3D_CHROMIUM 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_CHROMIUM 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_CHROMIUM 0x9098 +typedef void(GL_APIENTRYP PFNGLMATRIXLOADFCHROMIUMPROC)(GLenum matrixMode, const GLfloat *m); +typedef void(GL_APIENTRYP PFNGLMATRIXLOADIDENTITYCHROMIUMPROC)(GLenum matrixMode); +typedef GLuint(GL_APIENTRYP PFNGLGENPATHSCHROMIUMPROC)(GLsizei range); +typedef void(GL_APIENTRYP PFNGLDELETEPATHSCHROMIUMPROC)(GLuint path, GLsizei range); +typedef GLboolean(GL_APIENTRYP PFNGLISPATHCHROMIUMPROC)(GLuint path); +typedef void(GL_APIENTRYP PFNGLPATHCOMMANDSCHROMIUMPROC)(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); +typedef void(GL_APIENTRYP PFNGLPATHPARAMETERICHROMIUMPROC)(GLuint path, GLenum pname, GLint value); +typedef void(GL_APIENTRYP PFNGLPATHPARAMETERFCHROMIUMPROC)(GLuint path, + GLenum pname, + GLfloat value); +typedef void(GL_APIENTRYP PFNGLGETPATHPARAMETERIVCHROMIUMPROC)(GLuint path, + GLenum pname, + GLint *value); +typedef void(GL_APIENTRYP PFNGLGETPATHPARAMETERFVCHROMIUMPROC)(GLuint path, + GLenum pname, + GLfloat *value); +typedef void(GL_APIENTRYP PFNGLPATHSTENCILFUNCCHROMIUMPROC)(GLenum func, GLint ref, GLuint mask); +typedef void(GL_APIENTRYP PFNGLSTENCILFILLPATHCHROMIUMPROC)(GLuint path, + GLenum fillMode, + GLuint mask); +typedef void(GL_APIENTRYP PFNGLSTENCILSTROKEPATHCHROMIUMPROC)(GLuint path, + GLint reference, + GLuint mask); +typedef void(GL_APIENTRYP PFNGLCOVERFILLPATHCHROMIUMPROC)(GLuint path, GLenum coverMode); +typedef void(GL_APIENTRYP PFNGLCOVERSTROKEPATHCHROMIUMPROC)(GLuint path, GLenum coverMode); +typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHCHROMIUMPROC)(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); +typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHCHROMIUMPROC)(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode); +typedef void(GL_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDCHROMIUMPROC)(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +typedef void(GL_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDCHROMIUMPROC)( + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +typedef void(GL_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDCHROMIUMPROC)( + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +typedef void(GL_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDCHROMIUMPROC)( + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDCHROMIUMPROC)( + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +typedef void(GL_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDCHROMIUMPROC)( + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + +typedef void(GL_APIENTRY PFNGLBINDFRAGMENTINPUTLOCATIONCHROMIUMPROC)(GLuint program, + GLint location, + const GLchar *name); +typedef void(GL_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENCHROMIUMPROC)(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glMatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat *m); +GL_APICALL void GL_APIENTRY glMatrixLoadIdentityCHROMIUM(GLenum matrixMode); +GL_APICALL GLuint GL_APIENTRY glGenPathsCHROMIUM(GLsizei range); +GL_APICALL void GL_APIENTRY glDeletePathsCHROMIUM(GLuint path, GLsizei range); +GL_APICALL GLboolean GL_APIENTRY glIsPathCHROMIUM(GLuint path); +GL_APICALL void GL_APIENTRY glPathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); +GL_APICALL void GL_APIENTRY glPathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value); +GL_APICALL void GL_APIENTRY glPathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value); +GL_APICALL void GL_APIENTRY glGetPathParameterivCHROMIUM(GLuint path, GLenum pname, GLint *value); +GL_APICALL void GL_APIENTRY glGetPathParameterfvCHROMIUM(GLuint path, GLenum pname, GLfloat *value); +GL_APICALL void GL_APIENTRY glPathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask); +GL_APICALL void GL_APIENTRY glCoverFillPathCHROMIUM(GLuint path, GLenum coverMode); +GL_APICALL void GL_APIENTRY glCoverStrokePathCHROMIUM(GLuint path, GLenum coverMode); +GL_APICALL void GL_APIENTRY glStencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); +GL_APICALL void GL_APIENTRY glStencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode); +GL_APICALL void GL_APIENTRY glCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +GL_APICALL void GL_APIENTRY glCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +GL_APICALL void GL_APIENTRY glStencilFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +GL_APICALL void GL_APIENTRY glStencilStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +GL_APICALL void GL_APIENTRY +glStencilThenCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + +GL_APICALL void GL_APIENTRY +glStencilThenCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + +GL_APICALL void GL_APIENTRY glBindFragmentInputLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name); +GL_APICALL void GL_APIENTRY glProgramPathFragmentInputGenCHROMIUM(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + +#endif +#endif /* GL_CHROMIUM_path_rendering */ + +#ifndef GL_CHROMIUM_copy_texture +#define GL_CHROMIUM_copy_texture 1 +typedef void(GL_APIENTRYP PFNGLCOPYTEXTURECHROMIUMPROC)(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +typedef void(GL_APIENTRYP PFNGLCOPYSUBTEXTURECHROMIUMPROC)(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +#endif +#endif /* GL_CHROMIUM_copy_texture */ + +#ifndef GL_CHROMIUM_compressed_copy_texture +#define GL_CHROMIUM_compressed_copy_texture 1 +typedef void(GL_APIENTRYP PFNGLCOMPRESSEDCOPYTEXTURECHROMIUMPROC)(GLuint sourceId, GLuint destId); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glCompressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId); +#endif +#endif /* GL_CHROMIUM_compressed_copy_texture */ + +#ifndef GL_CHROMIUM_sync_query +#define GL_CHROMIUM_sync_query 1 +#define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7 +#endif /* GL_CHROMIUM_sync_query */ + +#ifndef GL_EXT_texture_compression_s3tc_srgb +#define GL_EXT_texture_compression_s3tc_srgb 1 +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif /* GL_EXT_texture_compression_s3tc_srgb */ + +#ifndef GL_ANGLE_lossy_etc_decode +#define GL_ANGLE_lossy_etc_decode 1 +#define GL_ETC1_RGB8_LOSSY_DECODE_ANGLE 0x9690 +#define GL_COMPRESSED_R11_LOSSY_DECODE_EAC_ANGLE 0x9691 +#define GL_COMPRESSED_SIGNED_R11_LOSSY_DECODE_EAC_ANGLE 0x9692 +#define GL_COMPRESSED_RG11_LOSSY_DECODE_EAC_ANGLE 0x9693 +#define GL_COMPRESSED_SIGNED_RG11_LOSSY_DECODE_EAC_ANGLE 0x9694 +#define GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE 0x9695 +#define GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE 0x9696 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE 0x9697 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE 0x9698 +#define GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE 0x9699 +#define GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE 0x969A +#endif /* GL_ANGLE_lossy_etc_decode */ + +#ifndef GL_ANGLE_robust_client_memory +#define GL_ANGLE_robust_client_memory 1 +typedef void (GL_APIENTRYP PFNGLGETBOOLEANVROBUSTANGLE) (GLenum pname, GLsizei bufSize, GLsizei *length, GLboolean *data); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETFLOATVROBUSTANGLE) (GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *data); +typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVROBUSTANGLE) (GLenum target, GLenum attachment, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETINTEGERVROBUSTANGLE) (GLenum pname, GLsizei bufSize, GLsizei *length, GLint *data); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMIVROBUSTANGLE) (GLuint program, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSHADERIVROBUSTANGLE) (GLuint shader, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERFVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMFVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMIVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBFVROBUSTANGLE) (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIVROBUSTANGLE) (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVROBUSTANGLE) (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, void **pointer); +typedef void (GL_APIENTRYP PFNGLREADPIXELSROBUSTANGLE) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLsizei *length, GLsizei *columns, GLsizei *rows, void *pixels); +typedef void (GL_APIENTRYP PFNGLTEXIMAGE2DROBUSTANGLE) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERFVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, const GLfloat *params); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, const GLint *params); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE2DROBUSTANGLE) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DROBUSTANGLE) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DROBUSTANGLE) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DROBUSTANGLE) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLsizei bufSize, const void *data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DROBUSTANGLE) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLsizei bufSize, const void *data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DROBUSTANGLE) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei bufSize, const void *data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DROBUSTANGLE) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei bufSize, const void *data); +typedef void (GL_APIENTRYP PFNGLGETQUERYIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVROBUSTANGLE) (GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, void **params); +typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VROBUSTANGLE) (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLint *data); +typedef void (GL_APIENTRYP PFNGETINTERNALFORMATIVROBUSTANGLE) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIIVROBUSTANGLE) (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETVERTEXATTRIBIUIVROBUSTANGLE) (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETUNIFORMUIVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVROBUSTANGLE) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETINTEGER64VROBUSTANGLE) (GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *data); +typedef void (GL_APIENTRYP PFNGLGETINTEGER64I_VROBUSTANGLE) (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLint64 *data); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPARAMETERI64VROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *params); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, const GLint *param); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERFVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, const GLfloat *param); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERFVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMINTERFACEIVROBUSTANGLE) (GLuint program, GLenum programInterface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETBOOLEANI_VROBUSTANGLE) (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLboolean *data); +typedef void (GL_APIENTRYP PFNGLGETMULTISAMPLEFVROBUSTANGLE) (GLenum pname, GLuint index, GLsizei bufSize, GLsizei *length, GLfloat *val); +typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERIVROBUSTANGLE) (GLenum target, GLint level, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETTEXLEVELPARAMETERFVROBUSTANGLE) (GLenum target, GLint level, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETPOINTERVROBUSTANGLEROBUSTANGLE) (GLenum pname, GLsizei bufSize, GLsizei *length, void **params); +typedef void (GL_APIENTRYP PFNGLREADNPIXELSROBUSTANGLE) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLsizei *length, GLsizei *columns, GLsizei *rows, void *data); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMUIVROBUSTANGLE) (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, const GLint *params); +typedef void (GL_APIENTRYP PFNGLTEXPARAMETERIUIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, const GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERIUIVROBUSTANGLE) (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, const GLint *param); +typedef void (GL_APIENTRYP PFNGLSAMPLERPARAMETERIUIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, const GLuint *param); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVROBUSTANGLE) (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVROBUSTANGLE)(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VROBUSTANGLE)(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VROBUSTANGLE)(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint64 *params); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetBooleanvRobustANGLE (GLenum pname, GLsizei bufSize, GLsizei *length, GLboolean *data); +GL_APICALL void GL_APIENTRY glGetBufferParameterivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetFloatvRobustANGLE (GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *data); +GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameterivRobustANGLE (GLenum target, GLenum attachment, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetIntegervRobustANGLE (GLenum pname, GLsizei bufSize, GLsizei *length, GLint *data); +GL_APICALL void GL_APIENTRY glGetProgramivRobustANGLE (GLuint program, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetRenderbufferParameterivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetShaderivRobustANGLE (GLuint shader, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetTexParameterfvRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetTexParameterivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetUniformfvRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetUniformivRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribfvRobustANGLE (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribivRobustANGLE (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribPointervRobustANGLE (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, void **pointer); +GL_APICALL void GL_APIENTRY glReadPixelsRobustANGLE (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLsizei *length, GLsizei *columns, GLsizei *rows, void *pixels); +GL_APICALL void GL_APIENTRY glTexImage2DRobustANGLE (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +GL_APICALL void GL_APIENTRY glTexParameterfvRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, const GLfloat *params); +GL_APICALL void GL_APIENTRY glTexParameterivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, const GLint *params); +GL_APICALL void GL_APIENTRY glTexSubImage2DRobustANGLE (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +GL_APICALL void GL_APIENTRY glTexImage3DRobustANGLE (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +GL_APICALL void GL_APIENTRY glTexSubImage3DRobustANGLE (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, const void *pixels); +GL_APICALL void GL_APIENTRY glCompressedTexImage2DRobustANGLE(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLsizei bufSize, const void *data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage2DRobustANGLE(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLsizei bufSize, const void *data); +GL_APICALL void GL_APIENTRY glCompressedTexImage3DRobustANGLE(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei bufSize, const void *data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DRobustANGLE(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei bufSize, const void *data); +GL_APICALL void GL_APIENTRY glGetQueryivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectuivRobustANGLE (GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glGetBufferPointervRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, void **params); +GL_APICALL void GL_APIENTRY glGetIntegeri_vRobustANGLE (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLint *data); +GL_APICALL void GL_APIENTRY glGetInternalformativRobustANGLE (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribIivRobustANGLE (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetVertexAttribIuivRobustANGLE (GLuint index, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glGetUniformuivRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glGetActiveUniformBlockivRobustANGLE (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetInteger64vRobustANGLE (GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *data); +GL_APICALL void GL_APIENTRY glGetInteger64i_vRobustANGLE (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLint64 *data); +GL_APICALL void GL_APIENTRY glGetBufferParameteri64vRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *params); +GL_APICALL void GL_APIENTRY glSamplerParameterivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, const GLint *param); +GL_APICALL void GL_APIENTRY glSamplerParameterfvRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, const GLfloat *param); +GL_APICALL void GL_APIENTRY glGetSamplerParameterivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetSamplerParameterfvRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetFramebufferParameterivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetProgramInterfaceivRobustANGLE (GLuint program, GLenum programInterface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetBooleani_vRobustANGLE (GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLboolean *data); +GL_APICALL void GL_APIENTRY glGetMultisamplefvRobustANGLE (GLenum pname, GLuint index, GLsizei bufSize, GLsizei *length, GLfloat *val); +GL_APICALL void GL_APIENTRY glGetTexLevelParameterivRobustANGLE (GLenum target, GLint level, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetTexLevelParameterfvRobustANGLE (GLenum target, GLint level, GLenum pname, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetPointervRobustANGLERobustANGLE (GLenum pname, GLsizei bufSize, GLsizei *length, void **params); +GL_APICALL void GL_APIENTRY glReadnPixelsRobustANGLE (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLsizei *length, GLsizei *columns, GLsizei *rows, void *data); +GL_APICALL void GL_APIENTRY glGetnUniformfvRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetnUniformivRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetnUniformuivRobustANGLE (GLuint program, GLint location, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glTexParameterIivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, const GLint *params); +GL_APICALL void GL_APIENTRY glTexParameterIuivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, const GLuint *params); +GL_APICALL void GL_APIENTRY glGetTexParameterIivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetTexParameterIuivRobustANGLE (GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glSamplerParameterIivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, const GLint *param); +GL_APICALL void GL_APIENTRY glSamplerParameterIuivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, const GLuint *param); +GL_APICALL void GL_APIENTRY glGetSamplerParameterIivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetSamplerParameterIuivRobustANGLE (GLuint sampler, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectivRobustANGLE(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjecti64vRobustANGLE(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLint64 *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectui64vRobustANGLE(GLuint id, GLenum pname, GLsizei bufSize, GLsizei *length, GLuint64 *params); +#endif +#endif /* GL_ANGLE_robust_client_memory */ + +#ifndef GL_ANGLE_program_cache_control +#define GL_ANGLE_program_cache_control 1 +#define GL_PROGRAM_CACHE_ENABLED_ANGLE 0x93AC +#endif /* GL_ANGLE_program_cache_control */ + +#ifndef GL_ANGLE_multiview +#define GL_ANGLE_multiview 1 +// The next four enums coincide with the enums introduced by the GL_OVR_multiview extension and use the values reserved by that extension. +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE 0x9630 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE 0x9632 +#define GL_MAX_VIEWS_ANGLE 0x9631 +#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE 0x9633 +// The next four enums are reserved specifically for ANGLE. +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE 0x969B +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE 0x969C +#define GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE 0x969D +#define GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE 0x969E +typedef void(GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWLAYEREDANGLE)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +typedef void(GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWSIDEBYSIDEANGLE)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint *viewportOffsets); +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLE(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLE(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint *viewportOffsets); +#endif +#endif /* GL_ANGLE_multiview */ + +#ifndef GL_ANGLE_texture_rectangle +#define GL_ANGLE_texture_rectangle 1 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE 0x84F8 +#define GL_TEXTURE_RECTANGLE_ANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ANGLE 0x84F6 +#define GL_SAMPLER_2D_RECT_ANGLE 0x8B63 +#endif /* GL_ANGLE_texture_rectangle */ + +// clang-format on + +#endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_ diff --git a/src/3rdparty/angle/include/GLES3/gl3ext.h b/src/3rdparty/angle/include/GLES3/gl3ext.h deleted file mode 100644 index 4d4ea96c4d..0000000000 --- a/src/3rdparty/angle/include/GLES3/gl3ext.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __gl3ext_h_ -#define __gl3ext_h_ - -/* $Revision: 17809 $ on $Date:: 2012-05-14 08:03:36 -0700 #$ */ - -/* - * This document is licensed under the SGI Free Software B License Version - * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . - */ - -/* OpenGL ES 3 Extensions - * - * After an OES extension's interactions with OpenGl ES 3.0 have been documented, - * its tokens and function definitions should be added to this file in a manner - * that does not conflict with gl2ext.h or gl3.h. - * - * Tokens and function definitions for extensions that have become standard - * features in OpenGL ES 3.0 will not be added to this file. - * - * Applications using OpenGL-ES-2-only extensions should include gl2ext.h - */ - -#endif /* __gl3ext_h_ */ - diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h index d02723e760..1468bb1464 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h @@ -6,27 +6,11 @@ #ifndef GLSLANG_SHADERLANG_H_ #define GLSLANG_SHADERLANG_H_ -#if defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC) -#if defined(_WIN32) || defined(_WIN64) - -#if defined(ANGLE_TRANSLATOR_IMPLEMENTATION) -#define COMPILER_EXPORT __declspec(dllexport) -#else -#define COMPILER_EXPORT __declspec(dllimport) -#endif // defined(ANGLE_TRANSLATOR_IMPLEMENTATION) - -#else // defined(_WIN32) || defined(_WIN64) -#define COMPILER_EXPORT __attribute__((visibility("default"))) -#endif - -#else // defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC) -#define COMPILER_EXPORT -#endif - #include #include "KHR/khrplatform.h" +#include #include #include #include @@ -36,51 +20,26 @@ // and the shading language compiler. // -namespace sh -{ -// GLenum alias -typedef unsigned int GLenum; -} - -// Must be included after GLenum proxy typedef // Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h #include "ShaderVars.h" // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 143 - -typedef enum { - SH_GLES2_SPEC = 0x8B40, - SH_WEBGL_SPEC = 0x8B41, - - SH_GLES3_SPEC = 0x8B86, - SH_WEBGL2_SPEC = 0x8B87, - - // The CSS Shaders spec is a subset of the WebGL spec. - // - // In both CSS vertex and fragment shaders, ANGLE: - // (1) Reserves the "css_" prefix. - // (2) Renames the main function to css_main. - // (3) Disables the gl_MaxDrawBuffers built-in. - // - // In CSS fragment shaders, ANGLE: - // (1) Disables the gl_FragColor built-in. - // (2) Disables the gl_FragData built-in. - // (3) Enables the css_MixColor built-in. - // (4) Enables the css_ColorMatrix built-in. - // - // After passing a CSS shader through ANGLE, the browser is expected to append - // a new main function to it. - // This new main function will call the css_main function. - // It may also perform additional operations like varying assignment, texture - // access, and gl_FragColor assignment in order to implement the CSS Shaders - // blend modes. - // - SH_CSS_SHADERS_SPEC = 0x8B42 -} ShShaderSpec; - -typedef enum +#define ANGLE_SH_VERSION 190 + +enum ShShaderSpec +{ + SH_GLES2_SPEC, + SH_WEBGL_SPEC, + + SH_GLES3_SPEC, + SH_WEBGL2_SPEC, + + SH_GLES3_1_SPEC, + SH_WEBGL3_SPEC, +}; + +enum ShShaderOutput { // ESSL output only supported in some configurations. SH_ESSL_OUTPUT = 0x8B45, @@ -99,147 +58,224 @@ typedef enum SH_GLSL_440_CORE_OUTPUT = 0x8B87, SH_GLSL_450_CORE_OUTPUT = 0x8B88, - // HLSL output only supported in some configurations. - // Deprecated: - SH_HLSL_OUTPUT = 0x8B48, - SH_HLSL9_OUTPUT = 0x8B48, - SH_HLSL11_OUTPUT = 0x8B49, - // Prefer using these to specify HLSL output type: SH_HLSL_3_0_OUTPUT = 0x8B48, // D3D 9 SH_HLSL_4_1_OUTPUT = 0x8B49, // D3D 11 - SH_HLSL_4_0_FL9_3_OUTPUT = 0x8B4A // D3D 11 feature level 9_3 -} ShShaderOutput; + SH_HLSL_4_0_FL9_3_OUTPUT = 0x8B4A, // D3D 11 feature level 9_3 + + // Output specialized GLSL to be fed to glslang for Vulkan SPIR. + SH_GLSL_VULKAN_OUTPUT = 0x8B4B, +}; // Compile options. -typedef enum { - SH_VALIDATE = 0, - SH_VALIDATE_LOOP_INDEXING = 0x0001, - SH_INTERMEDIATE_TREE = 0x0002, - SH_OBJECT_CODE = 0x0004, - SH_VARIABLES = 0x0008, - SH_LINE_DIRECTIVES = 0x0010, - SH_SOURCE_PATH = 0x0020, - SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040, - // If a sampler array index happens to be a loop index, - // 1) if its type is integer, unroll the loop. - // 2) if its type is float, fail the shader compile. - // This is to work around a mac driver bug. - SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080, - - // This is needed only as a workaround for certain OpenGL driver bugs. - SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100, - - // This is an experimental flag to enforce restrictions that aim to prevent - // timing attacks. - // It generates compilation errors for shaders that could expose sensitive - // texture information via the timing channel. - // To use this flag, you must compile the shader under the WebGL spec - // (using the SH_WEBGL_SPEC flag). - SH_TIMING_RESTRICTIONS = 0x0200, - - // This flag prints the dependency graph that is used to enforce timing - // restrictions on fragment shaders. - // This flag only has an effect if all of the following are true: - // - The shader spec is SH_WEBGL_SPEC. - // - The compile options contain the SH_TIMING_RESTRICTIONS flag. - // - The shader type is GL_FRAGMENT_SHADER. - SH_DEPENDENCY_GRAPH = 0x0400, - - // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions. - // This flag only enforces (and can only enforce) the packing - // restrictions for uniform variables in both vertex and fragment - // shaders. ShCheckVariablesWithinPackingLimits() lets embedders - // enforce the packing restrictions for varying variables during - // program link time. - SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800, - - // This flag ensures all indirect (expression-based) array indexing - // is clamped to the bounds of the array. This ensures, for example, - // that you cannot read off the end of a uniform, whether an array - // vec234, or mat234 type. The ShArrayIndexClampingStrategy enum, - // specified in the ShBuiltInResources when constructing the - // compiler, selects the strategy for the clamping implementation. - SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000, - - // This flag limits the complexity of an expression. - SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000, - - // This flag limits the depth of the call stack. - SH_LIMIT_CALL_STACK_DEPTH = 0x4000, - - // This flag initializes gl_Position to vec4(0,0,0,0) at the - // beginning of the vertex shader's main(), and has no effect in the - // fragment shader. It is intended as a workaround for drivers which - // incorrectly fail to link programs if gl_Position is not written. - SH_INIT_GL_POSITION = 0x8000, - - // This flag replaces - // "a && b" with "a ? b : false", - // "a || b" with "a ? true : b". - // This is to work around a MacOSX driver bug that |b| is executed - // independent of |a|'s value. - SH_UNFOLD_SHORT_CIRCUIT = 0x10000, - - // This flag initializes varyings without static use in vertex shader - // at the beginning of main(), and has no effects in the fragment shader. - // It is intended as a workaround for drivers which incorrectly optimize - // out such varyings and cause a link failure. - SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000, - - // This flag scalarizes vec/ivec/bvec/mat constructor args. - // It is intended as a workaround for Linux/Mac driver bugs. - SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000, - - // This flag overwrites a struct name with a unique prefix. - // It is intended as a workaround for drivers that do not handle - // struct scopes correctly, including all Mac drivers and Linux AMD. - SH_REGENERATE_STRUCT_NAMES = 0x80000, - - // This flag makes the compiler not prune unused function early in the - // compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH - // helps avoid bad shaders causing stack overflows. - SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000, - - // This flag works around a bug in NVIDIA 331 series drivers related - // to pow(x, y) where y is a constant vector. - SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000, - - // This flag works around bugs in Mac drivers related to do-while by - // transforming them into an other construct. - SH_REWRITE_DO_WHILE_LOOPS = 0x400000, -} ShCompileOptions; +// The Compile options type is defined in ShaderVars.h, to allow ANGLE to import the ShaderVars +// header without needing the ShaderLang header. This avoids some conflicts with glslang. + +const ShCompileOptions SH_VALIDATE = 0; +const ShCompileOptions SH_VALIDATE_LOOP_INDEXING = UINT64_C(1) << 0; +const ShCompileOptions SH_INTERMEDIATE_TREE = UINT64_C(1) << 1; +const ShCompileOptions SH_OBJECT_CODE = UINT64_C(1) << 2; +const ShCompileOptions SH_VARIABLES = UINT64_C(1) << 3; +const ShCompileOptions SH_LINE_DIRECTIVES = UINT64_C(1) << 4; +const ShCompileOptions SH_SOURCE_PATH = UINT64_C(1) << 5; + +// This flag will keep invariant declaration for input in fragment shader for GLSL >=4.20 on AMD. +// From GLSL >= 4.20, it's optional to add invariant for fragment input, but GPU vendors have +// different implementations about this. Some drivers forbid invariant in fragment for GLSL>= 4.20, +// e.g. Linux Mesa, some drivers treat that as optional, e.g. NVIDIA, some drivers require invariant +// must match between vertex and fragment shader, e.g. AMD. The behavior on AMD is obviously wrong. +// Remove invariant for input in fragment shader to workaround the restriction on Intel Mesa. +// But don't remove on AMD Linux to avoid triggering the bug on AMD. +const ShCompileOptions SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT = UINT64_C(1) << 6; + +// Due to spec difference between GLSL 4.1 or lower and ESSL3, some platforms (for example, Mac OSX +// core profile) require a variable's "invariant"/"centroid" qualifiers to match between vertex and +// fragment shader. A simple solution to allow such shaders to link is to omit the two qualifiers. +// AMD driver in Linux requires invariant qualifier to match between vertex and fragment shaders, +// while ESSL3 disallows invariant qualifier in fragment shader and GLSL >= 4.2 doesn't require +// invariant qualifier to match between shaders. Remove invariant qualifier from vertex shader to +// workaround AMD driver bug. +// Note that the two flags take effect on ESSL3 input shaders translated to GLSL 4.1 or lower and to +// GLSL 4.2 or newer on Linux AMD. +// TODO(zmo): This is not a good long-term solution. Simply dropping these qualifiers may break some +// developers' content. A more complex workaround of dynamically generating, compiling, and +// re-linking shaders that use these qualifiers should be implemented. +const ShCompileOptions SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3 = UINT64_C(1) << 7; + +// This flag works around bug in Intel Mac drivers related to abs(i) where +// i is an integer. +const ShCompileOptions SH_EMULATE_ABS_INT_FUNCTION = UINT64_C(1) << 8; + +// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions. +// This flag only enforces (and can only enforce) the packing +// restrictions for uniform variables in both vertex and fragment +// shaders. ShCheckVariablesWithinPackingLimits() lets embedders +// enforce the packing restrictions for varying variables during +// program link time. +const ShCompileOptions SH_ENFORCE_PACKING_RESTRICTIONS = UINT64_C(1) << 9; + +// This flag ensures all indirect (expression-based) array indexing +// is clamped to the bounds of the array. This ensures, for example, +// that you cannot read off the end of a uniform, whether an array +// vec234, or mat234 type. The ShArrayIndexClampingStrategy enum, +// specified in the ShBuiltInResources when constructing the +// compiler, selects the strategy for the clamping implementation. +const ShCompileOptions SH_CLAMP_INDIRECT_ARRAY_BOUNDS = UINT64_C(1) << 10; + +// This flag limits the complexity of an expression. +const ShCompileOptions SH_LIMIT_EXPRESSION_COMPLEXITY = UINT64_C(1) << 11; + +// This flag limits the depth of the call stack. +const ShCompileOptions SH_LIMIT_CALL_STACK_DEPTH = UINT64_C(1) << 12; + +// This flag initializes gl_Position to vec4(0,0,0,0) at the +// beginning of the vertex shader's main(), and has no effect in the +// fragment shader. It is intended as a workaround for drivers which +// incorrectly fail to link programs if gl_Position is not written. +const ShCompileOptions SH_INIT_GL_POSITION = UINT64_C(1) << 13; + +// This flag replaces +// "a && b" with "a ? b : false", +// "a || b" with "a ? true : b". +// This is to work around a MacOSX driver bug that |b| is executed +// independent of |a|'s value. +const ShCompileOptions SH_UNFOLD_SHORT_CIRCUIT = UINT64_C(1) << 14; + +// This flag initializes output variables to 0 at the beginning of main(). +// It is to avoid undefined behaviors. +const ShCompileOptions SH_INIT_OUTPUT_VARIABLES = UINT64_C(1) << 15; + +// This flag scalarizes vec/ivec/bvec/mat constructor args. +// It is intended as a workaround for Linux/Mac driver bugs. +const ShCompileOptions SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = UINT64_C(1) << 16; + +// This flag overwrites a struct name with a unique prefix. +// It is intended as a workaround for drivers that do not handle +// struct scopes correctly, including all Mac drivers and Linux AMD. +const ShCompileOptions SH_REGENERATE_STRUCT_NAMES = UINT64_C(1) << 17; + +// This flag makes the compiler not prune unused function early in the +// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH +// helps avoid bad shaders causing stack overflows. +const ShCompileOptions SH_DONT_PRUNE_UNUSED_FUNCTIONS = UINT64_C(1) << 18; + +// This flag works around a bug in NVIDIA 331 series drivers related +// to pow(x, y) where y is a constant vector. +const ShCompileOptions SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = UINT64_C(1) << 19; + +// This flag works around bugs in Mac drivers related to do-while by +// transforming them into an other construct. +const ShCompileOptions SH_REWRITE_DO_WHILE_LOOPS = UINT64_C(1) << 20; + +// This flag works around a bug in the HLSL compiler optimizer that folds certain +// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works +// by expanding the integer pow expressions into a series of multiplies. +const ShCompileOptions SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = UINT64_C(1) << 21; + +// Flatten "#pragma STDGL invariant(all)" into the declarations of +// varying variables and built-in GLSL variables. This compiler +// option is enabled automatically when needed. +const ShCompileOptions SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = UINT64_C(1) << 22; + +// Some drivers do not take into account the base level of the texture in the results of the +// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level +// offsetting. +const ShCompileOptions SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = UINT64_C(1) << 23; + +// This flag works around an issue in translating GLSL function texelFetchOffset on +// INTEL drivers. It works by translating texelFetchOffset into texelFetch. +const ShCompileOptions SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = UINT64_C(1) << 24; + +// This flag works around condition bug of for and while loops in Intel Mac OSX drivers. +// Condition calculation is not correct. Rewrite it from "CONDITION" to "CONDITION && true". +const ShCompileOptions SH_ADD_AND_TRUE_TO_LOOP_CONDITION = UINT64_C(1) << 25; + +// This flag works around a bug in evaluating unary minus operator on integer on some INTEL +// drivers. It works by translating -(int) into ~(int) + 1. +const ShCompileOptions SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR = UINT64_C(1) << 26; + +// This flag works around a bug in evaluating isnan() on some INTEL D3D and Mac OSX drivers. +// It works by using an expression to emulate this function. +const ShCompileOptions SH_EMULATE_ISNAN_FLOAT_FUNCTION = UINT64_C(1) << 27; + +// This flag will use all uniforms of unused std140 and shared uniform blocks at the +// beginning of the vertex/fragment shader's main(). It is intended as a workaround for Mac +// drivers with shader version 4.10. In those drivers, they will treat unused +// std140 and shared uniform blocks' members as inactive. However, WebGL2.0 based on +// OpenGL ES3.0.4 requires all members of a named uniform block declared with a shared or std140 +// layout qualifier to be considered active. The uniform block itself is also considered active. +const ShCompileOptions SH_USE_UNUSED_STANDARD_SHARED_BLOCKS = UINT64_C(1) << 28; + +// This flag works around a bug in unary minus operator on float numbers on Intel +// Mac OSX 10.11 drivers. It works by translating -float into 0.0 - float. +const ShCompileOptions SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR = UINT64_C(1) << 29; + +// This flag works around a bug in evaluating atan(y, x) on some NVIDIA OpenGL drivers. +// It works by using an expression to emulate this function. +const ShCompileOptions SH_EMULATE_ATAN2_FLOAT_FUNCTION = UINT64_C(1) << 30; + +// Set to 1 to translate gl_ViewID_OVR to an uniform so that the extension can be emulated. +// "uniform highp uint ViewID_OVR". +const ShCompileOptions SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM = UINT64_C(1) << 31; + +// Set to initialize uninitialized local and global temporary variables. Should only be used with +// GLSL output. In HLSL output variables are initialized regardless of if this flag is set. +const ShCompileOptions SH_INITIALIZE_UNINITIALIZED_LOCALS = UINT64_C(1) << 32; + +// The flag modifies the shader in the following way: +// Every occurrence of gl_InstanceID is replaced by the global temporary variable InstanceID. +// Every occurrence of gl_ViewID_OVR is replaced by the varying variable ViewID_OVR. +// At the beginning of the body of main() in a vertex shader the following initializers are added: +// ViewID_OVR = uint(gl_InstanceID) % num_views; +// InstanceID = gl_InstanceID / num_views; +// ViewID_OVR is added as a varying variable to both the vertex and fragment shaders. +const ShCompileOptions SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW = UINT64_C(1) << 33; + +// With the flag enabled the GLSL/ESSL vertex shader is modified to include code for viewport +// selection in the following way: +// - Code to enable the extension NV_viewport_array2 is included. +// - Code to select the viewport index or layer is inserted at the beginning of main after +// ViewID_OVR's initialization. +// - A declaration of the uniform multiviewBaseViewLayerIndex. +// Note: The SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW flag also has to be enabled to have the +// temporary variable ViewID_OVR declared and initialized. +const ShCompileOptions SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER = UINT64_C(1) << 34; + +// If the flag is enabled, gl_PointSize is clamped to the maximum point size specified in +// ShBuiltInResources in vertex shaders. +const ShCompileOptions SH_CLAMP_POINT_SIZE = UINT64_C(1) << 35; + +// Turn some arithmetic operations that operate on a float vector-scalar pair into vector-vector +// operations. This is done recursively. Some scalar binary operations inside vector constructors +// are also turned into vector operations. +// +// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA +// driver version 387.92. It works around the most common occurrences of the bug. +const ShCompileOptions SH_REWRITE_VECTOR_SCALAR_ARITHMETIC = UINT64_C(1) << 36; -// Defines alternate strategies for implementing array index clamping. -typedef enum { - // Use the clamp intrinsic for array index clamping. - SH_CLAMP_WITH_CLAMP_INTRINSIC = 1, +// Don't use loops to initialize uninitialized variables. Only has an effect if some kind of +// variable initialization is turned on. +const ShCompileOptions SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES = UINT64_C(1) << 37; - // Use a user-defined function for array index clamping. - SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION -} ShArrayIndexClampingStrategy; +// Defines alternate strategies for implementing array index clamping. +enum ShArrayIndexClampingStrategy +{ + // Use the clamp intrinsic for array index clamping. + SH_CLAMP_WITH_CLAMP_INTRINSIC = 1, -// -// Driver must call this first, once, before doing any other -// compiler operations. -// If the function succeeds, the return value is true, else false. -// -COMPILER_EXPORT bool ShInitialize(); -// -// Driver should call this at shutdown. -// If the function succeeds, the return value is true, else false. -// -COMPILER_EXPORT bool ShFinalize(); + // Use a user-defined function for array index clamping. + SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION +}; // The 64 bits hash function. The first parameter is the input string; the // second parameter is the string length. -typedef khronos_uint64_t (*ShHashFunction64)(const char*, size_t); +using ShHashFunction64 = khronos_uint64_t (*)(const char *, size_t); // // Implementation dependent built-in resources (constants and extensions). // The names for these resources has been obtained by stripping gl_/GL_. // -typedef struct +struct ShBuiltInResources { // Constants. int MaxVertexAttribs; @@ -255,6 +291,8 @@ typedef struct // Set to 1 to enable the extension, else 0. int OES_standard_derivatives; int OES_EGL_image_external; + int OES_EGL_image_external_essl3; + int NV_EGL_stream_consumer_external; int ARB_texture_rectangle; int EXT_blend_func_extended; int EXT_draw_buffers; @@ -264,6 +302,9 @@ typedef struct int EXT_shader_framebuffer_fetch; int NV_shader_framebuffer_fetch; int ARM_shader_framebuffer_fetch; + int OVR_multiview; + int EXT_YUV_target; + int OES_geometry_shader; // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate @@ -290,6 +331,9 @@ typedef struct // GLES SL version 100 gl_MaxDualSourceDrawBuffersEXT value for EXT_blend_func_extended. int MaxDualSourceDrawBuffers; + // Value of GL_MAX_VIEWS_OVR. + int MaxViewsOVR; + // Name Hashing. // Set a 64 bit hash function to enable user-defined name hashing. // Default is NULL. @@ -299,19 +343,107 @@ typedef struct // Default is SH_CLAMP_WITH_CLAMP_INTRINSIC. ShArrayIndexClampingStrategy ArrayIndexClampingStrategy; - // The maximum complexity an expression can be. + // The maximum complexity an expression can be when SH_LIMIT_EXPRESSION_COMPLEXITY is turned on. int MaxExpressionComplexity; // The maximum depth a call stack can be. int MaxCallStackDepth; -} ShBuiltInResources; -// -// Initialize built-in resources with minimum expected values. -// Parameters: -// resources: The object to initialize. Will be comparable with memcmp. -// -COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources); + // The maximum number of parameters a function can have when SH_LIMIT_EXPRESSION_COMPLEXITY is + // turned on. + int MaxFunctionParameters; + + // GLES 3.1 constants + + // texture gather offset constraints. + int MinProgramTextureGatherOffset; + int MaxProgramTextureGatherOffset; + + // maximum number of available image units + int MaxImageUnits; + + // maximum number of image uniforms in a vertex shader + int MaxVertexImageUniforms; + + // maximum number of image uniforms in a fragment shader + int MaxFragmentImageUniforms; + + // maximum number of image uniforms in a compute shader + int MaxComputeImageUniforms; + + // maximum total number of image uniforms in a program + int MaxCombinedImageUniforms; + + // maximum number of uniform locations + int MaxUniformLocations; + + // maximum number of ssbos and images in a shader + int MaxCombinedShaderOutputResources; + + // maximum number of groups in each dimension + std::array MaxComputeWorkGroupCount; + // maximum number of threads per work group in each dimension + std::array MaxComputeWorkGroupSize; + + // maximum number of total uniform components + int MaxComputeUniformComponents; + + // maximum number of texture image units in a compute shader + int MaxComputeTextureImageUnits; + + // maximum number of atomic counters in a compute shader + int MaxComputeAtomicCounters; + + // maximum number of atomic counter buffers in a compute shader + int MaxComputeAtomicCounterBuffers; + + // maximum number of atomic counters in a vertex shader + int MaxVertexAtomicCounters; + + // maximum number of atomic counters in a fragment shader + int MaxFragmentAtomicCounters; + + // maximum number of atomic counters in a program + int MaxCombinedAtomicCounters; + + // maximum binding for an atomic counter + int MaxAtomicCounterBindings; + + // maximum number of atomic counter buffers in a vertex shader + int MaxVertexAtomicCounterBuffers; + + // maximum number of atomic counter buffers in a fragment shader + int MaxFragmentAtomicCounterBuffers; + + // maximum number of atomic counter buffers in a program + int MaxCombinedAtomicCounterBuffers; + + // maximum number of buffer object storage in machine units + int MaxAtomicCounterBufferSize; + + // maximum number of uniform block bindings + int MaxUniformBufferBindings; + + // maximum number of shader storage buffer bindings + int MaxShaderStorageBufferBindings; + + // maximum point size (higher limit from ALIASED_POINT_SIZE_RANGE) + float MaxPointSize; + + // OES_geometry_shader constants + int MaxGeometryUniformComponents; + int MaxGeometryUniformBlocks; + int MaxGeometryInputComponents; + int MaxGeometryOutputComponents; + int MaxGeometryOutputVertices; + int MaxGeometryTotalOutputComponents; + int MaxGeometryTextureImageUnits; + int MaxGeometryAtomicCounterBuffers; + int MaxGeometryAtomicCounters; + int MaxGeometryShaderStorageBlocks; + int MaxGeometryShaderInvocations; + int MaxGeometryImageUniforms; +}; // // ShHandle held by but opaque to the driver. It is allocated, @@ -320,43 +452,60 @@ COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources); // // If handle creation fails, 0 will be returned. // -typedef void *ShHandle; +using ShHandle = void *; + +namespace sh +{ + +// +// Driver must call this first, once, before doing any other compiler operations. +// If the function succeeds, the return value is true, else false. +// +bool Initialize(); +// +// Driver should call this at shutdown. +// If the function succeeds, the return value is true, else false. +// +bool Finalize(); + +// +// Initialize built-in resources with minimum expected values. +// Parameters: +// resources: The object to initialize. Will be comparable with memcmp. +// +void InitBuiltInResources(ShBuiltInResources *resources); // -// Returns the a concatenated list of the items in ShBuiltInResources as a -// null-terminated string. +// Returns the a concatenated list of the items in ShBuiltInResources as a null-terminated string. // This function must be updated whenever ShBuiltInResources is changed. // Parameters: // handle: Specifies the handle of the compiler to be used. -COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle handle); +const std::string &GetBuiltInResourcesString(const ShHandle handle); // // Driver calls these to create and destroy compiler objects. // -// Returns the handle of constructed compiler, null if the requested compiler is -// not supported. +// Returns the handle of constructed compiler, null if the requested compiler is not supported. // Parameters: // type: Specifies the type of shader - GL_FRAGMENT_SHADER or GL_VERTEX_SHADER. -// spec: Specifies the language spec the compiler must conform to - -// SH_GLES2_SPEC or SH_WEBGL_SPEC. +// spec: Specifies the language spec the compiler must conform to - SH_GLES2_SPEC or SH_WEBGL_SPEC. // output: Specifies the output code type - for example SH_ESSL_OUTPUT, SH_GLSL_OUTPUT, // SH_HLSL_3_0_OUTPUT or SH_HLSL_4_1_OUTPUT. Note: Each output type may only // be supported in some configurations. // resources: Specifies the built-in resources. -COMPILER_EXPORT ShHandle ShConstructCompiler( - sh::GLenum type, - ShShaderSpec spec, - ShShaderOutput output, - const ShBuiltInResources *resources); -COMPILER_EXPORT void ShDestruct(ShHandle handle); +ShHandle ConstructCompiler(sh::GLenum type, + ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources *resources); +void Destruct(ShHandle handle); // // Compiles the given shader source. // If the function succeeds, the return value is true, else false. // Parameters: // handle: Specifies the handle of compiler to be used. -// shaderStrings: Specifies an array of pointers to null-terminated strings -// containing the shader source code. +// shaderStrings: Specifies an array of pointers to null-terminated strings containing the shader +// source code. // numStrings: Specifies the number of elements in shaderStrings array. // compileOptions: A mask containing the following parameters: // SH_VALIDATE: Validates shader to ensure that it conforms to the spec @@ -368,45 +517,41 @@ COMPILER_EXPORT void ShDestruct(ShHandle handle); // There is no need to specify this parameter when // compiling for WebGL - it is implied. // SH_INTERMEDIATE_TREE: Writes intermediate tree to info log. -// Can be queried by calling ShGetInfoLog(). +// Can be queried by calling sh::GetInfoLog(). // SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader. -// Can be queried by calling ShGetObjectCode(). +// Can be queried by calling sh::GetObjectCode(). // SH_VARIABLES: Extracts attributes, uniforms, and varyings. // Can be queried by calling ShGetVariableInfo(). // -COMPILER_EXPORT bool ShCompile( - const ShHandle handle, - const char * const shaderStrings[], - size_t numStrings, - int compileOptions); +bool Compile(const ShHandle handle, + const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); // Clears the results from the previous compilation. -COMPILER_EXPORT void ShClearResults(const ShHandle handle); +void ClearResults(const ShHandle handle); // Return the version of the shader language. -COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle); +int GetShaderVersion(const ShHandle handle); // Return the currently set language output type. -COMPILER_EXPORT ShShaderOutput ShGetShaderOutputType( - const ShHandle handle); +ShShaderOutput GetShaderOutputType(const ShHandle handle); // Returns null-terminated information log for a compiled shader. // Parameters: // handle: Specifies the compiler -COMPILER_EXPORT const std::string &ShGetInfoLog(const ShHandle handle); +const std::string &GetInfoLog(const ShHandle handle); // Returns null-terminated object code for a compiled shader. // Parameters: // handle: Specifies the compiler -COMPILER_EXPORT const std::string &ShGetObjectCode(const ShHandle handle); +const std::string &GetObjectCode(const ShHandle handle); -// Returns a (original_name, hash) map containing all the user defined -// names in the shader, including variable names, function names, struct -// names, and struct field names. +// Returns a (original_name, hash) map containing all the user defined names in the shader, +// including variable names, function names, struct names, and struct field names. // Parameters: // handle: Specifies the compiler -COMPILER_EXPORT const std::map *ShGetNameHashingMap( - const ShHandle handle); +const std::map *GetNameHashingMap(const ShHandle handle); // Shader variable inspection. // Returns a pointer to a list of variables of the designated type. @@ -414,52 +559,50 @@ COMPILER_EXPORT const std::map *ShGetNameHashingMap( // Returns NULL on failure. // Parameters: // handle: Specifies the compiler -COMPILER_EXPORT const std::vector *ShGetUniforms(const ShHandle handle); -COMPILER_EXPORT const std::vector *ShGetVaryings(const ShHandle handle); -COMPILER_EXPORT const std::vector *ShGetAttributes(const ShHandle handle); -COMPILER_EXPORT const std::vector *ShGetOutputVariables(const ShHandle handle); -COMPILER_EXPORT const std::vector *ShGetInterfaceBlocks(const ShHandle handle); - -typedef struct -{ - sh::GLenum type; - int size; -} ShVariableInfo; - -// Returns true if the passed in variables pack in maxVectors following -// the packing rules from the GLSL 1.017 spec, Appendix A, section 7. +const std::vector *GetUniforms(const ShHandle handle); +const std::vector *GetVaryings(const ShHandle handle); +const std::vector *GetInputVaryings(const ShHandle handle); +const std::vector *GetOutputVaryings(const ShHandle handle); +const std::vector *GetAttributes(const ShHandle handle); +const std::vector *GetOutputVariables(const ShHandle handle); +const std::vector *GetInterfaceBlocks(const ShHandle handle); +const std::vector *GetUniformBlocks(const ShHandle handle); +const std::vector *GetShaderStorageBlocks(const ShHandle handle); +sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle); +// Returns the number of views specified through the num_views layout qualifier. If num_views is +// not set, the function returns -1. +int GetVertexShaderNumViews(const ShHandle handle); + +// Returns true if the passed in variables pack in maxVectors followingthe packing rules from the +// GLSL 1.017 spec, Appendix A, section 7. // Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS // flag above. // Parameters: // maxVectors: the available rows of registers. -// varInfoArray: an array of variable info (types and sizes). -// varInfoArraySize: the size of the variable array. -COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits( - int maxVectors, - ShVariableInfo *varInfoArray, - size_t varInfoArraySize); - -// Gives the compiler-assigned register for an interface block. -// The method writes the value to the output variable "indexOut". -// Returns true if it found a valid interface block, false otherwise. -// Parameters: -// handle: Specifies the compiler -// interfaceBlockName: Specifies the interface block -// indexOut: output variable that stores the assigned register -COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle, - const std::string &interfaceBlockName, - unsigned int *indexOut); +// variables: an array of variables. +bool CheckVariablesWithinPackingLimits(int maxVectors, + const std::vector &variables); -// Gives the compiler-assigned register for uniforms in the default -// interface block. +// Gives the compiler-assigned register for a uniform block. // The method writes the value to the output variable "indexOut". -// Returns true if it found a valid default uniform, false otherwise. +// Returns true if it found a valid uniform block, false otherwise. // Parameters: // handle: Specifies the compiler -// interfaceBlockName: Specifies the uniform +// uniformBlockName: Specifies the uniform block // indexOut: output variable that stores the assigned register -COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle, - const std::string &uniformName, - unsigned int *indexOut); +bool GetUniformBlockRegister(const ShHandle handle, + const std::string &uniformBlockName, + unsigned int *indexOut); + +// Gives a map from uniform names to compiler-assigned registers in the default uniform block. +// Note that the map contains also registers of samplers that have been extracted from structs. +const std::map *GetUniformRegisterMap(const ShHandle handle); + +GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle); +GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle); +int GetGeometryShaderInvocations(const ShHandle handle); +int GetGeometryShaderMaxVertices(const ShHandle handle); + +} // namespace sh #endif // GLSLANG_SHADERLANG_H_ diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h index af9b65b7f5..709428aebf 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h @@ -10,15 +10,18 @@ #ifndef GLSLANG_SHADERVARS_H_ #define GLSLANG_SHADERVARS_H_ +#include +#include #include #include -#include -// Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum -// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h +// This type is defined here to simplify ANGLE's integration with glslang for SPIRv. +using ShCompileOptions = uint64_t; namespace sh { +// GLenum alias +typedef unsigned int GLenum; // Varying interpolation qualifier, see section 4.3.9 of the ESSL 3.00.4 spec enum InterpolationType @@ -29,30 +32,65 @@ enum InterpolationType }; // Validate link & SSO consistency of interpolation qualifiers -COMPILER_EXPORT bool InterpolationTypesMatch(InterpolationType a, InterpolationType b); +bool InterpolationTypesMatch(InterpolationType a, InterpolationType b); // Uniform block layout qualifier, see section 4.3.8.3 of the ESSL 3.00.4 spec enum BlockLayoutType { BLOCKLAYOUT_STANDARD, + BLOCKLAYOUT_STD140 = BLOCKLAYOUT_STANDARD, + BLOCKLAYOUT_STD430, // Shader storage block layout qualifier BLOCKLAYOUT_PACKED, BLOCKLAYOUT_SHARED }; +// Interface Blocks, see section 4.3.9 of the ESSL 3.10 spec +enum class BlockType +{ + BLOCK_UNIFORM, + BLOCK_BUFFER, + + // Required in OpenGL ES 3.1 extension GL_OES_shader_io_blocks. + // TODO(jiawei.shao@intel.com): add BLOCK_OUT. + BLOCK_IN +}; + // Base class for all variables defined in shaders, including Varyings, Uniforms, etc // Note: we must override the copy constructor and assignment operator so we can // work around excessive GCC binary bloating: // See https://code.google.com/p/angleproject/issues/detail?id=697 -struct COMPILER_EXPORT ShaderVariable +struct ShaderVariable { ShaderVariable(); + ShaderVariable(GLenum typeIn); ShaderVariable(GLenum typeIn, unsigned int arraySizeIn); ~ShaderVariable(); ShaderVariable(const ShaderVariable &other); ShaderVariable &operator=(const ShaderVariable &other); - bool isArray() const { return arraySize > 0; } - unsigned int elementCount() const { return std::max(1u, arraySize); } + bool isArrayOfArrays() const { return arraySizes.size() >= 2u; } + bool isArray() const { return !arraySizes.empty(); } + unsigned int getArraySizeProduct() const; + + // Array size 0 means not an array when passed to or returned from these functions. + // Note that setArraySize() is deprecated and should not be used inside ANGLE. + unsigned int getOutermostArraySize() const { return isArray() ? arraySizes.back() : 0; } + void setArraySize(unsigned int size); + + // Turn this ShaderVariable from an array into a specific element in that array. Will update + // flattenedOffsetInParentArrays. + void indexIntoArray(unsigned int arrayIndex); + + // Get the nth nested array size from the top. Caller is responsible for range checking + // arrayNestingIndex. + unsigned int getNestedArraySize(unsigned int arrayNestingIndex) const; + + // This function should only be used with variables that are of a basic type or an array of a + // basic type. Shader interface variables that are enumerated according to rules in GLES 3.1 + // spec section 7.3.1.1 page 77 are fine. For those variables the return value should match the + // ARRAY_SIZE value that can be queried through the API. + unsigned int getBasicTypeElementCount() const; + bool isStruct() const { return !fields.empty(); } // All of the shader's variables are described using nested data @@ -70,20 +108,32 @@ struct COMPILER_EXPORT ShaderVariable const ShaderVariable **leafVar, std::string* originalFullName) const; - bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; } + bool isBuiltIn() const; GLenum type; GLenum precision; std::string name; std::string mappedName; - unsigned int arraySize; + + // Used to make an array type. Outermost array size is stored at the end of the vector. + std::vector arraySizes; + + // Offset of this variable in parent arrays. In case the parent is an array of arrays, the + // offset is outerArrayElement * innerArraySize + innerArrayElement. + // For example, if there's a variable declared as size 3 array of size 4 array of int: + // int a[3][4]; + // then the flattenedOffsetInParentArrays of a[2] would be 2. + // and flattenedOffsetInParentArrays of a[2][1] would be 2*4 + 1 = 9. + unsigned int flattenedOffsetInParentArrays; + bool staticUse; std::vector fields; std::string structName; protected: bool isSameVariableAtLinkTime(const ShaderVariable &other, - bool matchPrecision) const; + bool matchPrecision, + bool matchName) const; bool operator==(const ShaderVariable &other) const; bool operator!=(const ShaderVariable &other) const @@ -92,7 +142,21 @@ struct COMPILER_EXPORT ShaderVariable } }; -struct COMPILER_EXPORT Uniform : public ShaderVariable +// A variable with an integer location to pass back to the GL API: either uniform (can have location +// in GLES3.1+), vertex shader input or fragment shader output. +struct VariableWithLocation : public ShaderVariable +{ + VariableWithLocation(); + ~VariableWithLocation(); + VariableWithLocation(const VariableWithLocation &other); + VariableWithLocation &operator=(const VariableWithLocation &other); + bool operator==(const VariableWithLocation &other) const; + bool operator!=(const VariableWithLocation &other) const { return !operator==(other); } + + int location; +}; + +struct Uniform : public VariableWithLocation { Uniform(); ~Uniform(); @@ -104,28 +168,17 @@ struct COMPILER_EXPORT Uniform : public ShaderVariable return !operator==(other); } + int binding; + int offset; + // Decide whether two uniforms are the same at shader link time, // assuming one from vertex shader and the other from fragment shader. - // See GLSL ES Spec 3.00.3, sec 4.3.5. + // GLSL ES Spec 3.00.3, section 4.3.5. + // GLSL ES Spec 3.10.4, section 4.4.5 bool isSameUniformAtLinkTime(const Uniform &other) const; }; -// An interface variable is a variable which passes data between the GL data structures and the -// shader execution: either vertex shader inputs or fragment shader outputs. These variables can -// have integer locations to pass back to the GL API. -struct COMPILER_EXPORT InterfaceVariable : public ShaderVariable -{ - InterfaceVariable(); - ~InterfaceVariable(); - InterfaceVariable(const InterfaceVariable &other); - InterfaceVariable &operator=(const InterfaceVariable &other); - bool operator==(const InterfaceVariable &other) const; - bool operator!=(const InterfaceVariable &other) const { return !operator==(other); } - - int location; -}; - -struct COMPILER_EXPORT Attribute : public InterfaceVariable +struct Attribute : public VariableWithLocation { Attribute(); ~Attribute(); @@ -135,7 +188,7 @@ struct COMPILER_EXPORT Attribute : public InterfaceVariable bool operator!=(const Attribute &other) const { return !operator==(other); } }; -struct COMPILER_EXPORT OutputVariable : public InterfaceVariable +struct OutputVariable : public VariableWithLocation { OutputVariable(); ~OutputVariable(); @@ -145,7 +198,7 @@ struct COMPILER_EXPORT OutputVariable : public InterfaceVariable bool operator!=(const OutputVariable &other) const { return !operator==(other); } }; -struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable +struct InterfaceBlockField : public ShaderVariable { InterfaceBlockField(); ~InterfaceBlockField(); @@ -167,7 +220,7 @@ struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable bool isRowMajorLayout; }; -struct COMPILER_EXPORT Varying : public ShaderVariable +struct Varying : public VariableWithLocation { Varying(); ~Varying(); @@ -193,7 +246,7 @@ struct COMPILER_EXPORT Varying : public ShaderVariable bool isInvariant; }; -struct COMPILER_EXPORT InterfaceBlock +struct InterfaceBlock { InterfaceBlock(); ~InterfaceBlock(); @@ -202,6 +255,15 @@ struct COMPILER_EXPORT InterfaceBlock // Fields from blocks with non-empty instance names are prefixed with the block name. std::string fieldPrefix() const; + std::string fieldMappedPrefix() const; + + // Decide whether two interface blocks are the same at shader link time. + bool isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const; + + bool isBuiltIn() const; + + bool isArray() const { return arraySize > 0; } + unsigned int elementCount() const { return std::max(1u, arraySize); } std::string name; std::string mappedName; @@ -209,10 +271,45 @@ struct COMPILER_EXPORT InterfaceBlock unsigned int arraySize; BlockLayoutType layout; bool isRowMajorLayout; + int binding; bool staticUse; + BlockType blockType; std::vector fields; }; +struct WorkGroupSize +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + WorkGroupSize() = default; + explicit constexpr WorkGroupSize(int initialSize) + : localSizeQualifiers{initialSize, initialSize, initialSize} + { + } + + void fill(int fillValue); + void setLocalSize(int localSizeX, int localSizeY, int localSizeZ); + + int &operator[](size_t index); + int operator[](size_t index) const; + size_t size() const; + + // Checks whether two work group size declarations match. + // Two work group size declarations are the same if the explicitly specified elements are the + // same or if one of them is specified as one and the other one is not specified + bool isWorkGroupSizeMatching(const WorkGroupSize &right) const; + + // Checks whether any of the values are set. + bool isAnyValueSet() const; + + // Checks whether all of the values are set. + bool isDeclared() const; + + // Checks whether either all of the values are set, or none of them are. + bool isLocalSizeValid() const; + + std::array localSizeQualifiers; +}; + } // namespace sh #endif // GLSLANG_SHADERVARS_H_ diff --git a/src/3rdparty/angle/include/KHR/khrplatform.h b/src/3rdparty/angle/include/KHR/khrplatform.h index c9e6f17d34..68fca48271 100644 --- a/src/3rdparty/angle/include/KHR/khrplatform.h +++ b/src/3rdparty/angle/include/KHR/khrplatform.h @@ -26,7 +26,7 @@ /* Khronos platform-specific types and definitions. * - * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ + * $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $ * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos @@ -101,6 +101,9 @@ # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# include +# define KHRONOS_APICALL __attribute__((visibility("default"))) __NDK_FPABI__ #else # define KHRONOS_APICALL #endif @@ -223,7 +226,7 @@ typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; /* - * Types that differ between LLP64 and LP64 architectures - in LLP64, + * Types that differ between LLP64 and LP64 architectures - in LLP64, * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ @@ -279,4 +282,4 @@ typedef enum { KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; -#endif /* __khrplatform_h_ */ +#endif /* __khrplatform_h_ */ \ No newline at end of file diff --git a/src/3rdparty/angle/include/angle_gl.h b/src/3rdparty/angle/include/angle_gl.h index 18de80b60b..b70a31c273 100644 --- a/src/3rdparty/angle/include/angle_gl.h +++ b/src/3rdparty/angle/include/angle_gl.h @@ -16,9 +16,4 @@ #include "GLES3/gl31.h" #include "GLES3/gl32.h" -// The following enum is used in ANGLE, but is from desktop GL -#ifndef GL_SAMPLER_2D_RECT_ARB -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#endif - #endif // ANGLEGL_H_ diff --git a/src/3rdparty/angle/include/export.h b/src/3rdparty/angle/include/export.h index cdf6245d6d..cf144f92a5 100644 --- a/src/3rdparty/angle/include/export.h +++ b/src/3rdparty/angle/include/export.h @@ -9,14 +9,17 @@ #ifndef LIBGLESV2_EXPORT_H_ #define LIBGLESV2_EXPORT_H_ +#if !defined(ANGLE_EXPORT) #if defined(_WIN32) -# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) +#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \ + defined(LIBANGLE_UTIL_IMPLEMENTATION) # define ANGLE_EXPORT __declspec(dllexport) # else # define ANGLE_EXPORT __declspec(dllimport) # endif #elif defined(__GNUC__) -# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) +#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \ + defined(LIBANGLE_UTIL_IMPLEMENTATION) # define ANGLE_EXPORT __attribute__((visibility ("default"))) # else # define ANGLE_EXPORT @@ -24,5 +27,6 @@ #else # define ANGLE_EXPORT #endif +#endif // !defined(ANGLE_EXPORT) #endif // LIBGLESV2_EXPORT_H_ diff --git a/src/3rdparty/angle/include/platform/Platform.h b/src/3rdparty/angle/include/platform/Platform.h index 0e8cdf477f..aa1221a86e 100644 --- a/src/3rdparty/angle/include/platform/Platform.h +++ b/src/3rdparty/angle/include/platform/Platform.h @@ -10,15 +10,16 @@ #define ANGLE_PLATFORM_H #include +#include #if defined(_WIN32) # if !defined(LIBANGLE_IMPLEMENTATION) # define ANGLE_PLATFORM_EXPORT __declspec(dllimport) +# else +# define ANGLE_PLATFORM_EXPORT __declspec(dllexport) # endif -#elif defined(__GNUC__) -# if defined(LIBANGLE_IMPLEMENTATION) -# define ANGLE_PLATFORM_EXPORT __attribute__((visibility ("default"))) -# endif +#elif defined(__GNUC__) || defined(__clang__) +# define ANGLE_PLATFORM_EXPORT __attribute__((visibility ("default"))) #endif #if !defined(ANGLE_PLATFORM_EXPORT) # define ANGLE_PLATFORM_EXPORT @@ -32,137 +33,295 @@ namespace angle { +struct WorkaroundsD3D; +using TraceEventHandle = uint64_t; +using EGLDisplayType = void *; +struct PlatformMethods; -class Platform -{ - public: - - // System -------------------------------------------------------------- - - // Wall clock time in seconds since the epoch. - // TODO(jmadill): investigate using an ANGLE internal time library - virtual double currentTime() { return 0; } - - // Monotonically increasing time in seconds from an arbitrary fixed point in the past. - // This function is expected to return at least millisecond-precision values. For this reason, - // it is recommended that the fixed point be no further in the past than the epoch. - virtual double monotonicallyIncreasingTime() { return 0; } - - // Logging ------------------------------------------------------------ - - // Log an error message within the platform implementation. - virtual void logError(const char *errorMessage) {} - - // Log a warning message within the platform implementation. - virtual void logWarning(const char *warningMessage) {} - - // Log an info message within the platform implementation. - virtual void logInfo(const char *infoMessage) {} - - // Tracing -------- - - // Get a pointer to the enabled state of the given trace category. The - // embedder can dynamically change the enabled state as trace event - // recording is started and stopped by the application. Only long-lived - // literal strings should be given as the category name. The implementation - // expects the returned pointer to be held permanently in a local static. If - // the unsigned char is non-zero, tracing is enabled. If tracing is enabled, - // addTraceEvent is expected to be called by the trace event macros. - virtual const unsigned char *getTraceCategoryEnabledFlag(const char *categoryName) { return 0; } - - typedef uint64_t TraceEventHandle; - - // Add a trace event to the platform tracing system. Depending on the actual - // enabled state, this event may be recorded or dropped. - // - phase specifies the type of event: - // - BEGIN ('B'): Marks the beginning of a scoped event. - // - END ('E'): Marks the end of a scoped event. - // - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't - // need a matching END event. Instead, at the end of the scope, - // updateTraceEventDuration() must be called with the TraceEventHandle - // returned from addTraceEvent(). - // - INSTANT ('I'): Standalone, instantaneous event. - // - START ('S'): Marks the beginning of an asynchronous event (the end - // event can occur in a different scope or thread). The id parameter is - // used to match START/FINISH pairs. - // - FINISH ('F'): Marks the end of an asynchronous event. - // - COUNTER ('C'): Used to trace integer quantities that change over - // time. The argument values are expected to be of type int. - // - METADATA ('M'): Reserved for internal use. - // - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag. - // - name is the name of the event. Also used to match BEGIN/END and - // START/FINISH pairs. - // - id optionally allows events of the same name to be distinguished from - // each other. For example, to trace the consutruction and destruction of - // objects, specify the pointer as the id parameter. - // - timestamp should be a time value returned from monotonicallyIncreasingTime. - // - numArgs specifies the number of elements in argNames, argTypes, and - // argValues. - // - argNames is the array of argument names. Use long-lived literal strings - // or specify the COPY flag. - // - argTypes is the array of argument types: - // - BOOL (1): bool - // - UINT (2): unsigned long long - // - INT (3): long long - // - DOUBLE (4): double - // - POINTER (5): void* - // - STRING (6): char* (long-lived null-terminated char* string) - // - COPY_STRING (7): char* (temporary null-terminated char* string) - // - CONVERTABLE (8): WebConvertableToTraceFormat - // - argValues is the array of argument values. Each value is the unsigned - // long long member of a union of all supported types. - // - flags can be 0 or one or more of the following, ORed together: - // - COPY (0x1): treat all strings (name, argNames and argValues of type - // string) as temporary so that they will be copied by addTraceEvent. - // - HAS_ID (0x2): use the id argument to uniquely identify the event for - // matching with other events of the same name. - // - MANGLE_ID (0x4): specify this flag if the id parameter is the value - // of a pointer. - virtual TraceEventHandle addTraceEvent(char phase, - const unsigned char *categoryEnabledFlag, - const char *name, - unsigned long long id, - double timestamp, - int numArgs, - const char **argNames, - const unsigned char *argTypes, - const unsigned long long *argValues, - unsigned char flags) - { - return 0; - } - - // Set the duration field of a COMPLETE trace event. - virtual void updateTraceEventDuration(const unsigned char *categoryEnabledFlag, const char *name, TraceEventHandle eventHandle) { } - - // Callbacks for reporting histogram data. - // CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 would do. - virtual void histogramCustomCounts(const char *name, int sample, int min, int max, int bucketCount) { } - // Enumeration histogram buckets are linear, boundaryValue should be larger than any possible sample value. - virtual void histogramEnumeration(const char *name, int sample, int boundaryValue) { } - // Unlike enumeration histograms, sparse histograms only allocate memory for non-empty buckets. - virtual void histogramSparse(const char *name, int sample) { } - // Boolean histograms track two-state variables. - virtual void histogramBoolean(const char *name, bool sample) { } - - protected: - virtual ~Platform() { } -}; +// Use a C-like API to not trigger undefined calling behaviour. +// Avoid using decltype here to work around sanitizer limitations. +// TODO(jmadill): Use decltype here if/when UBSAN is fixed. + +// System -------------------------------------------------------------- + +// Wall clock time in seconds since the epoch. +// TODO(jmadill): investigate using an ANGLE internal time library +using CurrentTimeFunc = double (*)(PlatformMethods *platform); +inline double DefaultCurrentTime(PlatformMethods *platform) +{ + return 0.0; +} + +// Monotonically increasing time in seconds from an arbitrary fixed point in the past. +// This function is expected to return at least millisecond-precision values. For this reason, +// it is recommended that the fixed point be no further in the past than the epoch. +using MonotonicallyIncreasingTimeFunc = double (*)(PlatformMethods *platform); +inline double DefaultMonotonicallyIncreasingTime(PlatformMethods *platform) +{ + return 0.0; +} + +// Logging ------------------------------------------------------------ + +// Log an error message within the platform implementation. +using LogErrorFunc = void (*)(PlatformMethods *platform, const char *errorMessage); +inline void DefaultLogError(PlatformMethods *platform, const char *errorMessage) +{ +} + +// Log a warning message within the platform implementation. +using LogWarningFunc = void (*)(PlatformMethods *platform, const char *warningMessage); +inline void DefaultLogWarning(PlatformMethods *platform, const char *warningMessage) +{ +} +// Log an info message within the platform implementation. +using LogInfoFunc = void (*)(PlatformMethods *platform, const char *infoMessage); +inline void DefaultLogInfo(PlatformMethods *platform, const char *infoMessage) +{ } -extern "C" +// Tracing -------- + +// Get a pointer to the enabled state of the given trace category. The +// embedder can dynamically change the enabled state as trace event +// recording is started and stopped by the application. Only long-lived +// literal strings should be given as the category name. The implementation +// expects the returned pointer to be held permanently in a local static. If +// the unsigned char is non-zero, tracing is enabled. If tracing is enabled, +// addTraceEvent is expected to be called by the trace event macros. +using GetTraceCategoryEnabledFlagFunc = const unsigned char *(*)(PlatformMethods *platform, + const char *categoryName); +inline const unsigned char *DefaultGetTraceCategoryEnabledFlag(PlatformMethods *platform, + const char *categoryName) { + return nullptr; +} -typedef void (ANGLE_APIENTRY *ANGLEPlatformInitializeFunc)(angle::Platform*); -ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform*); +// +// Add a trace event to the platform tracing system. Depending on the actual +// enabled state, this event may be recorded or dropped. +// - phase specifies the type of event: +// - BEGIN ('B'): Marks the beginning of a scoped event. +// - END ('E'): Marks the end of a scoped event. +// - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't +// need a matching END event. Instead, at the end of the scope, +// updateTraceEventDuration() must be called with the TraceEventHandle +// returned from addTraceEvent(). +// - INSTANT ('I'): Standalone, instantaneous event. +// - START ('S'): Marks the beginning of an asynchronous event (the end +// event can occur in a different scope or thread). The id parameter is +// used to match START/FINISH pairs. +// - FINISH ('F'): Marks the end of an asynchronous event. +// - COUNTER ('C'): Used to trace integer quantities that change over +// time. The argument values are expected to be of type int. +// - METADATA ('M'): Reserved for internal use. +// - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag. +// - name is the name of the event. Also used to match BEGIN/END and +// START/FINISH pairs. +// - id optionally allows events of the same name to be distinguished from +// each other. For example, to trace the consutruction and destruction of +// objects, specify the pointer as the id parameter. +// - timestamp should be a time value returned from monotonicallyIncreasingTime. +// - numArgs specifies the number of elements in argNames, argTypes, and +// argValues. +// - argNames is the array of argument names. Use long-lived literal strings +// or specify the COPY flag. +// - argTypes is the array of argument types: +// - BOOL (1): bool +// - UINT (2): unsigned long long +// - INT (3): long long +// - DOUBLE (4): double +// - POINTER (5): void* +// - STRING (6): char* (long-lived null-terminated char* string) +// - COPY_STRING (7): char* (temporary null-terminated char* string) +// - CONVERTABLE (8): WebConvertableToTraceFormat +// - argValues is the array of argument values. Each value is the unsigned +// long long member of a union of all supported types. +// - flags can be 0 or one or more of the following, ORed together: +// - COPY (0x1): treat all strings (name, argNames and argValues of type +// string) as temporary so that they will be copied by addTraceEvent. +// - HAS_ID (0x2): use the id argument to uniquely identify the event for +// matching with other events of the same name. +// - MANGLE_ID (0x4): specify this flag if the id parameter is the value +// of a pointer. +using AddTraceEventFunc = angle::TraceEventHandle (*)(PlatformMethods *platform, + char phase, + const unsigned char *categoryEnabledFlag, + const char *name, + unsigned long long id, + double timestamp, + int numArgs, + const char **argNames, + const unsigned char *argTypes, + const unsigned long long *argValues, + unsigned char flags); +inline angle::TraceEventHandle DefaultAddTraceEvent(PlatformMethods *platform, + char phase, + const unsigned char *categoryEnabledFlag, + const char *name, + unsigned long long id, + double timestamp, + int numArgs, + const char **argNames, + const unsigned char *argTypes, + const unsigned long long *argValues, + unsigned char flags) +{ + return 0; +} -typedef void (ANGLE_APIENTRY *ANGLEPlatformShutdownFunc)(); -ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEPlatformShutdown(); +// Set the duration field of a COMPLETE trace event. +using UpdateTraceEventDurationFunc = void (*)(PlatformMethods *platform, + const unsigned char *categoryEnabledFlag, + const char *name, + angle::TraceEventHandle eventHandle); +inline void DefaultUpdateTraceEventDuration(PlatformMethods *platform, + const unsigned char *categoryEnabledFlag, + const char *name, + angle::TraceEventHandle eventHandle) +{ +} + +// Callbacks for reporting histogram data. +// CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 +// would do. +using HistogramCustomCountsFunc = void (*)(PlatformMethods *platform, + const char *name, + int sample, + int min, + int max, + int bucketCount); +inline void DefaultHistogramCustomCounts(PlatformMethods *platform, + const char *name, + int sample, + int min, + int max, + int bucketCount) +{ +} +// Enumeration histogram buckets are linear, boundaryValue should be larger than any possible sample +// value. +using HistogramEnumerationFunc = void (*)(PlatformMethods *platform, + const char *name, + int sample, + int boundaryValue); +inline void DefaultHistogramEnumeration(PlatformMethods *platform, + const char *name, + int sample, + int boundaryValue) +{ +} +// Unlike enumeration histograms, sparse histograms only allocate memory for non-empty buckets. +using HistogramSparseFunc = void (*)(PlatformMethods *platform, const char *name, int sample); +inline void DefaultHistogramSparse(PlatformMethods *platform, const char *name, int sample) +{ +} +// Boolean histograms track two-state variables. +using HistogramBooleanFunc = void (*)(PlatformMethods *platform, const char *name, bool sample); +inline void DefaultHistogramBoolean(PlatformMethods *platform, const char *name, bool sample) +{ +} -typedef angle::Platform *(ANGLE_APIENTRY *ANGLEPlatformCurrentFunc)(); -ANGLE_PLATFORM_EXPORT angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent(); +// Allows us to programatically override ANGLE's default workarounds for testing purposes. +using OverrideWorkaroundsD3DFunc = void (*)(PlatformMethods *platform, + angle::WorkaroundsD3D *workaroundsD3D); +inline void DefaultOverrideWorkaroundsD3D(PlatformMethods *platform, + angle::WorkaroundsD3D *workaroundsD3D) +{ +} +// Callback on a successful program link with the program binary. Can be used to store +// shaders to disk. Keys are a 160-bit SHA-1 hash. +using ProgramKeyType = std::array; +using CacheProgramFunc = void (*)(PlatformMethods *platform, + const ProgramKeyType &key, + size_t programSize, + const uint8_t *programBytes); +inline void DefaultCacheProgram(PlatformMethods *platform, + const ProgramKeyType &key, + size_t programSize, + const uint8_t *programBytes) +{ } +// Platform methods are enumerated here once. +#define ANGLE_PLATFORM_OP(OP) \ + OP(currentTime, CurrentTime) \ + OP(monotonicallyIncreasingTime, MonotonicallyIncreasingTime) \ + OP(logError, LogError) \ + OP(logWarning, LogWarning) \ + OP(logInfo, LogInfo) \ + OP(getTraceCategoryEnabledFlag, GetTraceCategoryEnabledFlag) \ + OP(addTraceEvent, AddTraceEvent) \ + OP(updateTraceEventDuration, UpdateTraceEventDuration) \ + OP(histogramCustomCounts, HistogramCustomCounts) \ + OP(histogramEnumeration, HistogramEnumeration) \ + OP(histogramSparse, HistogramSparse) \ + OP(histogramBoolean, HistogramBoolean) \ + OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \ + OP(cacheProgram, CacheProgram) + +#define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName; + +struct ANGLE_PLATFORM_EXPORT PlatformMethods +{ + PlatformMethods(); + + // User data pointer for any implementation specific members. Put it at the start of the + // platform structure so it doesn't become overwritten if one version of the platform + // adds or removes new members. + void *context = 0; + + ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_DEF); +}; + +#undef ANGLE_PLATFORM_METHOD_DEF + +// Subtract one to account for the context pointer. +constexpr unsigned int g_NumPlatformMethods = (sizeof(PlatformMethods) / sizeof(uintptr_t)) - 1; + +#define ANGLE_PLATFORM_METHOD_STRING(Name) #Name +#define ANGLE_PLATFORM_METHOD_STRING2(Name, CapsName) ANGLE_PLATFORM_METHOD_STRING(Name), + +constexpr const char *const g_PlatformMethodNames[g_NumPlatformMethods] = { + ANGLE_PLATFORM_OP(ANGLE_PLATFORM_METHOD_STRING2)}; + +#undef ANGLE_PLATFORM_METHOD_STRING2 +#undef ANGLE_PLATFORM_METHOD_STRING + +} // namespace angle + +extern "C" { + +// Gets the platform methods on the passed-in EGL display. If the method name signature does not +// match the compiled signature for this ANGLE, false is returned. On success true is returned. +// The application should set any platform methods it cares about on the returned pointer. +// If display is not valid, behaviour is undefined. + +ANGLE_PLATFORM_EXPORT bool ANGLE_APIENTRY ANGLEGetDisplayPlatform(angle::EGLDisplayType display, + const char *const methodNames[], + unsigned int methodNameCount, + void *context, + void *platformMethodsOut); + +// Sets the platform methods back to their defaults. +// If display is not valid, behaviour is undefined. +ANGLE_PLATFORM_EXPORT void ANGLE_APIENTRY ANGLEResetDisplayPlatform(angle::EGLDisplayType display); + +} // extern "C" + +namespace angle +{ +typedef bool(ANGLE_APIENTRY *GetDisplayPlatformFunc)(angle::EGLDisplayType, + const char *const *, + unsigned int, + void *, + void *); +typedef void(ANGLE_APIENTRY *ResetDisplayPlatformFunc)(angle::EGLDisplayType); +} // namespace angle + +// This function is not exported +angle::PlatformMethods *ANGLEPlatformCurrent(); + #endif // ANGLE_PLATFORM_H diff --git a/src/3rdparty/angle/include/platform/WorkaroundsD3D.h b/src/3rdparty/angle/include/platform/WorkaroundsD3D.h new file mode 100644 index 0000000000..cc2abbf1d2 --- /dev/null +++ b/src/3rdparty/angle/include/platform/WorkaroundsD3D.h @@ -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. +// + +// WorkaroundsD3D.h: Workarounds for D3D driver bugs and other issues. + +#ifndef ANGLE_PLATFORM_WORKAROUNDSD3D_H_ +#define ANGLE_PLATFORM_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 angle +{ +struct CompilerWorkaroundsD3D +{ + bool skipOptimization = false; + bool useMaxOptimization = false; + + // IEEE strictness needs to be enabled for NANs to work. + bool enableIEEEStrictness = false; +}; + +struct WorkaroundsD3D +{ + // 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 = false; + + bool setDataFasterThanImageUpload = false; + + // 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 = false; + + // 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 = false; + + // A bug fixed in NVIDIA driver version 347.88 < x <= 368.81 triggers a TDR when using + // CopySubresourceRegion from a staging texture to a depth/stencil in D3D11. The workaround + // is to use UpdateSubresource to trigger an extra copy. We disable this workaround on newer + // NVIDIA driver versions because of a second driver bug present with the workaround enabled. + // (See: http://anglebug.com/1452) + bool depthStencilBlitExtraCopy = false; + + // The HLSL optimizer has a bug with optimizing "pow" in certain integer-valued expressions. + // We can work around this by expanding the pow into a series of multiplies if we're running + // under the affected compiler. + bool expandIntegerPowExpressions = false; + + // NVIDIA drivers sometimes write out-of-order results to StreamOut buffers when transform + // feedback is used to repeatedly write to the same buffer positions. + bool flushAfterEndingTransformFeedback = false; + + // Some drivers (NVIDIA) do not take into account the base level of the texture in the results + // of the HLSL GetDimensions builtin. + bool getDimensionsIgnoresBaseLevel = false; + + // On some Intel drivers, HLSL's function texture.Load returns 0 when the parameter Location + // is negative, even if the sum of Offset and Location is in range. This may cause errors when + // translating GLSL's function texelFetchOffset into texture.Load, as it is valid for + // texelFetchOffset to use negative texture coordinates as its parameter P when the sum of P + // and Offset is in range. To work around this, we translate texelFetchOffset into texelFetch + // by adding Offset directly to Location before reading the texture. + bool preAddTexelFetchOffsets = false; + + // On some AMD drivers, 1x1 and 2x2 mips of depth/stencil textures aren't sampled correctly. + // We can work around this bug by doing an internal blit to a temporary single-channel texture + // before we sample. + bool emulateTinyStencilTextures = false; + + // In Intel driver, the data with format DXGI_FORMAT_B5G6R5_UNORM will be parsed incorrectly. + // This workaroud will disable B5G6R5 support when it's Intel driver. By default, it will use + // R8G8B8A8 format. This bug is fixed in version 4539 on Intel drivers. + bool disableB5G6R5Support = false; + + // On some Intel drivers, evaluating unary minus operator on integer may get wrong answer in + // vertex shaders. To work around this bug, we translate -(int) into ~(int)+1. + // This driver bug is fixed in 20.19.15.4624. + bool rewriteUnaryMinusOperator = false; + + // On some Intel drivers, using isnan() on highp float will get wrong answer. To work around + // this bug, we use an expression to emulate function isnan(). + // Tracking bug: https://crbug.com/650547 + // This driver bug is fixed in 21.20.16.4542. + bool emulateIsnanFloat = false; + + // On some Intel drivers, using clear() may not take effect. To work around this bug, we call + // clear() twice on these platforms. + // Tracking bug: https://crbug.com/655534 + bool callClearTwice = false; + + // On some Intel drivers, copying from staging storage to constant buffer storage does not + // seem to work. Work around this by keeping system memory storage as a canonical reference + // for buffer data. + // D3D11-only workaround. See http://crbug.com/593024. + bool useSystemMemoryForConstantBuffers = false; + + // This workaround is for the ANGLE_multiview extension. If enabled the viewport or render + // target slice will be selected in the geometry shader stage. The workaround flag is added to + // make it possible to select the code path in end2end and performance tests. + bool selectViewInGeometryShader = false; + + // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel + // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel + // shader. + // 1. If rendertarget is not set, the pixel shader will be recompiled to drop 'SV_TARGET'. + // When using a pixel shader with no 'SV_TARGET' in a draw, the pixels are always generated even + // if they should be discard by 'discard' statements. + // 2. If ID3D11BlendState.RenderTarget[].RenderTargetWriteMask is 0 and rendertarget is not set, + // then rendering samples also pass neglecting discard statements in pixel shader. + // So we add a dummy texture as render target in such case. See http://anglebug.com/2152 + bool addDummyTextureNoRenderTarget = false; +}; + +} // namespace angle + +#endif // ANGLE_PLATFORM_WORKAROUNDSD3D_H_ diff --git a/src/3rdparty/angle/src/common/BitSetIterator.h b/src/3rdparty/angle/src/common/BitSetIterator.h deleted file mode 100644 index 3248ce44c9..0000000000 --- a/src/3rdparty/angle/src/common/BitSetIterator.h +++ /dev/null @@ -1,156 +0,0 @@ -// -// 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/Color.h b/src/3rdparty/angle/src/common/Color.h new file mode 100644 index 0000000000..2b4d2f6fba --- /dev/null +++ b/src/3rdparty/angle/src/common/Color.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Color.h : Defines the Color type used throughout the ANGLE libraries + +#ifndef COMMON_COLOR_H_ +#define COMMON_COLOR_H_ + +namespace angle +{ + +template +struct Color +{ + T red; + T green; + T blue; + T alpha; + + Color(); + Color(T r, T g, T b, T a); +}; + +template +bool operator==(const Color &a, const Color &b); + +template +bool operator!=(const Color &a, const Color &b); + +typedef Color ColorF; +typedef Color ColorI; +typedef Color ColorUI; + +} // namespace angle + +// TODO: Move this fully into the angle namespace +namespace gl +{ + +template +using Color = angle::Color; +using ColorF = angle::ColorF; +using ColorI = angle::ColorI; +using ColorUI = angle::ColorUI; + +} // namespace gl + +#include "Color.inl" + +#endif // COMMON_COLOR_H_ diff --git a/src/3rdparty/angle/src/common/Color.inl b/src/3rdparty/angle/src/common/Color.inl new file mode 100644 index 0000000000..c3073256b5 --- /dev/null +++ b/src/3rdparty/angle/src/common/Color.inl @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Color.inl : Inline definitions of some functions from Color.h + +namespace angle +{ + +template +Color::Color() : Color(0, 0, 0, 0) +{ +} + +template +Color::Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) +{ +} + +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); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/MemoryBuffer.cpp b/src/3rdparty/angle/src/common/MemoryBuffer.cpp index e7a3fb4a2b..6f5188c69c 100644 --- a/src/3rdparty/angle/src/common/MemoryBuffer.cpp +++ b/src/3rdparty/angle/src/common/MemoryBuffer.cpp @@ -11,19 +11,18 @@ #include "common/debug.h" -namespace rx +namespace angle { -MemoryBuffer::MemoryBuffer() - : mSize(0), - mData(NULL) +// MemoryBuffer implementation. +MemoryBuffer::MemoryBuffer() : mSize(0), mData(nullptr) { } MemoryBuffer::~MemoryBuffer() { free(mData); - mData = NULL; + mData = nullptr; } bool MemoryBuffer::resize(size_t size) @@ -31,7 +30,7 @@ bool MemoryBuffer::resize(size_t size) if (size == 0) { free(mData); - mData = NULL; + mData = nullptr; mSize = 0; return true; } @@ -42,8 +41,8 @@ bool MemoryBuffer::resize(size_t size) } // Only reallocate if the size has changed. - uint8_t *newMemory = reinterpret_cast(malloc(sizeof(uint8_t) * size)); - if (newMemory == NULL) + uint8_t *newMemory = reinterpret_cast(malloc(sizeof(uint8_t) * size)); + if (newMemory == nullptr) { return false; } @@ -61,20 +60,96 @@ bool MemoryBuffer::resize(size_t size) return true; } -size_t MemoryBuffer::size() const +void MemoryBuffer::fill(uint8_t datum) { - return mSize; + if (!empty()) + { + std::fill(mData, mData + mSize, datum); + } +} + +MemoryBuffer::MemoryBuffer(MemoryBuffer &&other) : MemoryBuffer() +{ + *this = std::move(other); } -const uint8_t *MemoryBuffer::data() const +MemoryBuffer &MemoryBuffer::operator=(MemoryBuffer &&other) { - return mData; + std::swap(mSize, other.mSize); + std::swap(mData, other.mData); + return *this; } -uint8_t *MemoryBuffer::data() +// ScratchBuffer implementation. + +ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) { - ASSERT(mData); - return mData; } +ScratchBuffer::~ScratchBuffer() +{ +} + +bool ScratchBuffer::get(size_t requestedSize, MemoryBuffer **memoryBufferOut) +{ + return getImpl(requestedSize, memoryBufferOut, Optional::Invalid()); } + +bool ScratchBuffer::getInitialized(size_t requestedSize, + MemoryBuffer **memoryBufferOut, + uint8_t initValue) +{ + return getImpl(requestedSize, memoryBufferOut, Optional(initValue)); +} + +bool ScratchBuffer::getImpl(size_t requestedSize, + MemoryBuffer **memoryBufferOut, + Optional initValue) +{ + if (mScratchMemory.size() == requestedSize) + { + mResetCounter = mLifetime; + *memoryBufferOut = &mScratchMemory; + return true; + } + + if (mScratchMemory.size() > requestedSize) + { + tick(); + } + + if (mResetCounter == 0 || mScratchMemory.size() < requestedSize) + { + mScratchMemory.resize(0); + if (!mScratchMemory.resize(requestedSize)) + { + return false; + } + mResetCounter = mLifetime; + if (initValue.valid()) + { + mScratchMemory.fill(initValue.value()); + } + } + + ASSERT(mScratchMemory.size() >= requestedSize); + + *memoryBufferOut = &mScratchMemory; + return true; +} + +void ScratchBuffer::tick() +{ + if (mResetCounter > 0) + { + --mResetCounter; + } +} + +void ScratchBuffer::clear() +{ + mResetCounter = mLifetime; + mScratchMemory.resize(0); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/MemoryBuffer.h b/src/3rdparty/angle/src/common/MemoryBuffer.h index ec621cbca7..f76b9ee62e 100644 --- a/src/3rdparty/angle/src/common/MemoryBuffer.h +++ b/src/3rdparty/angle/src/common/MemoryBuffer.h @@ -7,32 +7,71 @@ #ifndef COMMON_MEMORYBUFFER_H_ #define COMMON_MEMORYBUFFER_H_ +#include "common/Optional.h" #include "common/angleutils.h" +#include "common/debug.h" -#include #include +#include -namespace rx +namespace angle { -class MemoryBuffer : angle::NonCopyable +class MemoryBuffer final : NonCopyable { public: MemoryBuffer(); ~MemoryBuffer(); + MemoryBuffer(MemoryBuffer &&other); + MemoryBuffer &operator=(MemoryBuffer &&other); + bool resize(size_t size); - size_t size() const; + size_t size() const { return mSize; } bool empty() const { return mSize == 0; } - const uint8_t *data() const; - uint8_t *data(); + const uint8_t *data() const { return mData; } + uint8_t *data() + { + ASSERT(mData); + return mData; + } + + void fill(uint8_t datum); private: size_t mSize; uint8_t *mData; }; -} +class ScratchBuffer final : NonCopyable +{ + public: + // If we request a scratch buffer requesting a smaller size this many times, release and + // recreate the scratch buffer. This ensures we don't have a degenerate case where we are stuck + // hogging memory. + ScratchBuffer(uint32_t lifetime); + ~ScratchBuffer(); + + // Returns true with a memory buffer of the requested size, or false on failure. + bool get(size_t requestedSize, MemoryBuffer **memoryBufferOut); + + // Same as get, but ensures new values are initialized to a fixed constant. + bool getInitialized(size_t requestedSize, MemoryBuffer **memoryBufferOut, uint8_t initValue); + + // Ticks the release counter for the scratch buffer. Also done implicitly in get(). + void tick(); + + void clear(); + + private: + bool getImpl(size_t requestedSize, MemoryBuffer **memoryBufferOut, Optional initValue); + + const uint32_t mLifetime; + uint32_t mResetCounter; + MemoryBuffer mScratchMemory; +}; + +} // namespace angle -#endif // COMMON_MEMORYBUFFER_H_ +#endif // COMMON_MEMORYBUFFER_H_ diff --git a/src/3rdparty/angle/src/common/Optional.h b/src/3rdparty/angle/src/common/Optional.h index 256f38f329..822de4de51 100644 --- a/src/3rdparty/angle/src/common/Optional.h +++ b/src/3rdparty/angle/src/common/Optional.h @@ -10,23 +10,16 @@ #ifndef COMMON_OPTIONAL_H_ #define COMMON_OPTIONAL_H_ +#include + template struct Optional { - Optional() - : mValid(false), - mValue(T()) - {} + Optional() : mValid(false), mValue(T()) {} - explicit Optional(const T &valueIn) - : mValid(true), - mValue(valueIn) - {} + Optional(const T &valueIn) : mValid(true), mValue(valueIn) {} - Optional(const Optional &other) - : mValid(other.mValid), - mValue(other.mValue) - {} + Optional(const Optional &other) : mValid(other.mValid), mValue(other.mValue) {} Optional &operator=(const Optional &other) { @@ -49,10 +42,7 @@ struct Optional return *this; } - void reset() - { - mValid = false; - } + void reset() { mValid = false; } static Optional Invalid() { return Optional(); } @@ -64,14 +54,15 @@ struct Optional return ((mValid == other.mValid) && (!mValid || (mValue == other.mValue))); } - bool operator!=(const Optional &other) const - { - return !(*this == other); - } + bool operator!=(const Optional &other) const { return !(*this == other); } + + bool operator==(const T &value) const { return mValid && (mValue == value); } + + bool operator!=(const T &value) const { return !(*this == value); } private: bool mValid; T mValue; }; -#endif // COMMON_OPTIONAL_H_ +#endif // COMMON_OPTIONAL_H_ diff --git a/src/3rdparty/angle/src/common/angleutils.cpp b/src/3rdparty/angle/src/common/angleutils.cpp index 7099c21730..739d12a767 100644 --- a/src/3rdparty/angle/src/common/angleutils.cpp +++ b/src/3rdparty/angle/src/common/angleutils.cpp @@ -14,39 +14,61 @@ namespace angle { +// dirtyPointer is a special value that will make the comparison with any valid pointer fail and +// force the renderer to re-apply the state. const uintptr_t DirtyPointer = std::numeric_limits::max(); } +std::string ArrayString(unsigned int i) +{ + // We assume that UINT_MAX and GL_INVALID_INDEX are equal. + ASSERT(i != UINT_MAX); + + std::stringstream strstr; + strstr << "["; + strstr << i; + strstr << "]"; + return strstr.str(); +} + +std::string ArrayIndexString(const std::vector &indices) +{ + std::stringstream strstr; + + for (auto indicesIt = indices.rbegin(); indicesIt != indices.rend(); ++indicesIt) + { + // We assume that UINT_MAX and GL_INVALID_INDEX are equal. + ASSERT(*indicesIt != UINT_MAX); + strstr << "["; + strstr << (*indicesIt); + strstr << "]"; + } + + return strstr.str(); +} + size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector& outBuffer) { + // The state of the va_list passed to vsnprintf is undefined after the call, do a copy in case + // we need to grow the buffer. + va_list varargCopy; + va_copy(varargCopy, vararg); + // Attempt to just print to the current buffer - int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, varargCopy); + va_end(varargCopy); + if (len < 0 || static_cast(len) >= outBuffer.size()) { // Buffer was not large enough, calculate the required size and resize the buffer - len = vsnprintf(NULL, 0, fmt, vararg); + len = vsnprintf(nullptr, 0, fmt, vararg); outBuffer.resize(len + 1); // Print again - len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + va_copy(varargCopy, vararg); + len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, varargCopy); + va_end(varargCopy); } ASSERT(len >= 0); return static_cast(len); } - -std::string FormatString(const char *fmt, va_list vararg) -{ - static std::vector buffer(512); - - size_t len = FormatStringIntoVector(fmt, vararg, buffer); - return std::string(&buffer[0], len); -} - -std::string FormatString(const char *fmt, ...) -{ - va_list vararg; - va_start(vararg, fmt); - std::string result = FormatString(fmt, vararg); - va_end(vararg); - return result; -} diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h index a0178fd414..ad32a2f03a 100644 --- a/src/3rdparty/angle/src/common/angleutils.h +++ b/src/3rdparty/angle/src/common/angleutils.h @@ -23,25 +23,59 @@ namespace angle { +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) +using Microsoft::WRL::ComPtr; +#endif // defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + class NonCopyable { - public: + protected: NonCopyable() = default; ~NonCopyable() = default; - protected: + + private: NonCopyable(const NonCopyable&) = delete; void operator=(const NonCopyable&) = delete; }; extern const uintptr_t DirtyPointer; -} + +} // namespace angle template -inline size_t ArraySize(T(&)[N]) +constexpr inline size_t ArraySize(T (&)[N]) { return N; } +template +class WrappedArray final : angle::NonCopyable +{ + public: + template + constexpr WrappedArray(const T (&data)[N]) : mArray(&data[0]), mSize(N) + { + } + + constexpr WrappedArray() : mArray(nullptr), mSize(0) {} + constexpr WrappedArray(const T *data, size_t size) : mArray(data), mSize(size) {} + + WrappedArray(WrappedArray &&other) : WrappedArray() + { + std::swap(mArray, other.mArray); + std::swap(mSize, other.mSize); + } + + ~WrappedArray() {} + + constexpr const T *get() const { return mArray; } + constexpr size_t size() const { return mSize; } + + private: + const T *mArray; + size_t mSize; +}; + template void SafeRelease(T (&resourceBlock)[N]) { @@ -57,15 +91,15 @@ void SafeRelease(T& resource) if (resource) { resource->Release(); - resource = NULL; + resource = nullptr; } } template -void SafeDelete(T*& resource) +void SafeDelete(T *&resource) { delete resource; - resource = NULL; + resource = nullptr; } template @@ -82,7 +116,7 @@ template void SafeDeleteArray(T*& resource) { delete[] resource; - resource = NULL; + resource = nullptr; } // Provide a less-than function for comparing structs @@ -126,23 +160,11 @@ inline const char* MakeStaticString(const std::string &str) return strings.insert(str).first->c_str(); } -inline std::string ArrayString(unsigned int i) -{ - // We assume UINT_MAX and GL_INVALID_INDEX are equal - // See DynamicHLSL.cpp - if (i == UINT_MAX) - { - return ""; - } +std::string ArrayString(unsigned int i); - std::stringstream strstr; - - strstr << "["; - strstr << i; - strstr << "]"; - - return strstr.str(); -} +// Indices are stored in vectors with the outermost index in the back. In the output of the function +// the indices are reversed. +std::string ArrayIndexString(const std::vector &indices); inline std::string Str(int i) { @@ -156,17 +178,76 @@ size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector std::string FormatString(const char *fmt, va_list vararg); std::string FormatString(const char *fmt, ...); +template +std::string ToString(const T &value) +{ + std::ostringstream o; + o << value; + return o.str(); +} + // snprintf is not defined with MSVC prior to to msvc14 #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf #endif +#define GL_BGRX8_ANGLEX 0x6ABA +#define GL_BGR565_ANGLEX 0x6ABB #define GL_BGRA4_ANGLEX 0x6ABC #define GL_BGR5_A1_ANGLEX 0x6ABD #define GL_INT_64_ANGLEX 0x6ABE -#define GL_STRUCT_ANGLEX 0x6ABF +#define GL_UINT_64_ANGLEX 0x6ABF +#define GL_BGRA8_SRGB_ANGLEX 0x6AC0 // Hidden enum for the NULL D3D device type. #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x6AC0 +// TODO(jmadill): Clean this up at some point. +#define EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX 0x9999 + +#define ANGLE_TRY_CHECKED_MATH(result) \ + if (!result.IsValid()) \ + { \ + return gl::InternalError() << "Integer overflow."; \ + } + +// The below inlining code lifted from V8. +#if defined(__clang__) || (defined(__GNUC__) && defined(__has_attribute)) +#define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(always_inline)) +#define ANGLE_HAS___FORCEINLINE 0 +#elif defined(_MSC_VER) +#define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE 0 +#define ANGLE_HAS___FORCEINLINE 1 +#else +#define ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE 0 +#define ANGLE_HAS___FORCEINLINE 0 +#endif + +#if defined(NDEBUG) && ANGLE_HAS_ATTRIBUTE_ALWAYS_INLINE +#define ANGLE_INLINE inline __attribute__((always_inline)) +#elif defined(NDEBUG) && ANGLE_HAS___FORCEINLINE +#define ANGLE_INLINE __forceinline +#else +#define ANGLE_INLINE inline +#endif + +#ifndef ANGLE_STRINGIFY +#define ANGLE_STRINGIFY(x) #x +#endif + +#ifndef ANGLE_MACRO_STRINGIFY +#define ANGLE_MACRO_STRINGIFY(x) ANGLE_STRINGIFY(x) +#endif + +// Detect support for C++17 [[nodiscard]] +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(name) 0 +#endif // !defined(__has_cpp_attribute) + +#if __has_cpp_attribute(nodiscard) +#define ANGLE_NO_DISCARD [[nodiscard]] +#else +#define ANGLE_NO_DISCARD +#endif // __has_cpp_attribute(nodiscard) + #endif // COMMON_ANGLEUTILS_H_ diff --git a/src/3rdparty/angle/src/common/bitset_utils.h b/src/3rdparty/angle/src/common/bitset_utils.h new file mode 100644 index 0000000000..4166a562a7 --- /dev/null +++ b/src/3rdparty/angle/src/common/bitset_utils.h @@ -0,0 +1,498 @@ +// +// 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. +// +// bitset_utils: +// Bitset-related helper classes, such as a fast iterator to scan 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 BitSetT final +{ + public: + class Reference final + { + public: + ~Reference() {} + Reference &operator=(bool x) + { + mParent->set(mBit, x); + return *this; + } + explicit operator bool() const { return mParent->test(mBit); } + + private: + friend class BitSetT; + + Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {} + + BitSetT *mParent; + std::size_t mBit; + }; + + class Iterator final + { + public: + Iterator(const BitSetT &bits); + Iterator &operator++(); + + bool operator==(const Iterator &other) const; + bool operator!=(const Iterator &other) const; + std::size_t operator*() const; + + private: + std::size_t getNextBit(); + + BitSetT mBitsCopy; + std::size_t mCurrentBit; + }; + + BitSetT(); + BitSetT(BitsT value); + ~BitSetT(); + + BitSetT(const BitSetT &other); + BitSetT &operator=(const BitSetT &other); + + bool operator==(const BitSetT &other) const; + bool operator!=(const BitSetT &other) const; + + constexpr bool operator[](std::size_t pos) const; + Reference operator[](std::size_t pos) { return Reference(this, pos); } + + bool test(std::size_t pos) const; + + bool all() const; + bool any() const; + bool none() const; + std::size_t count() const; + + constexpr std::size_t size() const { return N; } + + BitSetT &operator&=(const BitSetT &other); + BitSetT &operator|=(const BitSetT &other); + BitSetT &operator^=(const BitSetT &other); + BitSetT operator~() const; + + BitSetT operator<<(std::size_t pos) const; + BitSetT &operator<<=(std::size_t pos); + BitSetT operator>>(std::size_t pos) const; + BitSetT &operator>>=(std::size_t pos); + + BitSetT &set(); + BitSetT &set(std::size_t pos, bool value = true); + + BitSetT &reset(); + BitSetT &reset(std::size_t pos); + + BitSetT &flip(); + BitSetT &flip(std::size_t pos); + + unsigned long to_ulong() const { return static_cast(mBits); } + BitsT bits() const { return mBits; } + + Iterator begin() const { return Iterator(*this); } + Iterator end() const { return Iterator(BitSetT()); } + + private: + constexpr static BitsT Bit(std::size_t x) { return (static_cast(1) << x); } + constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; } + + BitsT mBits; +}; + +template +class IterableBitSet : public std::bitset +{ + public: + IterableBitSet() {} + IterableBitSet(const std::bitset &implicitBitSet) : std::bitset(implicitBitSet) {} + + 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 constexpr size_t BitsPerWord = sizeof(uint32_t) * 8; + std::bitset mBits; + unsigned long mCurrentBit; + unsigned long mOffset; + }; + + Iterator begin() const { return Iterator(*this); } + Iterator end() const { return Iterator(std::bitset(0)); } +}; + +template +IterableBitSet::Iterator::Iterator(const std::bitset &bitset) + : mBits(bitset), mCurrentBit(0), mOffset(0) +{ + if (mBits.any()) + { + mCurrentBit = getNextBit(); + } + else + { + mOffset = static_cast(rx::roundUp(N, BitsPerWord)); + } +} + +template +typename IterableBitSet::Iterator &IterableBitSet::Iterator::operator++() +{ + ASSERT(mBits.any()); + mBits.set(mCurrentBit - mOffset, 0); + mCurrentBit = getNextBit(); + return *this; +} + +template +bool IterableBitSet::Iterator::operator==(const Iterator &other) const +{ + return mOffset == other.mOffset && mBits == other.mBits; +} + +template +bool IterableBitSet::Iterator::operator!=(const Iterator &other) const +{ + return !(*this == other); +} + +template +unsigned long IterableBitSet::Iterator::getNextBit() +{ + // TODO(jmadill): Use 64-bit scan when possible. + static constexpr std::bitset wordMask(std::numeric_limits::max()); + + while (mOffset < N) + { + uint32_t wordBits = static_cast((mBits & wordMask).to_ulong()); + if (wordBits != 0) + { + return gl::ScanForward(wordBits) + mOffset; + } + + mBits >>= BitsPerWord; + mOffset += BitsPerWord; + } + return 0; +} + +template +BitSetT::BitSetT() : mBits(0) +{ + static_assert(N > 0, "Bitset type cannot support zero bits."); + static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large."); +} + +template +BitSetT::BitSetT(BitsT value) : mBits(value & Mask(N)) +{ +} + +template +BitSetT::~BitSetT() +{ +} + +template +BitSetT::BitSetT(const BitSetT &other) : mBits(other.mBits) +{ +} + +template +BitSetT &BitSetT::operator=(const BitSetT &other) +{ + mBits = other.mBits; + return *this; +} + +template +bool BitSetT::operator==(const BitSetT &other) const +{ + return mBits == other.mBits; +} + +template +bool BitSetT::operator!=(const BitSetT &other) const +{ + return mBits != other.mBits; +} + +template +constexpr bool BitSetT::operator[](std::size_t pos) const +{ + return test(pos); +} + +template +bool BitSetT::test(std::size_t pos) const +{ + return (mBits & Bit(pos)) != 0; +} + +template +bool BitSetT::all() const +{ + ASSERT(mBits == (mBits & Mask(N))); + return mBits == Mask(N); +} + +template +bool BitSetT::any() const +{ + ASSERT(mBits == (mBits & Mask(N))); + return (mBits != 0); +} + +template +bool BitSetT::none() const +{ + ASSERT(mBits == (mBits & Mask(N))); + return (mBits == 0); +} + +template +std::size_t BitSetT::count() const +{ + return gl::BitCount(mBits); +} + +template +BitSetT &BitSetT::operator&=(const BitSetT &other) +{ + mBits &= other.mBits; + return *this; +} + +template +BitSetT &BitSetT::operator|=(const BitSetT &other) +{ + mBits |= other.mBits; + return *this; +} + +template +BitSetT &BitSetT::operator^=(const BitSetT &other) +{ + mBits = (mBits ^ other.mBits) & Mask(N); + return *this; +} + +template +BitSetT BitSetT::operator~() const +{ + return BitSetT(~mBits & Mask(N)); +} + +template +BitSetT BitSetT::operator<<(std::size_t pos) const +{ + return BitSetT((mBits << pos) & Mask(N)); +} + +template +BitSetT &BitSetT::operator<<=(std::size_t pos) +{ + mBits = (mBits << pos & Mask(N)); + return *this; +} + +template +BitSetT BitSetT::operator>>(std::size_t pos) const +{ + return BitSetT(mBits >> pos); +} + +template +BitSetT &BitSetT::operator>>=(std::size_t pos) +{ + mBits = ((mBits >> pos) & Mask(N)); + return *this; +} + +template +BitSetT &BitSetT::set() +{ + mBits = Mask(N); + return *this; +} + +template +BitSetT &BitSetT::set(std::size_t pos, bool value) +{ + if (value) + { + mBits |= Bit(pos); + } + else + { + reset(pos); + } + return *this; +} + +template +BitSetT &BitSetT::reset() +{ + mBits = 0; + return *this; +} + +template +BitSetT &BitSetT::reset(std::size_t pos) +{ + mBits &= ~Bit(pos); + return *this; +} + +template +BitSetT &BitSetT::flip() +{ + mBits ^= Mask(N); + return *this; +} + +template +BitSetT &BitSetT::flip(std::size_t pos) +{ + mBits ^= Bit(pos); + return *this; +} + +template +BitSetT::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0) +{ + if (bits.any()) + { + mCurrentBit = getNextBit(); + } +} + +template +typename BitSetT::Iterator &BitSetT::Iterator::operator++() +{ + ASSERT(mBitsCopy.any()); + mBitsCopy.reset(mCurrentBit); + mCurrentBit = getNextBit(); + return *this; +} + +template +bool BitSetT::Iterator::operator==(const Iterator &other) const +{ + return mBitsCopy == other.mBitsCopy; +} + +template +bool BitSetT::Iterator::operator!=(const Iterator &other) const +{ + return !(*this == other); +} + +template +std::size_t BitSetT::Iterator::operator*() const +{ + return mCurrentBit; +} + +template +std::size_t BitSetT::Iterator::getNextBit() +{ + if (mBitsCopy.none()) + { + return 0; + } + + return gl::ScanForward(mBitsCopy.mBits); +} + +template +using BitSet32 = BitSetT; + +// ScanForward for 64-bits requires a 64-bit implementation. +#if defined(ANGLE_IS_64_BIT_CPU) +template +using BitSet64 = BitSetT; +#endif // defined(ANGLE_IS_64_BIT_CPU) + +namespace priv +{ + +template +using EnableIfBitsFit = typename std::enable_if::type; + +template +struct GetBitSet +{ + using Type = IterableBitSet; +}; + +// Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit. +#if defined(ANGLE_IS_64_BIT_CPU) +template +struct GetBitSet> +{ + using Type = BitSet64; +}; +#else +template +struct GetBitSet> +{ + using Type = BitSet32; +}; +#endif // defined(ANGLE_IS_64_BIT_CPU) + +} // namespace priv + +template +using BitSet = typename priv::GetBitSet::Type; + +} // angle + +template +inline angle::BitSetT operator&(const angle::BitSetT &lhs, + const angle::BitSetT &rhs) +{ + return angle::BitSetT(lhs.bits() & rhs.bits()); +} + +template +inline angle::BitSetT operator|(const angle::BitSetT &lhs, + const angle::BitSetT &rhs) +{ + return angle::BitSetT(lhs.bits() | rhs.bits()); +} + +template +inline angle::BitSetT operator^(const angle::BitSetT &lhs, + const angle::BitSetT &rhs) +{ + return angle::BitSetT(lhs.bits() ^ rhs.bits()); +} + +#endif // COMMON_BITSETITERATOR_H_ diff --git a/src/3rdparty/angle/src/common/debug.cpp b/src/3rdparty/angle/src/common/debug.cpp index 1fcc062908..b02e80be5f 100644 --- a/src/3rdparty/angle/src/common/debug.cpp +++ b/src/3rdparty/angle/src/common/debug.cpp @@ -7,92 +7,61 @@ // debug.cpp: Debugging utilities. #include "common/debug.h" -#include "common/platform.h" -#include "common/angleutils.h" #include -#include -#include + +#include #include +#include +#include +#include + +#include "common/angleutils.h" +#include "common/Optional.h" namespace gl { namespace { -enum DebugTraceOutputType -{ - DebugTraceOutputTypeNone, - DebugTraceOutputTypeSetMarker, - DebugTraceOutputTypeBeginEvent -}; DebugAnnotator *g_debugAnnotator = nullptr; -void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType outputType, - const char *format, va_list vararg) -{ - if (DebugAnnotationsActive()) - { - static std::vector buffer(512); - size_t len = FormatStringIntoVector(format, vararg, buffer); - std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); - - ASSERT(g_debugAnnotator != nullptr); - switch (outputType) - { - case DebugTraceOutputTypeNone: - break; - case DebugTraceOutputTypeBeginEvent: - g_debugAnnotator->beginEvent(formattedWideMessage.c_str()); - break; - case DebugTraceOutputTypeSetMarker: - g_debugAnnotator->setMarker(formattedWideMessage.c_str()); - break; - } - } +constexpr std::array g_logSeverityNames = { + {"EVENT", "WARN", "ERR"}}; - std::string formattedMessage; - UNUSED_VARIABLE(formattedMessage); +constexpr const char *LogSeverityName(int severity) +{ + return (severity >= 0 && severity < LOG_NUM_SEVERITIES) ? g_logSeverityNames[severity] + : "UNKNOWN"; +} -#if !defined(NDEBUG) && defined(_MSC_VER) - if (messageType == MESSAGE_ERR) - { - if (formattedMessage.empty()) - { - formattedMessage = FormatString(format, vararg); - } - OutputDebugStringA(formattedMessage.c_str()); - } +bool ShouldCreateLogMessage(LogSeverity severity) +{ +#if defined(ANGLE_TRACE_ENABLED) + return true; +#elif defined(ANGLE_ENABLE_ASSERTS) + return severity == LOG_ERR; +#else + return false; #endif +} -#if defined(ANGLE_ENABLE_DEBUG_TRACE) -#if defined(NDEBUG) - if (traceInDebugOnly) - { - return; - } -#endif // NDEBUG - if (formattedMessage.empty()) - { - formattedMessage = FormatString(format, vararg); - } - - static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); - if (file) - { - file.write(formattedMessage.c_str(), formattedMessage.length()); - file.flush(); - } +} // namespace -#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) - OutputDebugStringA(formattedMessage.c_str()); -#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER +namespace priv +{ -#endif // ANGLE_ENABLE_DEBUG_TRACE +bool ShouldCreatePlatformLogMessage(LogSeverity severity) +{ +#if defined(ANGLE_TRACE_ENABLED) + return true; +#else + return severity != LOG_EVENT; +#endif } -} // namespace +} // namespace priv bool DebugAnnotationsActive() { @@ -103,6 +72,11 @@ bool DebugAnnotationsActive() #endif } +bool DebugAnnotationsInitialized() +{ + return g_debugAnnotator != nullptr; +} + void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator) { UninitializeDebugAnnotations(); @@ -115,25 +89,20 @@ void UninitializeDebugAnnotations() g_debugAnnotator = nullptr; } -void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...) -{ - va_list vararg; - va_start(vararg, format); - output(traceInDebugOnly, messageType, DebugTraceOutputTypeSetMarker, format, vararg); - va_end(vararg); -} - -ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) +ScopedPerfEventHelper::ScopedPerfEventHelper(const char *format, ...) { #if !defined(ANGLE_ENABLE_DEBUG_TRACE) if (!DebugAnnotationsActive()) { return; } -#endif // !ANGLE_ENABLE_DEBUG_TRACE +#endif // !ANGLE_ENABLE_DEBUG_TRACE + va_list vararg; va_start(vararg, format); - output(true, MESSAGE_EVENT, DebugTraceOutputTypeBeginEvent, format, vararg); + std::vector buffer(512); + size_t len = FormatStringIntoVector(format, vararg, buffer); + ANGLE_LOG(EVENT) << std::string(&buffer[0], len); va_end(vararg); } @@ -145,4 +114,107 @@ ScopedPerfEventHelper::~ScopedPerfEventHelper() } } +LogMessage::LogMessage(const char *function, int line, LogSeverity severity) + : mFunction(function), mLine(line), mSeverity(severity) +{ + // EVENT() does not require additional function(line) info. + if (mSeverity != LOG_EVENT) + { + mStream << mFunction << "(" << mLine << "): "; + } +} + +LogMessage::~LogMessage() +{ + if (DebugAnnotationsInitialized() && (mSeverity == LOG_ERR || mSeverity == LOG_WARN)) + { + g_debugAnnotator->logMessage(*this); + } + else + { + Trace(getSeverity(), getMessage().c_str()); + } +} + +void Trace(LogSeverity severity, const char *message) +{ + if (!ShouldCreateLogMessage(severity)) + { + return; + } + + std::string str(message); + + if (DebugAnnotationsActive()) + { + std::wstring formattedWideMessage(str.begin(), str.end()); + + switch (severity) + { + case LOG_EVENT: + g_debugAnnotator->beginEvent(formattedWideMessage.c_str()); + break; + default: + g_debugAnnotator->setMarker(formattedWideMessage.c_str()); + break; + } + } + + if (severity == LOG_ERR) + { + // Note: we use fprintf because includes static initializers. + fprintf(stderr, "%s: %s\n", LogSeverityName(severity), str.c_str()); + } + +#if defined(ANGLE_PLATFORM_WINDOWS) && \ + (defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) || !defined(NDEBUG)) +#if !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) + if (severity == LOG_ERR) +#endif // !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) + { + OutputDebugStringA(str.c_str()); + } +#endif + +#if defined(ANGLE_ENABLE_DEBUG_TRACE) +#if defined(NDEBUG) + if (severity == LOG_EVENT || severity == LOG_WARN) + { + return; + } +#endif // defined(NDEBUG) + static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); + if (file) + { + file << LogSeverityName(severity) << ": " << str << std::endl; + file.flush(); + } +#endif // defined(ANGLE_ENABLE_DEBUG_TRACE) } + +LogSeverity LogMessage::getSeverity() const +{ + return mSeverity; +} + +std::string LogMessage::getMessage() const +{ + return mStream.str(); +} + +#if defined(ANGLE_PLATFORM_WINDOWS) +std::ostream &operator<<(std::ostream &os, const FmtHR &fmt) +{ + os << "HRESULT: "; + return FmtHexInt(os, fmt.mHR); +} + +std::ostream &operator<<(std::ostream &os, const FmtErr &fmt) +{ + os << "error: "; + return FmtHexInt(os, fmt.mErr); +} + +#endif // defined(ANGLE_PLATFORM_WINDOWS) + +} // namespace gl diff --git a/src/3rdparty/angle/src/common/debug.h b/src/3rdparty/angle/src/common/debug.h index 64cfef4cd9..290a4e8bb7 100644 --- a/src/3rdparty/angle/src/common/debug.h +++ b/src/3rdparty/angle/src/common/debug.h @@ -11,6 +11,10 @@ #include #include + +#include +#include +#include #include #include "common/angleutils.h" @@ -22,17 +26,6 @@ namespace gl { -enum MessageType -{ - MESSAGE_TRACE, - MESSAGE_FIXME, - MESSAGE_ERR, - MESSAGE_EVENT, -}; - -// Outputs text to the debugging log, or the debugging window -void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...); - // Pairs a D3D begin event with an end event. class ScopedPerfEventHelper : angle::NonCopyable { @@ -41,50 +34,177 @@ class ScopedPerfEventHelper : angle::NonCopyable ~ScopedPerfEventHelper(); }; +using LogSeverity = int; +// Note: the log severities are used to index into the array of names, +// see g_logSeverityNames. +constexpr LogSeverity LOG_EVENT = 0; +constexpr LogSeverity LOG_WARN = 1; +constexpr LogSeverity LOG_ERR = 2; +constexpr LogSeverity LOG_NUM_SEVERITIES = 3; + +void Trace(LogSeverity severity, const char *message); + +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the ERR() and WARN() macros. +class LogMessage : angle::NonCopyable +{ + public: + // Used for ANGLE_LOG(severity). + LogMessage(const char *function, int line, LogSeverity severity); + ~LogMessage(); + std::ostream &stream() { return mStream; } + + LogSeverity getSeverity() const; + std::string getMessage() const; + + private: + const char *mFunction; + const int mLine; + const LogSeverity mSeverity; + + std::ostringstream mStream; +}; + // Wraps the D3D9/D3D11 debug annotation functions. +// Also handles redirecting logging destination. class DebugAnnotator : angle::NonCopyable { public: - DebugAnnotator() { }; + DebugAnnotator(){}; virtual ~DebugAnnotator() { }; virtual void beginEvent(const wchar_t *eventName) = 0; virtual void endEvent() = 0; virtual void setMarker(const wchar_t *markerName) = 0; virtual bool getStatus() = 0; + // Log Message Handler that gets passed every log message, + // when debug annotations are initialized, + // replacing default handling by LogMessage. + virtual void logMessage(const LogMessage &msg) const = 0; }; void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator); void UninitializeDebugAnnotations(); bool DebugAnnotationsActive(); +bool DebugAnnotationsInitialized(); + +namespace priv +{ +// This class is used to explicitly ignore values in the conditional logging macros. This avoids +// compiler warnings like "value computed is not used" and "statement has no effect". +class LogMessageVoidify +{ + public: + LogMessageVoidify() {} + // This has to be an operator with a precedence lower than << but higher than ?: + void operator&(std::ostream &) {} +}; + +// Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments. +bool ShouldCreatePlatformLogMessage(LogSeverity severity); + +template +std::ostream &FmtHex(std::ostream &os, T value) +{ + os << "0x"; + + std::ios_base::fmtflags oldFlags = os.flags(); + std::streamsize oldWidth = os.width(); + std::ostream::char_type oldFill = os.fill(); + + os << std::hex << std::uppercase << std::setw(N) << std::setfill('0') << value; + + os.flags(oldFlags); + os.width(oldWidth); + os.fill(oldFill); + + return os; +} +} // namespace priv + +#if defined(ANGLE_PLATFORM_WINDOWS) +class FmtHR +{ + public: + explicit FmtHR(HRESULT hresult) : mHR(hresult) {} + private: + HRESULT mHR; + friend std::ostream &operator<<(std::ostream &os, const FmtHR &fmt); +}; + +class FmtErr +{ + public: + explicit FmtErr(DWORD err) : mErr(err) {} + + private: + DWORD mErr; + friend std::ostream &operator<<(std::ostream &os, const FmtErr &fmt); +}; +#endif // defined(ANGLE_PLATFORM_WINDOWS) + +template +std::ostream &FmtHexShort(std::ostream &os, T value) +{ + return priv::FmtHex<4>(os, value); +} +template +std::ostream &FmtHexInt(std::ostream &os, T value) +{ + return priv::FmtHex<8>(os, value); } +// A few definitions of macros that don't generate much code. These are used +// by ANGLE_LOG(). Since these are used all over our code, it's +// better to have compact code for these operations. +#define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) \ + ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__) +#define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \ + ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__) +#define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \ + ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__) + +#define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage) +#define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage) +#define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage) + +#define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##severity)) + +// Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold. +// Condition is evaluated once and only once. +#define ANGLE_LAZY_STREAM(stream, condition) \ + !(condition) ? static_cast(0) : ::gl::priv::LogMessageVoidify() & (stream) + +// We use the preprocessor's merging operator, "##", so that, e.g., +// ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define ANGLE_LOG_STREAM(severity) COMPACT_ANGLE_LOG_##severity.stream() + +#define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(severity)) + +} // namespace gl + #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #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__) -#else -#define TRACE(message, ...) (void(0)) -#endif - -// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing. -#if defined(ANGLE_TRACE_ENABLED) -#define FIXME(message, ...) gl::trace(false, gl::MESSAGE_FIXME, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) -#else -#define FIXME(message, ...) (void(0)) +#if !defined(NDEBUG) || defined(ANGLE_ENABLE_RELEASE_ASSERTS) +#define ANGLE_ENABLE_ASSERTS #endif -// A macro to output a function call and its arguments to the debugging log, in case of error. -#if defined(ANGLE_TRACE_ENABLED) -#define ERR(message, ...) gl::trace(false, gl::MESSAGE_ERR, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) -#else -#define ERR(message, ...) (void(0)) -#endif +#define WARN() ANGLE_LOG(WARN) +#define ERR() ANGLE_LOG(ERR) // A macro to log a performance event around a scope. #if defined(ANGLE_TRACE_ENABLED) @@ -97,54 +217,70 @@ bool DebugAnnotationsActive(); #define EVENT(message, ...) (void(0)) #endif -#if defined(ANGLE_TRACE_ENABLED) -#undef ANGLE_TRACE_ENABLED +#if defined(COMPILER_GCC) || defined(__clang__) +#define ANGLE_CRASH() __builtin_trap() +#else +#define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)) #endif -// A macro asserting a condition and outputting failures to the debug log #if !defined(NDEBUG) -#define ASSERT(expression) { \ - if(!(expression)) \ - ERR("\t! Assert failed in %s(%d): %s\n", __FUNCTION__, __LINE__, #expression); \ - assert(expression); \ - } ANGLE_EMPTY_STATEMENT -#define UNUSED_ASSERTION_VARIABLE(variable) +#define ANGLE_ASSERT_IMPL(expression) assert(expression) #else -#define ASSERT(expression) (void(0)) -#define UNUSED_ASSERTION_VARIABLE(variable) ((void)variable) -#endif +// TODO(jmadill): Detect if debugger is attached and break. +#define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH() +#endif // !defined(NDEBUG) + +// A macro asserting a condition and outputting failures to the debug log +#if defined(ANGLE_ENABLE_ASSERTS) +#define ASSERT(expression) \ + (expression ? static_cast(0) : ((ERR() << "\t! Assert failed in " << __FUNCTION__ << "(" \ + << __LINE__ << "): " << #expression), \ + ANGLE_ASSERT_IMPL(expression))) +#else +// These are just dummy values. +#define COMPACT_ANGLE_LOG_EX_ASSERT(ClassName, ...) \ + COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ##__VA_ARGS__) +#define COMPACT_ANGLE_LOG_ASSERT COMPACT_ANGLE_LOG_EVENT +namespace gl +{ +constexpr LogSeverity LOG_ASSERT = LOG_EVENT; +} // namespace gl + +#define ASSERT(condition) \ + ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(ASSERT), false ? !(condition) : false) \ + << "Check failed: " #condition ". " +#endif // defined(ANGLE_ENABLE_ASSERTS) #define UNUSED_VARIABLE(variable) ((void)variable) // A macro to indicate unimplemented functionality - -#if defined (ANGLE_TEST_CONFIG) +#ifndef NOASSERT_UNIMPLEMENTED #define NOASSERT_UNIMPLEMENTED 1 #endif -// Define NOASSERT_UNIMPLEMENTED to non zero to skip the assert fail in the unimplemented checks -// This will allow us to test with some automated test suites (eg dEQP) without crashing -#ifndef NOASSERT_UNIMPLEMENTED -#define NOASSERT_UNIMPLEMENTED 0 -#endif +#if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS) +#define UNIMPLEMENTED() \ + { \ + ERR() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \ + << ")"; \ + ASSERT(NOASSERT_UNIMPLEMENTED); \ + } \ + ANGLE_EMPTY_STATEMENT -#if !defined(NDEBUG) -#define UNIMPLEMENTED() { \ - FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \ - assert(NOASSERT_UNIMPLEMENTED); \ - } ANGLE_EMPTY_STATEMENT +// A macro for code which is not expected to be reached under valid assumptions +#define UNREACHABLE() \ + ((ERR() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \ + << ")"), \ + ASSERT(false)) #else - #define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__) -#endif +#define UNIMPLEMENTED() \ + { \ + ASSERT(NOASSERT_UNIMPLEMENTED); \ + } \ + ANGLE_EMPTY_STATEMENT // A macro for code which is not expected to be reached under valid assumptions -#if !defined(NDEBUG) -#define UNREACHABLE() { \ - ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ - assert(false); \ - } ANGLE_EMPTY_STATEMENT -#else - #define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__) -#endif +#define UNREACHABLE() ASSERT(false) +#endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS) #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 c9eb5e3073..6dc8458acc 100644 --- a/src/3rdparty/angle/src/common/event_tracer.cpp +++ b/src/3rdparty/angle/src/common/event_tracer.cpp @@ -11,10 +11,11 @@ namespace angle const unsigned char *GetTraceCategoryEnabledFlag(const char *name) { - angle::Platform *platform = ANGLEPlatformCurrent(); + auto *platform = ANGLEPlatformCurrent(); ASSERT(platform); - const unsigned char *categoryEnabledFlag = platform->getTraceCategoryEnabledFlag(name); + const unsigned char *categoryEnabledFlag = + platform->getTraceCategoryEnabledFlag(platform, name); if (categoryEnabledFlag != nullptr) { return categoryEnabledFlag; @@ -24,33 +25,31 @@ const unsigned char *GetTraceCategoryEnabledFlag(const char *name) return &disabled; } -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) +angle::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) { - angle::Platform *platform = ANGLEPlatformCurrent(); + auto *platform = ANGLEPlatformCurrent(); ASSERT(platform); - double timestamp = platform->monotonicallyIncreasingTime(); + double timestamp = platform->monotonicallyIncreasingTime(platform); if (timestamp != 0) { - angle::Platform::TraceEventHandle handle = - platform->addTraceEvent(phase, - categoryGroupEnabled, - name, - id, - timestamp, - numArgs, - argNames, - argTypes, - argValues, - flags); + angle::TraceEventHandle handle = + platform->addTraceEvent(platform, phase, categoryGroupEnabled, name, id, timestamp, + numArgs, argNames, argTypes, argValues, flags); ASSERT(handle != 0); return handle; } - return static_cast(0); + return static_cast(0); } } // namespace angle diff --git a/src/3rdparty/angle/src/common/event_tracer.h b/src/3rdparty/angle/src/common/event_tracer.h index ed70f249d2..9b30c750c1 100644 --- a/src/3rdparty/angle/src/common/event_tracer.h +++ b/src/3rdparty/angle/src/common/event_tracer.h @@ -12,11 +12,15 @@ namespace angle { 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); - +angle::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); } #endif // COMMON_EVENT_TRACER_H_ diff --git a/src/3rdparty/angle/src/common/mathutil.cpp b/src/3rdparty/angle/src/common/mathutil.cpp index 927b6ebebe..5db997c664 100644 --- a/src/3rdparty/angle/src/common/mathutil.cpp +++ b/src/3rdparty/angle/src/common/mathutil.cpp @@ -14,6 +14,9 @@ namespace gl { +namespace +{ + struct RGB9E5Data { unsigned int R : 9; @@ -23,17 +26,20 @@ struct RGB9E5Data }; // B is the exponent bias (15) -static const int g_sharedexp_bias = 15; +constexpr int g_sharedexp_bias = 15; // N is the number of mantissa bits per component (9) -static const int g_sharedexp_mantissabits = 9; +constexpr int g_sharedexp_mantissabits = 9; // Emax is the maximum allowed biased exponent value (31) -static const int g_sharedexp_maxexponent = 31; +constexpr int g_sharedexp_maxexponent = 31; -static const float g_sharedexp_max = ((pow(2.0f, g_sharedexp_mantissabits) - 1) / - pow(2.0f, g_sharedexp_mantissabits)) * - pow(2.0f, g_sharedexp_maxexponent - g_sharedexp_bias); +constexpr float g_sharedexp_max = + ((static_cast(1 << g_sharedexp_mantissabits) - 1) / + static_cast(1 << g_sharedexp_mantissabits)) * + static_cast(1 << (g_sharedexp_maxexponent - g_sharedexp_bias)); + +} // anonymous namespace unsigned int convertRGBFloatsTo999E5(float red, float green, float blue) { @@ -64,4 +70,4 @@ void convert999E5toRGBFloats(unsigned int input, float *red, float *green, float *blue = inputData->B * pow(2.0f, (int)inputData->E - g_sharedexp_bias - g_sharedexp_mantissabits); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h index 3de62aef10..372e432066 100644 --- a/src/3rdparty/angle/src/common/mathutil.h +++ b/src/3rdparty/angle/src/common/mathutil.h @@ -9,9 +9,6 @@ #ifndef COMMON_MATHUTIL_H_ #define COMMON_MATHUTIL_H_ -#include "common/debug.h" -#include "common/platform.h" - #include #include #include @@ -19,25 +16,27 @@ #include #include +#include + +#include "common/debug.h" +#include "common/platform.h" + +namespace angle +{ +using base::CheckedNumeric; +using base::IsValueInRangeForNumericType; +} + namespace gl { const unsigned int Float32One = 0x3F800000; const unsigned short Float16One = 0x3C00; -struct Vector4 -{ - Vector4() {} - Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} - - float x; - float y; - float z; - float w; -}; - -inline bool isPow2(int x) +template +inline bool isPow2(T x) { + static_assert(std::is_integral::value, "isPow2 must be called on an integer type."); return (x & (x - 1)) == 0 && (x != 0); } @@ -61,37 +60,52 @@ inline unsigned int ceilPow2(unsigned int x) return x; } -inline int clampToInt(unsigned int x) -{ - return static_cast(std::min(x, static_cast(std::numeric_limits::max()))); -} - template inline DestT clampCast(SrcT value) { - 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) + // For floating-point types with denormalization, min returns the minimum positive normalized + // value. To find the value that has no values less than it, use numeric_limits::lowest. + constexpr const long double destLo = + static_cast(std::numeric_limits::lowest()); + constexpr const long double destHi = + static_cast(std::numeric_limits::max()); + constexpr const long double srcLo = + static_cast(std::numeric_limits::lowest()); + constexpr long double srcHi = static_cast(std::numeric_limits::max()); + + if (destHi < srcHi) { - return destHi; + DestT destMax = std::numeric_limits::max(); + if (value >= static_cast(destMax)) + { + return destMax; + } } - else + + if (destLo > srcLo) { - return static_cast(value); + DestT destLow = std::numeric_limits::lowest(); + if (value <= static_cast(destLow)) + { + return destLow; + } } + + return static_cast(value); +} + +// Specialize clampCast for bool->int conversion to avoid MSVS 2015 performance warning when the max +// value is casted to the source type. +template <> +inline unsigned int clampCast(bool value) +{ + return static_cast(value); +} + +template <> +inline int clampCast(bool value) +{ + return static_cast(value); } template @@ -127,7 +141,7 @@ inline unsigned int unorm(float x) inline bool supportsSSE2() { -#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) +#if defined(ANGLE_USE_SSE) static bool checked = false; static bool supports = false; @@ -136,21 +150,22 @@ inline bool supportsSSE2() return supports; } - int info[4]; - __cpuid(info, 0); - - if (info[0] >= 1) +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) { - __cpuid(info, 1); + int info[4]; + __cpuid(info, 0); - supports = (info[3] >> 26) & 1; - } + if (info[0] >= 1) + { + __cpuid(info, 1); + supports = (info[3] >> 26) & 1; + } + } +#endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) checked = true; - return supports; -#else - UNIMPLEMENTED(); +#else // defined(ANGLE_USE_SSE) return false; #endif } @@ -467,6 +482,43 @@ inline T shiftData(T input) return (input & mask) << inputBitStart; } +inline unsigned int CountLeadingZeros(uint32_t x) +{ + // Use binary search to find the amount of leading zeros. + unsigned int zeros = 32u; + uint32_t y; + + y = x >> 16u; + if (y != 0) + { + zeros = zeros - 16u; + x = y; + } + y = x >> 8u; + if (y != 0) + { + zeros = zeros - 8u; + x = y; + } + y = x >> 4u; + if (y != 0) + { + zeros = zeros - 4u; + x = y; + } + y = x >> 2u; + if (y != 0) + { + zeros = zeros - 2u; + x = y; + } + y = x >> 1u; + if (y != 0) + { + return zeros - 2u; + } + return zeros - x; +} inline unsigned char average(unsigned char a, unsigned char b) { @@ -520,38 +572,65 @@ inline unsigned int averageFloat10(unsigned int a, unsigned int b) } template -struct Range +class Range { + public: Range() {} - Range(T lo, T hi) : start(lo), end(hi) { ASSERT(lo <= hi); } - - T start; - T end; + Range(T lo, T hi) : mLow(lo), mHigh(hi) {} - T length() const { return end - start; } + T length() const { return (empty() ? 0 : (mHigh - mLow)); } bool intersects(Range other) { - if (start <= other.start) + if (mLow <= other.mLow) { - return other.start < end; + return other.mLow < mHigh; } else { - return start < other.end; + return mLow < other.mHigh; } } + // Assumes that end is non-inclusive.. for example, extending to 5 will make "end" 6. void extend(T value) { - start = value > start ? value : start; - end = value < end ? value : end; + mLow = value < mLow ? value : mLow; + mHigh = value >= mHigh ? (value + 1) : mHigh; } - bool empty() const + bool empty() const { return mHigh <= mLow; } + + bool contains(T value) const { return value >= mLow && value < mHigh; } + + class Iterator final { - return end <= start; - } + public: + Iterator(T value) : mCurrent(value) {} + + Iterator &operator++() + { + mCurrent++; + return *this; + } + bool operator==(const Iterator &other) const { return mCurrent == other.mCurrent; } + bool operator!=(const Iterator &other) const { return mCurrent != other.mCurrent; } + T operator*() const { return mCurrent; } + + private: + T mCurrent; + }; + + Iterator begin() const { return Iterator(mLow); } + + Iterator end() const { return Iterator(mHigh); } + + T low() const { return mLow; } + T high() const { return mHigh; } + + private: + T mLow; + T mHigh; }; typedef Range RangeI; @@ -577,6 +656,22 @@ struct IndexRange size_t vertexIndexCount; }; +// Combine a floating-point value representing a mantissa (x) and an integer exponent (exp) into a +// floating-point value. As in GLSL ldexp() built-in. +inline float Ldexp(float x, int exp) +{ + if (exp > 128) + { + return std::numeric_limits::infinity(); + } + if (exp < -126) + { + return 0.0f; + } + double result = static_cast(x) * std::pow(2.0, static_cast(exp)); + return static_cast(result); +} + // 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; @@ -632,6 +727,86 @@ inline void unpackUnorm2x16(uint32_t u, float *f1, float *f2) *f2 = static_cast(mostSignificantBits) / 65535.0f; } +// Helper functions intended to be used only here. +namespace priv +{ + +inline uint8_t ToPackedUnorm8(float f) +{ + return static_cast(roundf(clamp(f, 0.0f, 1.0f) * 255.0f)); +} + +inline int8_t ToPackedSnorm8(float f) +{ + return static_cast(roundf(clamp(f, -1.0f, 1.0f) * 127.0f)); +} + +} // namespace priv + +// Packs 4 normalized unsigned floating-point values to a single 32-bit unsigned integer. Works +// similarly to packUnorm2x16. The floats are clamped to the range 0.0 to 1.0, and written to the +// unsigned integer starting from the least significant bits. +inline uint32_t PackUnorm4x8(float f1, float f2, float f3, float f4) +{ + uint8_t bits[4]; + bits[0] = priv::ToPackedUnorm8(f1); + bits[1] = priv::ToPackedUnorm8(f2); + bits[2] = priv::ToPackedUnorm8(f3); + bits[3] = priv::ToPackedUnorm8(f4); + uint32_t result = 0u; + for (int i = 0; i < 4; ++i) + { + int shift = i * 8; + result |= (static_cast(bits[i]) << shift); + } + return result; +} + +// Unpacks 4 normalized unsigned floating-point values from a single 32-bit unsigned integer into f. +// Works similarly to unpackUnorm2x16. The floats are unpacked starting from the least significant +// bits. +inline void UnpackUnorm4x8(uint32_t u, float *f) +{ + for (int i = 0; i < 4; ++i) + { + int shift = i * 8; + uint8_t bits = static_cast((u >> shift) & 0xFF); + f[i] = static_cast(bits) / 255.0f; + } +} + +// Packs 4 normalized signed floating-point values to a single 32-bit unsigned integer. The floats +// are clamped to the range -1.0 to 1.0, and written to the unsigned integer starting from the least +// significant bits. +inline uint32_t PackSnorm4x8(float f1, float f2, float f3, float f4) +{ + int8_t bits[4]; + bits[0] = priv::ToPackedSnorm8(f1); + bits[1] = priv::ToPackedSnorm8(f2); + bits[2] = priv::ToPackedSnorm8(f3); + bits[3] = priv::ToPackedSnorm8(f4); + uint32_t result = 0u; + for (int i = 0; i < 4; ++i) + { + int shift = i * 8; + result |= ((static_cast(bits[i]) & 0xFF) << shift); + } + return result; +} + +// Unpacks 4 normalized signed floating-point values from a single 32-bit unsigned integer into f. +// Works similarly to unpackSnorm2x16. The floats are unpacked starting from the least significant +// bits, and clamped to the range -1.0 to 1.0. +inline void UnpackSnorm4x8(uint32_t u, float *f) +{ + for (int i = 0; i < 4; ++i) + { + int shift = i * 8; + int8_t bits = static_cast((u >> shift) & 0xFF); + f[i] = clamp(static_cast(bits) / 127.0f, -1.0f, 1.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. @@ -658,6 +833,179 @@ inline void unpackHalf2x16(uint32_t u, float *f1, float *f2) *f2 = float16ToFloat32(mostSignificantBits); } +inline uint8_t sRGBToLinear(uint8_t srgbValue) +{ + float value = srgbValue / 255.0f; + if (value <= 0.04045f) + { + value = value / 12.92f; + } + else + { + value = std::pow((value + 0.055f) / 1.055f, 2.4f); + } + return static_cast(clamp(value * 255.0f + 0.5f, 0.0f, 255.0f)); +} + +inline uint8_t linearToSRGB(uint8_t linearValue) +{ + float value = linearValue / 255.0f; + if (value <= 0.0f) + { + value = 0.0f; + } + else if (value < 0.0031308f) + { + value = value * 12.92f; + } + else if (value < 1.0f) + { + value = std::pow(value, 0.41666f) * 1.055f - 0.055f; + } + else + { + value = 1.0f; + } + return static_cast(clamp(value * 255.0f + 0.5f, 0.0f, 255.0f)); +} + +// Reverse the order of the bits. +inline uint32_t BitfieldReverse(uint32_t value) +{ + // TODO(oetuaho@nvidia.com): Optimize this if needed. There don't seem to be compiler intrinsics + // for this, and right now it's not used in performance-critical paths. + uint32_t result = 0u; + for (size_t j = 0u; j < 32u; ++j) + { + result |= (((value >> j) & 1u) << (31u - j)); + } + return result; +} + +// Count the 1 bits. +#if defined(ANGLE_PLATFORM_WINDOWS) +#if defined(_M_ARM) +inline int BitCount(uint32_t bits) +{ + bits = bits - ((bits >> 1) & 0x55555555); + bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); + return (((bits + (bits >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; +} +#else // _M_ARM +inline int BitCount(uint32_t bits) +{ + return static_cast(__popcnt(bits)); +} +#if defined(ANGLE_IS_64_BIT_CPU) +inline int BitCount(uint64_t bits) +{ + return static_cast(__popcnt64(bits)); +} +#endif // !_M_ARM +#endif // defined(ANGLE_IS_64_BIT_CPU) +#endif // defined(ANGLE_PLATFORM_WINDOWS) + +#if defined(ANGLE_PLATFORM_POSIX) +inline int BitCount(uint32_t bits) +{ + return __builtin_popcount(bits); +} + +#if defined(ANGLE_IS_64_BIT_CPU) +inline int BitCount(uint64_t bits) +{ + return __builtin_popcountll(bits); +} +#endif // defined(ANGLE_IS_64_BIT_CPU) +#endif // defined(ANGLE_PLATFORM_POSIX) + +#if defined(ANGLE_PLATFORM_WINDOWS) +// Return the index of the least significant bit set. Indexing is such that bit 0 is the least +// significant bit. Implemented for different bit widths on different platforms. +inline unsigned long ScanForward(uint32_t bits) +{ + ASSERT(bits != 0u); + unsigned long firstBitIndex = 0ul; + unsigned char ret = _BitScanForward(&firstBitIndex, bits); + ASSERT(ret != 0u); + return firstBitIndex; +} + +#if defined(ANGLE_IS_64_BIT_CPU) +inline unsigned long ScanForward(uint64_t bits) +{ + ASSERT(bits != 0u); + unsigned long firstBitIndex = 0ul; + unsigned char ret = _BitScanForward64(&firstBitIndex, bits); + ASSERT(ret != 0u); + return firstBitIndex; +} +#endif // defined(ANGLE_IS_64_BIT_CPU) +#endif // defined(ANGLE_PLATFORM_WINDOWS) + +#if defined(ANGLE_PLATFORM_POSIX) +inline unsigned long ScanForward(uint32_t bits) +{ + ASSERT(bits != 0u); + return static_cast(__builtin_ctz(bits)); +} + +#if defined(ANGLE_IS_64_BIT_CPU) +inline unsigned long ScanForward(uint64_t bits) +{ + ASSERT(bits != 0u); + return static_cast(__builtin_ctzll(bits)); +} +#endif // defined(ANGLE_IS_64_BIT_CPU) +#endif // defined(ANGLE_PLATFORM_POSIX) + +// Return the index of the most significant bit set. Indexing is such that bit 0 is the least +// significant bit. +inline unsigned long ScanReverse(unsigned long bits) +{ + ASSERT(bits != 0u); +#if defined(ANGLE_PLATFORM_WINDOWS) + unsigned long lastBitIndex = 0ul; + unsigned char ret = _BitScanReverse(&lastBitIndex, bits); + ASSERT(ret != 0u); + return lastBitIndex; +#elif defined(ANGLE_PLATFORM_POSIX) + return static_cast(sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(bits)); +#else +#error Please implement bit-scan-reverse for your platform! +#endif +} + +// Returns -1 on 0, otherwise the index of the least significant 1 bit as in GLSL. +template +int FindLSB(T bits) +{ + static_assert(std::is_integral::value, "must be integral type."); + if (bits == 0u) + { + return -1; + } + else + { + return static_cast(ScanForward(bits)); + } +} + +// Returns -1 on 0, otherwise the index of the most significant 1 bit as in GLSL. +template +int FindMSB(T bits) +{ + static_assert(std::is_integral::value, "must be integral type."); + if (bits == 0u) + { + return -1; + } + else + { + return static_cast(ScanReverse(bits)); + } +} + // 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) @@ -676,41 +1024,98 @@ inline bool isInf(float f) return ((bitCast(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast(f) & 0x7fffffu); } +namespace priv +{ +template +struct iSquareRoot +{ + static constexpr unsigned int solve() + { + return (R * R > N) + ? 0 + : ((R * R == N) ? R : static_cast(iSquareRoot::value)); + } + enum Result + { + value = iSquareRoot::solve() + }; +}; + +template +struct iSquareRoot +{ + enum result + { + value = N + }; +}; + +} // namespace priv + +template +constexpr unsigned int iSquareRoot() +{ + return priv::iSquareRoot::value; } -namespace rx +// Sum, difference and multiplication operations for signed ints that wrap on 32-bit overflow. +// +// Unsigned types are defined to do arithmetic modulo 2^n in C++. For signed types, overflow +// behavior is undefined. + +template +inline T WrappingSum(T lhs, T rhs) { + uint32_t lhsUnsigned = static_cast(lhs); + uint32_t rhsUnsigned = static_cast(rhs); + return static_cast(lhsUnsigned + rhsUnsigned); +} template -T roundUp(const T value, const T alignment) +inline T WrappingDiff(T lhs, T rhs) { - return value + alignment - 1 - (value - 1) % alignment; + uint32_t lhsUnsigned = static_cast(lhs); + uint32_t rhsUnsigned = static_cast(rhs); + return static_cast(lhsUnsigned - rhsUnsigned); } -inline unsigned int UnsignedCeilDivide(unsigned int value, unsigned int divisor) +inline int32_t WrappingMul(int32_t lhs, int32_t rhs) { - unsigned int divided = value / divisor; - return (divided + ((value % divisor == 0) ? 0 : 1)); + int64_t lhsWide = static_cast(lhs); + int64_t rhsWide = static_cast(rhs); + // The multiplication is guaranteed not to overflow. + int64_t resultWide = lhsWide * rhsWide; + // Implement the desired wrapping behavior by masking out the high-order 32 bits. + resultWide = resultWide & 0xffffffffll; + // Casting to a narrower signed type is fine since the casted value is representable in the + // narrower type. + return static_cast(resultWide); } -template -inline bool IsUnsignedAdditionSafe(T lhs, T rhs) +} // namespace gl + +namespace rx { - static_assert(!std::numeric_limits::is_signed, "T must be unsigned."); - return (rhs <= std::numeric_limits::max() - lhs); + +template +T roundUp(const T value, const T alignment) +{ + auto temp = value + alignment - static_cast(1); + return temp - temp % alignment; } -template -inline bool IsUnsignedMultiplicationSafe(T lhs, T rhs) +template +angle::CheckedNumeric CheckedRoundUp(const T value, const T alignment) { - static_assert(!std::numeric_limits::is_signed, "T must be unsigned."); - return (lhs == T(0) || rhs == T(0) || (rhs <= std::numeric_limits::max() / lhs)); + angle::CheckedNumeric checkedValue(value); + angle::CheckedNumeric checkedAlignment(alignment); + return roundUp(checkedValue, checkedAlignment); } -template -inline bool IsIntegerCastSafe(BigIntT bigValue) +inline unsigned int UnsignedCeilDivide(unsigned int value, unsigned int divisor) { - return (static_cast(static_cast(bigValue)) == bigValue); + unsigned int divided = value / divisor; + return (divided + ((value % divisor == 0) ? 0 : 1)); } #if defined(_MSC_VER) @@ -730,8 +1135,8 @@ 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) +#define ANGLE_ROTL(x, y) ::rx::RotL(x, y) +#define ANGLE_ROTR16(x, y) ::rx::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 index 6f3187c3e8..aa3f89536e 100644 --- a/src/3rdparty/angle/src/common/matrix_utils.h +++ b/src/3rdparty/angle/src/common/matrix_utils.h @@ -16,6 +16,7 @@ #include #include "common/debug.h" +#include "common/mathutil.h" namespace angle { @@ -337,6 +338,42 @@ class Matrix return result; } + void setToIdentity() + { + ASSERT(rows() == columns()); + + const auto one = T(1); + const auto zero = T(0); + + for (auto &e : mElements) + e = zero; + + for (unsigned int i = 0; i < rows(); ++i) + { + const auto pos = i * columns() + (i % columns()); + mElements[pos] = one; + } + } + + template + static void setToIdentity(T(&matrix)[Size]) + { + static_assert(gl::iSquareRoot() != 0, "Matrix is not square."); + + const auto cols = gl::iSquareRoot(); + const auto one = T(1); + const auto zero = T(0); + + for (auto &e : matrix) + e = zero; + + for (unsigned int i = 0; i < cols; ++i) + { + const auto pos = i * cols + (i % cols); + matrix[pos] = one; + } + } + private: std::vector mElements; unsigned int mRows; diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h index be4cb94987..47cd57b999 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h @@ -27,7 +27,9 @@ defined(__sun) || \ defined(__GLIBC__) || \ defined(__GNU__) || \ - defined(__QNX__) + defined(__QNX__) || \ + defined(__Fuchsia__) || \ + defined(__HAIKU__) # define ANGLE_PLATFORM_POSIX 1 #else # error Unsupported platform. @@ -57,28 +59,22 @@ # endif # if defined(ANGLE_ENABLE_D3D11) -# include -# include -# include -# if defined(__MINGW32__) && !defined(__d3d11sdklayers_h__) -# define ANGLE_MINGW32_COMPAT -# endif -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# define ANGLE_ENABLE_D3D11_1 -# endif -# if defined(ANGLE_ENABLE_D3D11_1) -# include -# include -# endif -# include +#include +#include +#include +#include +#include +#include # endif +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) +#include +#endif + # if defined(ANGLE_ENABLE_WINDOWS_STORE) # include # if defined(_DEBUG) -# if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP # include -# endif # include # endif # endif @@ -87,8 +83,21 @@ # undef far #endif -#if !defined(_M_ARM) && !defined(ANGLE_PLATFORM_ANDROID) -# define ANGLE_USE_SSE +#if defined(_MSC_VER) && !defined(_M_ARM) +#include +#define ANGLE_USE_SSE +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && !defined(__MINGW32__) +#include +#define ANGLE_USE_SSE #endif +// Mips and arm devices need to include stddef for size_t. +#if defined(__mips__) || defined(__arm__) || defined(__aarch64__) +#include +#endif + +// The MemoryBarrier function name collides with a macro under Windows +// We will undef the macro so that the function name does not get replaced +#undef MemoryBarrier + #endif // COMMON_PLATFORM_H_ diff --git a/src/3rdparty/angle/src/common/string_utils.cpp b/src/3rdparty/angle/src/common/string_utils.cpp index acb0376bf9..26f384bb2a 100644 --- a/src/3rdparty/angle/src/common/string_utils.cpp +++ b/src/3rdparty/angle/src/common/string_utils.cpp @@ -9,9 +9,14 @@ #include "string_utils.h" +#include +#include +#include #include #include +#include "common/platform.h" + namespace angle { @@ -133,4 +138,76 @@ bool ReadFileToString(const std::string &path, std::string *stringOut) return !inFile.fail(); } +Optional> WidenString(size_t length, const char *cString) +{ + std::vector wcstring(length + 1); +#if !defined(ANGLE_PLATFORM_WINDOWS) + size_t written = mbstowcs(wcstring.data(), cString, length + 1); + if (written == 0) + { + return Optional>::Invalid(); + } +#else + size_t convertedChars = 0; + errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, cString, _TRUNCATE); + if (err != 0) + { + return Optional>::Invalid(); + } +#endif + return Optional>(wcstring); +} + +bool BeginsWith(const std::string &str, const std::string &prefix) +{ + return strncmp(str.c_str(), prefix.c_str(), prefix.length()) == 0; +} + +bool BeginsWith(const std::string &str, const char *prefix) +{ + return strncmp(str.c_str(), prefix, strlen(prefix)) == 0; +} + +bool BeginsWith(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} + +bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength) +{ + return strncmp(str.c_str(), prefix.c_str(), prefixLength) == 0; +} + +bool EndsWith(const std::string &str, const char *suffix) +{ + const auto len = strlen(suffix); + if (len > str.size()) + return false; + + const char *end = str.c_str() + str.size() - len; + + return memcmp(end, suffix, len) == 0; +} + +void ToLower(std::string *str) +{ + for (auto &ch : *str) + { + ch = static_cast(::tolower(ch)); + } +} + +bool ReplaceSubstring(std::string *str, + const std::string &substring, + const std::string &replacement) +{ + size_t replacePos = str->find(substring); + if (replacePos == std::string::npos) + { + return false; + } + str->replace(replacePos, substring.size(), replacement); + return true; } + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/string_utils.h b/src/3rdparty/angle/src/common/string_utils.h index 131b17e086..07bf1ff81a 100644 --- a/src/3rdparty/angle/src/common/string_utils.h +++ b/src/3rdparty/angle/src/common/string_utils.h @@ -13,6 +13,8 @@ #include #include +#include "common/Optional.h" + namespace angle { @@ -44,6 +46,40 @@ bool HexStringToUInt(const std::string &input, unsigned int *uintOut); bool ReadFileToString(const std::string &path, std::string *stringOut); -} +Optional> WidenString(size_t length, const char *cString); + +// Check if the string str begins with the given prefix. +// The comparison is case sensitive. +bool BeginsWith(const std::string &str, const std::string &prefix); + +// Check if the string str begins with the given prefix. +// Prefix may not be NULL and needs to be NULL terminated. +// The comparison is case sensitive. +bool BeginsWith(const std::string &str, const char *prefix); + +// Check if the string str begins with the given prefix. +// str and prefix may not be NULL and need to be NULL terminated. +// The comparison is case sensitive. +bool BeginsWith(const char *str, const char *prefix); + +// Check if the string str begins with the first prefixLength characters of the given prefix. +// The length of the prefix string should be greater than or equal to prefixLength. +// The comparison is case sensitive. +bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength); + +// Check if the string str ends with the given suffix. +// Suffix may not be NUL and needs to be NULL terminated. +// The comparison is case sensitive. +bool EndsWith(const std::string& str, const char* suffix); + +// Convert to lower-case. +void ToLower(std::string *str); + +// Replaces the substring 'substring' in 'str' with 'replacement'. Returns true if successful. +bool ReplaceSubstring(std::string *str, + const std::string &substring, + const std::string &replacement); + +} // namespace angle #endif // LIBANGLE_STRING_UTILS_H_ diff --git a/src/3rdparty/angle/src/common/system_utils.h b/src/3rdparty/angle/src/common/system_utils.h new file mode 100644 index 0000000000..d61faa53fd --- /dev/null +++ b/src/3rdparty/angle/src/common/system_utils.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// system_utils.h: declaration of OS-specific utility functions + +#ifndef COMMON_SYSTEM_UTILS_H_ +#define COMMON_SYSTEM_UTILS_H_ + +#include "common/angleutils.h" +#include "common/Optional.h" + +namespace angle +{ + +const char *GetExecutablePath(); +const char *GetExecutableDirectory(); +const char *GetSharedLibraryExtension(); +Optional GetCWD(); +bool SetCWD(const char *dirName); +bool SetEnvironmentVar(const char *variableName, const char *value); + +} // namespace angle + +#endif // COMMON_SYSTEM_UTILS_H_ diff --git a/src/3rdparty/angle/src/common/system_utils_linux.cpp b/src/3rdparty/angle/src/common/system_utils_linux.cpp new file mode 100644 index 0000000000..98ab4cce6d --- /dev/null +++ b/src/3rdparty/angle/src/common/system_utils_linux.cpp @@ -0,0 +1,89 @@ +// +// 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. +// + +// system_utils_linux.cpp: Implementation of OS-specific functions for Linux + +#include "system_utils.h" + +#include +#include +#include +#include + +#include + +namespace angle +{ + +namespace +{ + +std::string GetExecutablePathImpl() +{ + // We cannot use lstat to get the size of /proc/self/exe as it always returns 0 + // so we just use a big buffer and hope the path fits in it. + char path[4096]; + + ssize_t result = readlink("/proc/self/exe", path, sizeof(path) - 1); + if (result < 0 || static_cast(result) >= sizeof(path) - 1) + { + return ""; + } + + path[result] = '\0'; + return path; +} + +std::string GetExecutableDirectoryImpl() +{ + std::string executablePath = GetExecutablePath(); + size_t lastPathSepLoc = executablePath.find_last_of("/"); + return (lastPathSepLoc != std::string::npos) ? executablePath.substr(0, lastPathSepLoc) : ""; +} + +} // anonymous namespace + +const char *GetExecutablePath() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exePath = GetExecutablePathImpl(); + return exePath.c_str(); +} + +const char *GetExecutableDirectory() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exeDir = GetExecutableDirectoryImpl(); + return exeDir.c_str(); +} + +const char *GetSharedLibraryExtension() +{ + return "so"; +} + +Optional GetCWD() +{ + std::array pathBuf; + char *result = getcwd(pathBuf.data(), pathBuf.size()); + if (result == nullptr) + { + return Optional::Invalid(); + } + return std::string(pathBuf.data()); +} + +bool SetCWD(const char *dirName) +{ + return (chdir(dirName) == 0); +} + +bool SetEnvironmentVar(const char *variableName, const char *value) +{ + return (setenv(variableName, value, 1) == 0); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/system_utils_mac.cpp b/src/3rdparty/angle/src/common/system_utils_mac.cpp new file mode 100644 index 0000000000..03b9185ab1 --- /dev/null +++ b/src/3rdparty/angle/src/common/system_utils_mac.cpp @@ -0,0 +1,94 @@ +// +// 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. +// + +// system_utils_osx.cpp: Implementation of OS-specific functions for OSX + +#include "system_utils.h" + +#include + +#include +#include +#include + +#include + +namespace angle +{ + +namespace +{ + +std::string GetExecutablePathImpl() +{ + std::string result; + + uint32_t size = 0; + _NSGetExecutablePath(nullptr, &size); + + std::vector buffer; + buffer.resize(size + 1); + + _NSGetExecutablePath(buffer.data(), &size); + buffer[size] = '\0'; + + if (!strrchr(buffer.data(), '/')) + { + return ""; + } + return buffer.data(); +} + +std::string GetExecutableDirectoryImpl() +{ + std::string executablePath = GetExecutablePath(); + size_t lastPathSepLoc = executablePath.find_last_of("/"); + return (lastPathSepLoc != std::string::npos) ? executablePath.substr(0, lastPathSepLoc) : ""; +} + +} // anonymous namespace + +const char *GetExecutablePath() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exePath = GetExecutablePathImpl(); + return exePath.c_str(); +} + +const char *GetExecutableDirectory() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exeDir = GetExecutableDirectoryImpl(); + return exeDir.c_str(); +} + +const char *GetSharedLibraryExtension() +{ + return "dylib"; +} + +Optional GetCWD() +{ + std::array pathBuf; + char *result = getcwd(pathBuf.data(), pathBuf.size()); + if (result == nullptr) + { + return Optional::Invalid(); + } + return std::string(pathBuf.data()); +} + +bool SetCWD(const char *dirName) +{ + return (chdir(dirName) == 0); +} + +bool SetEnvironmentVar(const char *variableName, const char *value) +{ + return (setenv(variableName, value, 1) == 0); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/system_utils_win.cpp b/src/3rdparty/angle/src/common/system_utils_win.cpp new file mode 100644 index 0000000000..6bb2bfbd3f --- /dev/null +++ b/src/3rdparty/angle/src/common/system_utils_win.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// system_utils_win.cpp: Implementation of OS-specific functions for Windows + +#include "system_utils.h" + +#include +#include +#include +#include + +namespace angle +{ + +namespace +{ + +std::string GetExecutablePathImpl() +{ + std::array executableFileBuf; + DWORD executablePathLen = GetModuleFileNameA(nullptr, executableFileBuf.data(), + static_cast(executableFileBuf.size())); + return (executablePathLen > 0 ? std::string(executableFileBuf.data()) : ""); +} + +std::string GetExecutableDirectoryImpl() +{ + std::string executablePath = GetExecutablePath(); + size_t lastPathSepLoc = executablePath.find_last_of("\\/"); + return (lastPathSepLoc != std::string::npos) ? executablePath.substr(0, lastPathSepLoc) : ""; +} + +} // anonymous namespace + +const char *GetExecutablePath() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exePath = GetExecutablePathImpl(); + return exePath.c_str(); +} + +const char *GetExecutableDirectory() +{ + // TODO(jmadill): Make global static string thread-safe. + const static std::string &exeDir = GetExecutableDirectoryImpl(); + return exeDir.c_str(); +} + +const char *GetSharedLibraryExtension() +{ + return "dll"; +} + +Optional GetCWD() +{ + std::array pathBuf; + DWORD result = GetCurrentDirectoryA(static_cast(pathBuf.size()), pathBuf.data()); + if (result == 0) + { + return Optional::Invalid(); + } + return std::string(pathBuf.data()); +} + +bool SetCWD(const char *dirName) +{ + return (SetCurrentDirectoryA(dirName) == TRUE); +} + +bool SetEnvironmentVar(const char *variableName, const char *value) +{ + return (SetEnvironmentVariableA(variableName, value) == TRUE); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/third_party/base/README.angle b/src/3rdparty/angle/src/common/third_party/base/README.angle new file mode 100644 index 0000000000..ca0943bc99 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/README.angle @@ -0,0 +1,27 @@ +Name: Chromium base:: helper Classes +Short Name: base::numerics, base::MRUCachem, base::SHA1 +Version: +URL: https://chromium.googlesource.com/chromium/src/base/+/master +SOURCE CODE: Copy the Chromium folder manually into this folder and run git cl format. +Date: 24/05/2017 +Revision: 28b5bbb227d331c01e6ff9b2f8729732135aadc7 (Chromium) +Security Critical: no +License: Chromium +License File: LICENSE in Chromium/src + +Description: +base::numerics is a library for doing some simple safe math and conversions. +base::MRUCache is a few collections of most-recently-used caching structures. +base::SHA1 is a secure hashing algorithm. + +To update the checkout, simply overwrite the folder with Chromium's latest, apply +the appropriate namespace, and make sure the paths are correct (anglebase/ instead of +base/), and update the header guards and macros. + +Modifications: + +- the file scope is now anglebase/ from base/ to prevent include conflicts. +- anglebase/logging.h defines (D)CHECK to be ASSERT to be compatible with ANGLE. +- the headers use namespace angle::base instead of base:: to avoid ODR + violations when ANGLE code is mixed with Chromium code. +- header guards and macros are changed from BASE to ANGLEBASE to prevent conflicts. diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h new file mode 100644 index 0000000000..1af5485336 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/base_export.h @@ -0,0 +1,13 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// base_export.h: Compatiblity hacks for importing Chromium's base/SHA1. + +#ifndef ANGLEBASE_BASE_EXPORT_H_ +#define ANGLEBASE_BASE_EXPORT_H_ + +#define ANGLEBASE_EXPORT + +#endif // ANGLEBASE_BASE_EXPORT_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h new file mode 100644 index 0000000000..fe4fec5768 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/containers/mru_cache.h @@ -0,0 +1,275 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains a template for a Most Recently Used cache that allows +// constant-time access to items using a key, but easy identification of the +// least-recently-used items for removal. Each key can only be associated with +// one payload item at a time. +// +// The key object will be stored twice, so it should support efficient copying. +// +// NOTE: While all operations are O(1), this code is written for +// legibility rather than optimality. If future profiling identifies this as +// a bottleneck, there is room for smaller values of 1 in the O(1). :] + +#ifndef ANGLEBASE_CONTAINERS_MRU_CACHE_H_ +#define ANGLEBASE_CONTAINERS_MRU_CACHE_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/macros.h" + +namespace angle +{ + +namespace base +{ + +// MRUCacheBase ---------------------------------------------------------------- + +// This template is used to standardize map type containers that can be used +// by MRUCacheBase. This level of indirection is necessary because of the way +// that template template params and default template params interact. +template +struct MRUCacheStandardMap +{ + typedef std::map Type; +}; + +// Base class for the MRU cache specializations defined below. +template class MapType = MRUCacheStandardMap> +class MRUCacheBase +{ + public: + // The payload of the list. This maintains a copy of the key so we can + // efficiently delete things given an element of the list. + typedef std::pair value_type; + + private: + typedef std::list PayloadList; + typedef + typename MapType::Type KeyIndex; + + public: + typedef typename PayloadList::size_type size_type; + + typedef typename PayloadList::iterator iterator; + typedef typename PayloadList::const_iterator const_iterator; + typedef typename PayloadList::reverse_iterator reverse_iterator; + typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; + + enum + { + NO_AUTO_EVICT = 0 + }; + + // The max_size is the size at which the cache will prune its members to when + // a new item is inserted. If the caller wants to manager this itself (for + // example, maybe it has special work to do when something is evicted), it + // can pass NO_AUTO_EVICT to not restrict the cache size. + explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {} + + virtual ~MRUCacheBase() {} + + size_type max_size() const { return max_size_; } + + // Inserts a payload item with the given key. If an existing item has + // the same key, it is removed prior to insertion. An iterator indicating the + // inserted item will be returned (this will always be the front of the list). + // + // The payload will be forwarded. + template + iterator Put(const KeyType &key, Payload &&payload) + { + // Remove any existing payload with that key. + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter != index_.end()) + { + // Erase the reference to it. The index reference will be replaced in the + // code below. + Erase(index_iter->second); + } + else if (max_size_ != NO_AUTO_EVICT) + { + // New item is being inserted which might make it larger than the maximum + // size: kick the oldest thing out if necessary. + ShrinkToSize(max_size_ - 1); + } + + ordering_.emplace_front(key, std::forward(payload)); + index_.emplace(key, ordering_.begin()); + return ordering_.begin(); + } + + // Retrieves the contents of the given key, or end() if not found. This method + // has the side effect of moving the requested item to the front of the + // recency list. + iterator Get(const KeyType &key) + { + typename KeyIndex::iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + typename PayloadList::iterator iter = index_iter->second; + + // Move the touched item to the front of the recency ordering. + ordering_.splice(ordering_.begin(), ordering_, iter); + return ordering_.begin(); + } + + // Retrieves the payload associated with a given key and returns it via + // result without affecting the ordering (unlike Get). + iterator Peek(const KeyType &key) + { + typename KeyIndex::const_iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + return index_iter->second; + } + + const_iterator Peek(const KeyType &key) const + { + typename KeyIndex::const_iterator index_iter = index_.find(key); + if (index_iter == index_.end()) + return end(); + return index_iter->second; + } + + // Exchanges the contents of |this| by the contents of the |other|. + void Swap(MRUCacheBase &other) + { + ordering_.swap(other.ordering_); + index_.swap(other.index_); + std::swap(max_size_, other.max_size_); + } + + // Erases the item referenced by the given iterator. An iterator to the item + // following it will be returned. The iterator must be valid. + iterator Erase(iterator pos) + { + index_.erase(pos->first); + return ordering_.erase(pos); + } + + // MRUCache entries are often processed in reverse order, so we add this + // convenience function (not typically defined by STL containers). + reverse_iterator Erase(reverse_iterator pos) + { + // We have to actually give it the incremented iterator to delete, since + // the forward iterator that base() returns is actually one past the item + // being iterated over. + return reverse_iterator(Erase((++pos).base())); + } + + // Shrinks the cache so it only holds |new_size| items. If |new_size| is + // bigger or equal to the current number of items, this will do nothing. + void ShrinkToSize(size_type new_size) + { + for (size_type i = size(); i > new_size; i--) + Erase(rbegin()); + } + + // Deletes everything from the cache. + void Clear() + { + index_.clear(); + ordering_.clear(); + } + + // Returns the number of elements in the cache. + size_type size() const + { + // We don't use ordering_.size() for the return value because + // (as a linked list) it can be O(n). + DCHECK(index_.size() == ordering_.size()); + return index_.size(); + } + + // Allows iteration over the list. Forward iteration starts with the most + // recent item and works backwards. + // + // Note that since these iterators are actually iterators over a list, you + // can keep them as you insert or delete things (as long as you don't delete + // the one you are pointing to) and they will still be valid. + iterator begin() { return ordering_.begin(); } + const_iterator begin() const { return ordering_.begin(); } + iterator end() { return ordering_.end(); } + const_iterator end() const { return ordering_.end(); } + + reverse_iterator rbegin() { return ordering_.rbegin(); } + const_reverse_iterator rbegin() const { return ordering_.rbegin(); } + reverse_iterator rend() { return ordering_.rend(); } + const_reverse_iterator rend() const { return ordering_.rend(); } + + bool empty() const { return ordering_.empty(); } + + private: + PayloadList ordering_; + KeyIndex index_; + + size_type max_size_; + + DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); +}; + +// MRUCache -------------------------------------------------------------------- + +// A container that does not do anything to free its data. Use this when storing +// value types (as opposed to pointers) in the list. +template > +class MRUCache : public MRUCacheBase +{ + private: + using ParentType = MRUCacheBase; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit MRUCache(typename ParentType::size_type max_size) : ParentType(max_size) {} + virtual ~MRUCache() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MRUCache); +}; + +// HashingMRUCache ------------------------------------------------------------ + +template +struct MRUCacheHashMap +{ + typedef std::unordered_map Type; +}; + +// This class is similar to MRUCache, except that it uses std::unordered_map as +// the map type instead of std::map. Note that your KeyType must be hashable to +// use this cache or you need to provide a hashing class. +template > +class HashingMRUCache : public MRUCacheBase +{ + private: + using ParentType = MRUCacheBase; + + public: + // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. + explicit HashingMRUCache(typename ParentType::size_type max_size) : ParentType(max_size) {} + virtual ~HashingMRUCache() {} + + private: + DISALLOW_COPY_AND_ASSIGN(HashingMRUCache); +}; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_CONTAINERS_MRU_CACHE_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h new file mode 100644 index 0000000000..85ad82b47d --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/logging.h @@ -0,0 +1,26 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// logging.h: Compatiblity hacks for importing Chromium's base/numerics. + +#ifndef ANGLEBASE_LOGGING_H_ +#define ANGLEBASE_LOGGING_H_ + +#include "common/debug.h" + +#ifndef DCHECK +#define DCHECK(X) ASSERT(X) +#endif + +#ifndef CHECK +#define CHECK(X) ASSERT(X) +#endif + +// Unfortunately ANGLE relies on ASSERT being an empty statement, which these libs don't respect. +#ifndef NOTREACHED +#define NOTREACHED() UNREACHABLE() +#endif + +#endif // ANGLEBASE_LOGGING_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h new file mode 100644 index 0000000000..06391784e4 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/macros.h @@ -0,0 +1,17 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// macros.h: Compatiblity hacks for importing Chromium's MRUCache. + +#ifndef ANGLEBASE_MACROS_H_ +#define ANGLEBASE_MACROS_H_ + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &) = delete; \ + void operator=(const TypeName &) = delete + +#endif // ANGLEBASE_MACROS_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS new file mode 100644 index 0000000000..41f35fc79b --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/OWNERS @@ -0,0 +1,3 @@ +jschuh@chromium.org +tsepez@chromium.org + diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h new file mode 100644 index 0000000000..43babc31a8 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions.h @@ -0,0 +1,179 @@ +// Copyright 2014 The Chromium 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 ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include + +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/numerics/safe_conversions_impl.h" + +namespace angle +{ + +namespace base +{ + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template +constexpr bool IsValueInRangeForNumericType(Src value) +{ + return internal::DstRangeRelationToSrcRange(value) == internal::RANGE_VALID; +} + +// Convenience function for determining if a numeric value is negative without +// throwing compiler warnings on: unsigned(value) < 0. +template +constexpr typename std::enable_if::is_signed, bool>::type IsValueNegative( + T value) +{ + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + return value < 0; +} + +template +constexpr typename std::enable_if::is_signed, bool>::type IsValueNegative(T) +{ + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + return false; +} + +// checked_cast<> is analogous to static_cast<> for numeric types, +// except that it CHECKs that the specified numeric conversion will not +// overflow or underflow. NaN source will always trigger a CHECK. +template +inline Dst checked_cast(Src value) +{ + CHECK(IsValueInRangeForNumericType(value)); + return static_cast(value); +} + +// HandleNaN will cause this class to CHECK(false). +struct SaturatedCastNaNBehaviorCheck +{ + template + static T HandleNaN() + { + CHECK(false); + return T(); + } +}; + +// HandleNaN will return 0 in this case. +struct SaturatedCastNaNBehaviorReturnZero +{ + template + static constexpr T HandleNaN() + { + return T(); + } +}; + +namespace internal +{ +// This wrapper is used for C++11 constexpr support by avoiding the declaration +// of local variables in the saturated_cast template function. +template +constexpr Dst saturated_cast_impl(const Src value, const RangeConstraint constraint) +{ + return constraint == RANGE_VALID + ? static_cast(value) + : (constraint == RANGE_UNDERFLOW + ? std::numeric_limits::min() + : (constraint == RANGE_OVERFLOW + ? std::numeric_limits::max() + : (constraint == RANGE_INVALID + ? NaNHandler::template HandleNaN() + : (NOTREACHED(), static_cast(value))))); +} +} // namespace internal + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will defer the behavior to a +// specified class. By default, it will return 0. +template +constexpr Dst saturated_cast(Src value) +{ + return std::numeric_limits::is_iec559 + ? static_cast(value) // Floating point optimization. + : internal::saturated_cast_impl( + value, internal::DstRangeRelationToSrcRange(value)); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. +template +constexpr Dst strict_cast(Src value) +{ + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + static_assert(std::numeric_limits::is_specialized, "Result must be numeric."); + static_assert((internal::StaticDstRangeRelationToSrcRange::value == + internal::NUMERIC_RANGE_CONTAINED), + "The numeric conversion is out of range for this type. You " + "should probably use one of the following conversion " + "mechanisms on the value you want to pass:\n" + "- base::checked_cast\n" + "- base::saturated_cast\n" + "- base::CheckedNumeric"); + + return static_cast(value); +} + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of the actual value being assigned. +template +class StrictNumeric +{ + public: + typedef T type; + + constexpr StrictNumeric() : value_(0) {} + + // Copy constructor. + template + constexpr StrictNumeric(const StrictNumeric &rhs) : value_(strict_cast(rhs.value_)) + { + } + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template + constexpr StrictNumeric(Src value) : value_(strict_cast(value)) + { + } + + // The numeric cast operator basically handles all the magic. + template + constexpr operator Dst() const + { + return strict_cast(value_); + } + + private: + const T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric SizeT; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h new file mode 100644 index 0000000000..10ed6c7a7f --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_conversions_impl.h @@ -0,0 +1,274 @@ +// Copyright 2014 The Chromium 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 ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include +#include + +#include +#include + +namespace angle +{ + +namespace base +{ +namespace internal +{ + +// The std library doesn't provide a binary max_exponent for integers, however +// we can compute one by adding one to the number of non-sign bits. This allows +// for accurate range comparisons between floating point and integer types. +template +struct MaxExponent +{ + static_assert(std::is_arithmetic::value, "Argument must be numeric."); + static const int value = + std::numeric_limits::is_iec559 + ? std::numeric_limits::max_exponent + : (sizeof(NumericType) * CHAR_BIT + 1 - std::numeric_limits::is_signed); +}; + +enum IntegerRepresentation +{ + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits::max() <= numeric_limits::max() and +// numeric_limits::min() >= numeric_limits::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation +{ + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template ::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED> +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template +struct StaticDstRangeRelationToSrcRange +{ + static const NumericRangeRepresentation value = + MaxExponent::value >= MaxExponent::value ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template +struct StaticDstRangeRelationToSrcRange +{ + static const NumericRangeRepresentation value = + MaxExponent::value > MaxExponent::value ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template +struct StaticDstRangeRelationToSrcRange +{ + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint : unsigned char +{ + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) +{ + // TODO(jschuh): Once we get full C++14 support we want this + // assert(integer_range_constraint >= RANGE_VALID && + // integer_range_constraint <= RANGE_INVALID) + return static_cast(integer_range_constraint); +} + +// This function creates a RangeConstraint from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, bool is_in_lower_bound) +{ + return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | + (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); +} + +// The following helper template addresses a corner case in range checks for +// conversion from a floating-point type to an integral type of smaller range +// but larger precision (e.g. float -> unsigned). The problem is as follows: +// 1. Integral maximum is always one less than a power of two, so it must be +// truncated to fit the mantissa of the floating point. The direction of +// rounding is implementation defined, but by default it's always IEEE +// floats, which round to nearest and thus result in a value of larger +// magnitude than the integral value. +// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX +// // is 4294967295u. +// 2. If the floating point value is equal to the promoted integral maximum +// value, a range check will erroneously pass. +// Example: (4294967296f <= 4294967295u) // This is true due to a precision +// // loss in rounding up to float. +// 3. When the floating point value is then converted to an integral, the +// resulting value is out of range for the target integral type and +// thus is implementation defined. +// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. +// To fix this bug we manually truncate the maximum value when the destination +// type is an integral of larger precision than the source floating-point type, +// such that the resulting maximum is represented exactly as a floating point. +template +struct NarrowingRange +{ + typedef typename std::numeric_limits SrcLimits; + typedef typename std::numeric_limits DstLimits; + // The following logic avoids warnings where the max function is + // instantiated with invalid values for a bit shift (even though + // such a function can never be called). + static const int shift = (MaxExponent::value > MaxExponent::value && + SrcLimits::digits < DstLimits::digits && + SrcLimits::is_iec559 && + DstLimits::is_integer) + ? (DstLimits::digits - SrcLimits::digits) + : 0; + + static constexpr Dst max() + { + // We use UINTMAX_C below to avoid compiler warnings about shifting floating + // points. Since it's a compile time calculation, it shouldn't have any + // performance impact. + return DstLimits::max() - static_cast((UINTMAX_C(1) << shift) - 1); + } + + static constexpr Dst min() + { + return std::numeric_limits::is_iec559 ? -DstLimits::max() : DstLimits::min(); + } +}; + +template ::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = StaticDstRangeRelationToSrcRange::value> +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr RangeConstraint Check(Src value) + { + return GetRangeConstraint((value <= NarrowingRange::max()), + (value >= NarrowingRange::min())); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr RangeConstraint Check(Src value) + { + return GetRangeConstraint(value <= NarrowingRange::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr RangeConstraint Check(Src value) + { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint(value <= static_cast(NarrowingRange::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template +struct DstRangeRelationToSrcRangeImpl +{ + static constexpr RangeConstraint Check(Src value) + { + return (MaxExponent::value >= MaxExponent::value) + ? GetRangeConstraint(true, value >= static_cast(0)) + : GetRangeConstraint(value <= static_cast(NarrowingRange::max()), + value >= static_cast(0)); + } +}; + +template +constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) +{ + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + static_assert(std::numeric_limits::is_specialized, "Result must be numeric."); + return DstRangeRelationToSrcRangeImpl::Check(value); +} + +} // namespace internal +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h new file mode 100644 index 0000000000..3af4db63f7 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math.h @@ -0,0 +1,329 @@ +// Copyright 2014 The Chromium 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 ANGLEBASE_NUMERICS_SAFE_MATH_H_ +#define ANGLEBASE_NUMERICS_SAFE_MATH_H_ + +#include + +#include +#include + +#include "anglebase/logging.h" +#include "anglebase/numerics/safe_math_impl.h" + +namespace angle +{ + +namespace base +{ + +namespace internal +{ + +// CheckedNumeric implements all the logic and operators for detecting integer +// boundary conditions such as overflow, underflow, and invalid conversions. +// The CheckedNumeric type implicitly converts from floating point and integer +// data types, and contains overloads for basic arithmetic operations (i.e.: +, +// -, *, /, %). +// +// The following methods convert from CheckedNumeric to standard numeric values: +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has +// has not wrapped and is not the result of an invalid conversion). +// ValueOrDie() - Returns the underlying value. If the state is not valid this +// call will crash on a CHECK. +// ValueOrDefault() - Returns the current value, or the supplied default if the +// state is not valid. +// ValueFloating() - Returns the underlying floating point value (valid only +// only for floating point CheckedNumeric types). +// +// Bitwise operations are explicitly not supported, because correct +// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison +// operations are explicitly not supported because they could result in a crash +// on a CHECK condition. You should use patterns like the following for these +// operations: +// Bitwise operation: +// CheckedNumeric checked_int = untrusted_input_value; +// int x = checked_int.ValueOrDefault(0) | kFlagValues; +// Comparison: +// CheckedNumeric checked_size = untrusted_input_value; +// checked_size += HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template +class CheckedNumeric +{ + static_assert(std::is_arithmetic::value, "CheckedNumeric: T must be a numeric type."); + + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template + CheckedNumeric(const CheckedNumeric &rhs) : state_(rhs.ValueUnsafe(), rhs.validity()) + { + } + + template + CheckedNumeric(Src value, RangeConstraint validity) : state_(value, validity) + { + } + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template + CheckedNumeric(Src value) // NOLINT(runtime/explicit) + : state_(value) + { + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template + CheckedNumeric(StrictNumeric value) // NOLINT(runtime/explicit) + : state_(static_cast(value)) + { + } + + // IsValid() is the public API to test if a CheckedNumeric is currently valid. + bool IsValid() const { return validity() == RANGE_VALID; } + + // ValueOrDie() The primary accessor for the underlying value. If the current + // state is not valid it will CHECK and crash. + T ValueOrDie() const + { + CHECK(IsValid()); + return state_.value(); + } + + // ValueOrDefault(T default_value) A convenience method that returns the + // current value if the state is valid, and the supplied default_value for + // any other state. + T ValueOrDefault(T default_value) const { return IsValid() ? state_.value() : default_value; } + + // ValueFloating() - Since floating point values include their validity state, + // we provide an easy method for extracting them directly, without a risk of + // crashing on a CHECK. + T ValueFloating() const + { + static_assert(std::numeric_limits::is_iec559, "Argument must be float."); + return CheckedNumeric::cast(*this).ValueUnsafe(); + } + + // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for + // tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: current validity state (i.e. valid, overflow, underflow, nan). + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + RangeConstraint validity() const { return state_.validity(); } + + // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now + // for tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: the raw numeric value, regardless of the current state. + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + T ValueUnsafe() const { return state_.value(); } + + // Prototypes for the supported arithmetic operator overloads. + template + CheckedNumeric &operator+=(Src rhs); + template + CheckedNumeric &operator-=(Src rhs); + template + CheckedNumeric &operator*=(Src rhs); + template + CheckedNumeric &operator/=(Src rhs); + template + CheckedNumeric &operator%=(Src rhs); + + CheckedNumeric operator-() const + { + RangeConstraint validity; + T value = CheckedNeg(state_.value(), &validity); + // Negation is always valid for floating point. + if (std::numeric_limits::is_iec559) + return CheckedNumeric(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + CheckedNumeric Abs() const + { + RangeConstraint validity; + T value = CheckedAbs(state_.value(), &validity); + // Absolute value is always valid for floating point. + if (std::numeric_limits::is_iec559) + return CheckedNumeric(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric(value, validity); + } + + // This function is available only for integral types. It returns an unsigned + // integer of the same width as the source type, containing the absolute value + // of the source, and properly handling signed min. + CheckedNumeric::type> UnsignedAbs() const + { + return CheckedNumeric::type>( + CheckedUnsignedAbs(state_.value()), state_.validity()); + } + + CheckedNumeric &operator++() + { + *this += 1; + return *this; + } + + CheckedNumeric operator++(int) + { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + CheckedNumeric &operator--() + { + *this -= 1; + return *this; + } + + CheckedNumeric operator--(int) + { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These static methods behave like a convenience cast operator targeting + // the desired CheckedNumeric type. As an optimization, a reference is + // returned when Src is the same type as T. + template + static CheckedNumeric cast( + Src u, + typename std::enable_if::is_specialized, int>::type = 0) + { + return u; + } + + template + static CheckedNumeric cast( + const CheckedNumeric &u, + typename std::enable_if::value, int>::type = 0) + { + return u; + } + + static const CheckedNumeric &cast(const CheckedNumeric &u) { return u; } + + private: + template + struct UnderlyingType + { + using type = NumericType; + }; + + template + struct UnderlyingType> + { + using type = NumericType; + }; + + CheckedNumericState state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric &lhs, const CheckedNumeric &rhs) \ + { \ + typedef typename ArithmeticPromotion::type Promotion; \ + /* Floating point always takes the fast path */ \ + if (std::numeric_limits::is_iec559) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = \ + static_cast(Checked##NAME(static_cast(lhs.ValueUnsafe()), \ + static_cast(rhs.ValueUnsafe()), &validity)); \ + return CheckedNumeric( \ + result, GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ + } \ + /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ + template \ + template \ + CheckedNumeric &CheckedNumeric::operator COMPOUND_OP(Src rhs) \ + { \ + *this = CheckedNumeric::cast(*this) \ + OP CheckedNumeric::type>::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric &lhs, const CheckedNumeric &rhs) \ + { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric::cast(lhs) OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template ::value>::type * = nullptr> \ + CheckedNumeric::type> operator OP( \ + const CheckedNumeric &lhs, Src rhs) \ + { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs.ValueUnsafe() OP rhs, lhs.validity()); \ + return CheckedNumeric::cast(lhs) OP CheckedNumeric::cast(rhs); \ + } \ + /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ + template ::value>::type * = nullptr> \ + CheckedNumeric::type> operator OP( \ + Src lhs, const CheckedNumeric &rhs) \ + { \ + typedef typename ArithmeticPromotion::type Promotion; \ + if (IsIntegerArithmeticSafe::value) \ + return CheckedNumeric(lhs OP rhs.ValueUnsafe(), rhs.validity()); \ + return CheckedNumeric::cast(lhs) OP CheckedNumeric::cast(rhs); \ + } + +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) +ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) + +#undef ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_MATH_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h new file mode 100644 index 0000000000..2831cc6ceb --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_math_impl.h @@ -0,0 +1,575 @@ +// Copyright 2014 The Chromium 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 ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include +#include + +#include +#include +#include +#include +#include + +#include "anglebase/numerics/safe_conversions.h" + +namespace angle +{ + +namespace base +{ +namespace internal +{ + +// Everything from here up to the floating point operations is portable C++, +// but it may not be fast. This code could be split based on +// platform/architecture and replaced with potentially faster implementations. + +// Integer promotion templates used by the portable checked integer arithmetic. +template +struct IntegerForSizeAndSign; +template <> +struct IntegerForSizeAndSign<1, true> +{ + typedef int8_t type; +}; +template <> +struct IntegerForSizeAndSign<1, false> +{ + typedef uint8_t type; +}; +template <> +struct IntegerForSizeAndSign<2, true> +{ + typedef int16_t type; +}; +template <> +struct IntegerForSizeAndSign<2, false> +{ + typedef uint16_t type; +}; +template <> +struct IntegerForSizeAndSign<4, true> +{ + typedef int32_t type; +}; +template <> +struct IntegerForSizeAndSign<4, false> +{ + typedef uint32_t type; +}; +template <> +struct IntegerForSizeAndSign<8, true> +{ + typedef int64_t type; +}; +template <> +struct IntegerForSizeAndSign<8, false> +{ + typedef uint64_t type; +}; + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). + +template +struct UnsignedIntegerForSize +{ + typedef + typename std::enable_if::is_integer, + typename IntegerForSizeAndSign::type>::type + type; +}; + +template +struct SignedIntegerForSize +{ + typedef + typename std::enable_if::is_integer, + typename IntegerForSizeAndSign::type>::type + type; +}; + +template +struct TwiceWiderInteger +{ + typedef typename std::enable_if< + std::numeric_limits::is_integer, + typename IntegerForSizeAndSign::is_signed>::type>::type type; +}; + +template +struct PositionOfSignBit +{ + static const typename std::enable_if::is_integer, size_t>::type + value = CHAR_BIT * sizeof(Integer) - 1; +}; + +// This is used for UnsignedAbs, where we need to support floating-point +// template instantiations even though we don't actually support the operations. +// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, +// so the float versions will not compile. +template ::is_integer, + bool IsFloat = std::numeric_limits::is_iec559> +struct UnsignedOrFloatForSize; + +template +struct UnsignedOrFloatForSize +{ + typedef typename UnsignedIntegerForSize::type type; +}; + +template +struct UnsignedOrFloatForSize +{ + typedef Numeric type; +}; + +// Helper templates for integer manipulations. + +template +constexpr bool HasSignBit(T x) +{ + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast::type>(x) >> + PositionOfSignBit::value); +} + +// This wrapper undoes the standard integer promotions. +template +constexpr T BinaryComplement(T x) +{ + return static_cast(~x); +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template +typename std::enable_if::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint *validity) +{ + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = static_cast(ux + uy); + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (std::numeric_limits::is_signed) + { + if (HasSignBit(BinaryComplement(static_cast((uresult ^ ux) & (uresult ^ uy))))) + { + *validity = RANGE_VALID; + } + else + { // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + } + } + else + { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast(uresult); +} + +template +typename std::enable_if::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint *validity) +{ + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize::type UnsignedDst; + UnsignedDst ux = static_cast(x); + UnsignedDst uy = static_cast(y); + UnsignedDst uresult = static_cast(ux - uy); + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (std::numeric_limits::is_signed) + { + if (HasSignBit(BinaryComplement(static_cast((uresult ^ ux) & (ux ^ uy))))) + { + *validity = RANGE_VALID; + } + else + { // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + } + } + else + { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template +typename std::enable_if::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + typedef typename TwiceWiderInteger::type IntermediateType; + IntermediateType tmp = static_cast(x) * static_cast(y); + *validity = DstRangeRelationToSrcRange(tmp); + return static_cast(tmp); +} + +template +typename std::enable_if::is_integer && std::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + // If either side is zero then the result will be zero. + if (!x || !y) + { + *validity = RANGE_VALID; + return static_cast(0); + } + else if (x > 0) + { + if (y > 0) + *validity = x <= std::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= std::numeric_limits::min() / x ? RANGE_VALID : RANGE_UNDERFLOW; + } + else + { + if (y > 0) + *validity = x >= std::numeric_limits::min() / y ? RANGE_VALID : RANGE_UNDERFLOW; + else + *validity = y >= std::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return static_cast(x * y); +} + +template +typename std::enable_if::is_integer && !std::numeric_limits::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + *validity = (y == 0 || x <= std::numeric_limits::max() / y) ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast(x * y); +} + +// Division just requires a check for an invalid negation on signed min/-1. +template +T CheckedDiv(T x, + T y, + RangeConstraint *validity, + typename std::enable_if::is_integer, int>::type = 0) +{ + if (std::numeric_limits::is_signed && x == std::numeric_limits::min() && + y == static_cast(-1)) + { + *validity = RANGE_OVERFLOW; + return std::numeric_limits::min(); + } + + *validity = RANGE_VALID; + return static_cast(x / y); +} + +template +typename std::enable_if::is_integer && std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint *validity) +{ + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return static_cast(x % y); +} + +template +typename std::enable_if::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint *validity) +{ + *validity = RANGE_VALID; + return static_cast(x % y); +} + +template +typename std::enable_if::is_integer && std::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint *validity) +{ + *validity = value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return static_cast(-value); +} + +template +typename std::enable_if::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint *validity) +{ + // The only legal unsigned negation is zero. + *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; + return static_cast(-static_cast::type>(value)); +} + +template +typename std::enable_if::is_integer && std::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint *validity) +{ + *validity = value != std::numeric_limits::min() ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast(std::abs(value)); +} + +template +typename std::enable_if::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint *validity) +{ + // T is unsigned, so |value| must already be positive. + *validity = RANGE_VALID; + return value; +} + +template +typename std::enable_if::is_integer && std::numeric_limits::is_signed, + typename UnsignedIntegerForSize::type>::type +CheckedUnsignedAbs(T value) +{ + typedef typename UnsignedIntegerForSize::type UnsignedT; + return value == std::numeric_limits::min() + ? static_cast(std::numeric_limits::max()) + 1 + : static_cast(std::abs(value)); +} + +template +typename std::enable_if::is_integer && !std::numeric_limits::is_signed, + T>::type +CheckedUnsignedAbs(T value) +{ + // T is unsigned, so |value| must already be positive. + return static_cast(value); +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define ANGLEBASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template \ + typename std::enable_if::is_iec559, T>::type Checked##NAME( \ + T, T, RangeConstraint *) \ + { \ + NOTREACHED(); \ + return static_cast(0); \ + } + +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Add) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Sub) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Mul) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Div) +ANGLEBASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef ANGLEBASE_FLOAT_ARITHMETIC_STUBS + +template +typename std::enable_if::is_iec559, T>::type CheckedNeg(T value, + RangeConstraint *) +{ + return static_cast(-value); +} + +template +typename std::enable_if::is_iec559, T>::type CheckedAbs(T value, + RangeConstraint *) +{ + return static_cast(std::abs(value)); +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation +{ + NUMERIC_INTEGER, + NUMERIC_FLOATING, + NUMERIC_UNKNOWN +}; + +template +struct GetNumericRepresentation +{ + static const NumericRepresentation value = + std::numeric_limits::is_integer + ? NUMERIC_INTEGER + : (std::numeric_limits::is_iec559 ? NUMERIC_FLOATING : NUMERIC_UNKNOWN); +}; + +template ::value> +class CheckedNumericState +{ +}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template +class CheckedNumericState +{ + private: + T value_; + RangeConstraint validity_ : CHAR_BIT; // Actually requires only two bits. + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template + CheckedNumericState(Src value, RangeConstraint validity) + : value_(static_cast(value)), + validity_(GetRangeConstraint(validity | DstRangeRelationToSrcRange(value))) + { + static_assert(std::numeric_limits::is_specialized, "Argument must be numeric."); + } + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState &rhs) + : value_(static_cast(rhs.value())), + validity_(GetRangeConstraint(rhs.validity() | DstRangeRelationToSrcRange(rhs.value()))) + { + } + + template + explicit CheckedNumericState( + Src value, + typename std::enable_if::is_specialized, int>::type = 0) + : value_(static_cast(value)), validity_(DstRangeRelationToSrcRange(value)) + { + } + + RangeConstraint validity() const { return validity_; } + T value() const { return value_; } +}; + +// Floating points maintain their own validity, but need translation wrappers. +template +class CheckedNumericState +{ + private: + T value_; + + public: + template + friend class CheckedNumericState; + + CheckedNumericState() : value_(0.0) {} + + template + CheckedNumericState( + Src value, + RangeConstraint validity, + typename std::enable_if::is_integer, int>::type = 0) + { + switch (DstRangeRelationToSrcRange(value)) + { + case RANGE_VALID: + value_ = static_cast(value); + break; + + case RANGE_UNDERFLOW: + value_ = -std::numeric_limits::infinity(); + break; + + case RANGE_OVERFLOW: + value_ = std::numeric_limits::infinity(); + break; + + case RANGE_INVALID: + value_ = std::numeric_limits::quiet_NaN(); + break; + + default: + NOTREACHED(); + } + } + + template + explicit CheckedNumericState( + Src value, + typename std::enable_if::is_specialized, int>::type = 0) + : value_(static_cast(value)) + { + } + + // Copy constructor. + template + CheckedNumericState(const CheckedNumericState &rhs) : value_(static_cast(rhs.value())) + { + } + + RangeConstraint validity() const + { + return GetRangeConstraint(value_ <= std::numeric_limits::max(), + value_ >= -std::numeric_limits::max()); + } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we have the type +// with the larger maximum exponent take precedence. +enum ArithmeticPromotionCategory +{ + LEFT_PROMOTION, + RIGHT_PROMOTION +}; + +template ::value > MaxExponent::value) ? LEFT_PROMOTION + : RIGHT_PROMOTION> +struct ArithmeticPromotion; + +template +struct ArithmeticPromotion +{ + typedef Lhs type; +}; + +template +struct ArithmeticPromotion +{ + typedef Rhs type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template +struct IsIntegerArithmeticSafe +{ + static const bool value = + !std::numeric_limits::is_iec559 && + StaticDstRangeRelationToSrcRange::value == NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange::value != NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc new file mode 100644 index 0000000000..052d850427 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/numerics/safe_numerics_unittest.cc @@ -0,0 +1,771 @@ +// Copyright 2013 The Chromium 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 +#include + +#include +#include + +#include "base/compiler_specific.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) +#include +#endif + +using std::numeric_limits; +using base::CheckedNumeric; +using base::checked_cast; +using base::IsValueInRangeForNumericType; +using base::IsValueNegative; +using base::SizeT; +using base::StrictNumeric; +using base::saturated_cast; +using base::strict_cast; +using base::internal::MaxExponent; +using base::internal::RANGE_VALID; +using base::internal::RANGE_INVALID; +using base::internal::RANGE_OVERFLOW; +using base::internal::RANGE_UNDERFLOW; +using base::internal::SignedIntegerForSize; + +// These tests deliberately cause arithmetic overflows. If the compiler is +// aggressive enough, it can const fold these overflows. Disable warnings about +// overflows for const expressions. +#if defined(OS_WIN) +#pragma warning(disable : 4756) +#endif + +// This is a helper function for finding the maximum value in Src that can be +// wholy represented as the destination floating-point type. +template +Dst GetMaxConvertibleToFloat() +{ + typedef numeric_limits DstLimits; + typedef numeric_limits SrcLimits; + static_assert(SrcLimits::is_specialized, "Source must be numeric."); + static_assert(DstLimits::is_specialized, "Destination must be numeric."); + CHECK(DstLimits::is_iec559); + + if (SrcLimits::digits <= DstLimits::digits && + MaxExponent::value <= MaxExponent::value) + return SrcLimits::max(); + Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0); + while (max != static_cast(static_cast(max))) + { + max /= 2; + } + return static_cast(max); +} + +// Helper macros to wrap displaying the conversion types and line numbers. +#define TEST_EXPECTED_VALIDITY(expected, actual) \ + EXPECT_EQ(expected, CheckedNumeric(actual).IsValid()) \ + << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst << " on line " \ + << line; + +#define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual) +#define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual) + +#define TEST_EXPECTED_VALUE(expected, actual) \ + EXPECT_EQ(static_cast(expected), CheckedNumeric(actual).ValueUnsafe()) \ + << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst << " on line " \ + << line; + +// Signed integer arithmetic. +template +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_integer && numeric_limits::is_signed, + int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_FAILURE(-CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) - -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) * 2); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) / -1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(-1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(-1, CheckedNumeric(-1) % 2); + TEST_EXPECTED_FAILURE(CheckedNumeric(-1) % -2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Unsigned integer arithmetic. +template +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_integer && !numeric_limits::is_signed, + int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric(DstLimits::min())); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::min()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) * 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) / 2); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).UnsignedAbs()); + TEST_EXPECTED_SUCCESS(CheckedNumeric::type>( + std::numeric_limits::type>::min()) + .UnsignedAbs()); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) % 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Floating point arithmetic. +template +void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if::is_iec559, int>::type = 0) +{ + typedef numeric_limits DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric(DstLimits::min())); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) + -1); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) * 2); + + TEST_EXPECTED_VALUE(-0.5, CheckedNumeric(-1.0) / 2); + EXPECT_EQ(static_cast(1.0), CheckedNumeric(1.0).ValueFloating()); +} + +// Generic arithmetic tests. +template +static void TestArithmetic(const char *dst, int line) +{ + typedef numeric_limits DstLimits; + + EXPECT_EQ(true, CheckedNumeric().IsValid()); + EXPECT_EQ( + false, + CheckedNumeric(CheckedNumeric(DstLimits::max()) * DstLimits::max()).IsValid()); + EXPECT_EQ(static_cast(0), CheckedNumeric().ValueOrDie()); + EXPECT_EQ(static_cast(0), CheckedNumeric().ValueOrDefault(1)); + EXPECT_EQ(static_cast(1), + CheckedNumeric(CheckedNumeric(DstLimits::max()) * DstLimits::max()) + .ValueOrDefault(1)); + + // Test the operator combinations. + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric(1)); + TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric(1)); + TEST_EXPECTED_VALUE(2, CheckedNumeric(1) + 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric(1) - 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) * 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + CheckedNumeric checked_dst = 1; + TEST_EXPECTED_VALUE(2, checked_dst += 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst -= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst *= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst /= 1); + + // Generic negation. + TEST_EXPECTED_VALUE(0, -CheckedNumeric()); + TEST_EXPECTED_VALUE(-1, -CheckedNumeric(1)); + TEST_EXPECTED_VALUE(1, -CheckedNumeric(-1)); + TEST_EXPECTED_VALUE(static_cast(DstLimits::max() * -1), + -CheckedNumeric(DstLimits::max())); + + // Generic absolute value. + TEST_EXPECTED_VALUE(0, CheckedNumeric().Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1).Abs()); + TEST_EXPECTED_VALUE(DstLimits::max(), CheckedNumeric(DstLimits::max()).Abs()); + + // Generic addition. + TEST_EXPECTED_VALUE(1, (CheckedNumeric() + 1)); + TEST_EXPECTED_VALUE(2, (CheckedNumeric(1) + 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) + 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::min()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) + DstLimits::max()); + + // Generic subtraction. + TEST_EXPECTED_VALUE(-1, (CheckedNumeric() - 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(1) - 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) - 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric(DstLimits::max()) - 1); + + // Generic multiplication. + TEST_EXPECTED_VALUE(0, (CheckedNumeric() * 1)); + TEST_EXPECTED_VALUE(1, (CheckedNumeric(1) * 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric(-1) * 2)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(-1) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric(0) * -1)); + TEST_EXPECTED_FAILURE(CheckedNumeric(DstLimits::max()) * DstLimits::max()); + + // Generic division. + TEST_EXPECTED_VALUE(0, CheckedNumeric() / 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric(1) / 1); + TEST_EXPECTED_VALUE(DstLimits::min() / 2, CheckedNumeric(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::max() / 2, CheckedNumeric(DstLimits::max()) / 2); + + TestSpecializedArithmetic(dst, line); +} + +// Helper macro to wrap displaying the conversion types and line numbers. +#define TEST_ARITHMETIC(Dst) TestArithmetic(#Dst, __LINE__) + +TEST(SafeNumerics, SignedIntegerMath) +{ + TEST_ARITHMETIC(int8_t); + TEST_ARITHMETIC(int); + TEST_ARITHMETIC(intptr_t); + TEST_ARITHMETIC(intmax_t); +} + +TEST(SafeNumerics, UnsignedIntegerMath) +{ + TEST_ARITHMETIC(uint8_t); + TEST_ARITHMETIC(unsigned int); + TEST_ARITHMETIC(uintptr_t); + TEST_ARITHMETIC(uintmax_t); +} + +TEST(SafeNumerics, FloatingPointMath) +{ + TEST_ARITHMETIC(float); + TEST_ARITHMETIC(double); +} + +// Enumerates the five different conversions types we need to test. +enum NumericConversionType +{ + SIGN_PRESERVING_VALUE_PRESERVING, + SIGN_PRESERVING_NARROW, + SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, + SIGN_TO_UNSIGN_NARROW, + UNSIGN_TO_SIGN_NARROW_OR_EQUAL, +}; + +// Template covering the different conversion tests. +template +struct TestNumericConversion +{ +}; + +// EXPECT_EQ wrappers providing specific detail on test failures. +#define TEST_EXPECTED_RANGE(expected, actual) \ + EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange(actual)) \ + << "Conversion test: " << src << " value " << actual << " to " << dst << " on line " \ + << line; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + // Integral to floating. + static_assert( + (DstLimits::is_iec559 && SrcLimits::is_integer) || + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && sizeof(Dst) >= sizeof(Src)) || + // Or signed destination and source is smaller + (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + "Comparison must be sign preserving and value preserving"); + + const CheckedNumeric checked_dst = SrcLimits::max(); + TEST_EXPECTED_SUCCESS(checked_dst); + if (MaxExponent::value > MaxExponent::value) + { + if (MaxExponent::value >= MaxExponent::value * 2 - 1) + { + // At least twice larger type. + TEST_EXPECTED_SUCCESS(SrcLimits::max() * checked_dst); + } + else + { // Larger, but not at least twice as large. + TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst); + TEST_EXPECTED_SUCCESS(checked_dst + 1); + } + } + else + { // Same width type. + TEST_EXPECTED_FAILURE(checked_dst + 1); + } + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } + else if (numeric_limits::is_signed) + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(SrcLimits::is_signed == DstLimits::is_signed, + "Destination and source sign must be the same"); + static_assert(sizeof(Dst) < sizeof(Src) || (DstLimits::is_integer && SrcLimits::is_iec559), + "Destination must be narrower than source"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast(GetMaxConvertibleToFloat())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } + else if (SrcLimits::is_signed) + { + TEST_EXPECTED_VALUE(-1, checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(-1)); + } + else + { + TEST_EXPECTED_FAILURE(checked_dst - static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(sizeof(Dst) >= sizeof(Src), + "Destination must be equal or wider than source."); + static_assert(SrcLimits::is_signed, "Source must be signed"); + static_assert(!DstLimits::is_signed, "Destination must be unsigned"); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert( + (DstLimits::is_integer && SrcLimits::is_iec559) || (sizeof(Dst) < sizeof(Src)), + "Destination must be narrower than source."); + static_assert(SrcLimits::is_signed, "Source must be signed."); + static_assert(!DstLimits::is_signed, "Destination must be unsigned."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast(-1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast(GetMaxConvertibleToFloat())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(DstLimits::min())); + } + } + else + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + } + } +}; + +template +struct TestNumericConversion +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits SrcLimits; + typedef numeric_limits DstLimits; + static_assert(sizeof(Dst) <= sizeof(Src), + "Destination must be narrower or equal to source."); + static_assert(!SrcLimits::is_signed, "Source must be unsigned."); + static_assert(DstLimits::is_signed, "Destination must be signed."); + + const CheckedNumeric checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast(1)); + } +}; + +// Helper macro to wrap displaying the conversion types and line numbers +#define TEST_NUMERIC_CONVERSION(d, s, t) TestNumericConversion::Test(#d, #s, __LINE__) + +TEST(SafeNumerics, IntMinOperations) +{ + TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntOperations) +{ + TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntMaxOperations) +{ + TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, FloatOperations) +{ + TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); +} + +TEST(SafeNumerics, DoubleOperations) +{ + TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); +} + +TEST(SafeNumerics, SizeTOperations) +{ + TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, CastTests) +{ +// MSVC catches and warns that we're forcing saturation in these tests. +// Since that's intentional, we need to shut this warning off. +#if defined(COMPILER_MSVC) +#pragma warning(disable : 4756) +#endif + + int small_positive = 1; + int small_negative = -1; + double double_small = 1.0; + double double_large = numeric_limits::max(); + double double_infinity = numeric_limits::infinity(); + double double_large_int = numeric_limits::max(); + double double_small_int = numeric_limits::min(); + + // Just test that the casts compile, since the other tests cover logic. + EXPECT_EQ(0, checked_cast(static_cast(0))); + EXPECT_EQ(0, strict_cast(static_cast(0))); + EXPECT_EQ(0, strict_cast(static_cast(0))); + EXPECT_EQ(0U, strict_cast(static_cast(0))); + EXPECT_EQ(1ULL, static_cast(StrictNumeric(1U))); + EXPECT_EQ(1ULL, static_cast(SizeT(1U))); + EXPECT_EQ(1U, static_cast(StrictNumeric(1U))); + + EXPECT_TRUE(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_TRUE(CheckedNumeric(StrictNumeric(1U)).IsValid()); + EXPECT_FALSE(CheckedNumeric(StrictNumeric(-1)).IsValid()); + + EXPECT_TRUE(IsValueNegative(-1)); + EXPECT_TRUE(IsValueNegative(numeric_limits::min())); + EXPECT_FALSE(IsValueNegative(numeric_limits::min())); + EXPECT_TRUE(IsValueNegative(-numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(0)); + EXPECT_FALSE(IsValueNegative(1)); + EXPECT_FALSE(IsValueNegative(0u)); + EXPECT_FALSE(IsValueNegative(1u)); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits::max())); + + // These casts and coercions will fail to compile: + // EXPECT_EQ(0, strict_cast(static_cast(0))); + // EXPECT_EQ(0, strict_cast(static_cast(0))); + // EXPECT_EQ(1ULL, StrictNumeric(1)); + // EXPECT_EQ(1, StrictNumeric(1U)); + + // Test various saturation corner cases. + EXPECT_EQ(saturated_cast(small_negative), static_cast(small_negative)); + EXPECT_EQ(saturated_cast(small_positive), static_cast(small_positive)); + EXPECT_EQ(saturated_cast(small_negative), static_cast(0)); + EXPECT_EQ(saturated_cast(double_small), static_cast(double_small)); + EXPECT_EQ(saturated_cast(double_large), numeric_limits::max()); + EXPECT_EQ(saturated_cast(double_large), double_infinity); + EXPECT_EQ(saturated_cast(-double_large), -double_infinity); + EXPECT_EQ(numeric_limits::min(), saturated_cast(double_small_int)); + EXPECT_EQ(numeric_limits::max(), saturated_cast(double_large_int)); + + float not_a_number = + std::numeric_limits::infinity() - std::numeric_limits::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_EQ(0, saturated_cast(not_a_number)); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, SaturatedCastChecks) +{ + float not_a_number = + std::numeric_limits::infinity() - std::numeric_limits::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_DEATH((saturated_cast(not_a_number)), ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, IsValueInRangeForNumericType) +{ + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_FALSE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_TRUE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_FALSE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_TRUE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()))); + EXPECT_FALSE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()) - 1)); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_FALSE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_FALSE(IsValueInRangeForNumericType(INT64_C(-1))); + EXPECT_FALSE(IsValueInRangeForNumericType(std::numeric_limits::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType(0)); + EXPECT_TRUE(IsValueInRangeForNumericType(1)); + EXPECT_TRUE(IsValueInRangeForNumericType(2)); + EXPECT_TRUE(IsValueInRangeForNumericType(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x7fffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(0x80000000u)); + EXPECT_TRUE(IsValueInRangeForNumericType(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x80000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType(INT64_C(0x7fffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(UINT64_C(0x7fffffffffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0x8000000000000000))); + EXPECT_FALSE(IsValueInRangeForNumericType(UINT64_C(0xffffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); + EXPECT_TRUE(IsValueInRangeForNumericType( + static_cast(std::numeric_limits::min()))); + EXPECT_TRUE(IsValueInRangeForNumericType(std::numeric_limits::min())); +} + +TEST(SafeNumerics, CompoundNumericOperations) +{ + CheckedNumeric a = 1; + CheckedNumeric b = 2; + CheckedNumeric c = 3; + CheckedNumeric d = 4; + a += b; + EXPECT_EQ(3, a.ValueOrDie()); + a -= c; + EXPECT_EQ(0, a.ValueOrDie()); + d /= b; + EXPECT_EQ(2, d.ValueOrDie()); + d *= d; + EXPECT_EQ(4, d.ValueOrDie()); + + CheckedNumeric too_large = std::numeric_limits::max(); + EXPECT_TRUE(too_large.IsValid()); + too_large += d; + EXPECT_FALSE(too_large.IsValid()); + too_large -= d; + EXPECT_FALSE(too_large.IsValid()); + too_large /= d; + EXPECT_FALSE(too_large.IsValid()); +} diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc new file mode 100644 index 0000000000..cb88ba06e1 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.cc @@ -0,0 +1,245 @@ +// Copyright (c) 2011 The Chromium 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 "anglebase/sha1.h" + +#include +#include +#include + +#include "anglebase/sys_byteorder.h" + +namespace angle +{ + +namespace base +{ + +// Implementation of SHA-1. Only handles data in byte-sized blocks, +// which simplifies the code a fair bit. + +// Identifier names follow notation in FIPS PUB 180-3, where you'll +// also find a description of the algorithm: +// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf + +// Usage example: +// +// SecureHashAlgorithm sha; +// while(there is data to hash) +// sha.Update(moredata, size of data); +// sha.Final(); +// memcpy(somewhere, sha.Digest(), 20); +// +// to reuse the instance of sha, call sha.Init(); + +// TODO(jhawkins): Replace this implementation with a per-platform +// implementation using each platform's crypto library. See +// http://crbug.com/47218 + +class SecureHashAlgorithm +{ + public: + SecureHashAlgorithm() { Init(); } + + static const int kDigestSizeBytes; + + void Init(); + void Update(const void *data, size_t nbytes); + void Final(); + + // 20 bytes of message digest. + const unsigned char *Digest() const { return reinterpret_cast(H); } + + private: + void Pad(); + void Process(); + + uint32_t A, B, C, D, E; + + uint32_t H[5]; + + union { + uint32_t W[80]; + uint8_t M[64]; + }; + + uint32_t cursor; + uint64_t l; +}; + +static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) +{ + if (t < 20) + { + return (B & C) | ((~B) & D); + } + else if (t < 40) + { + return B ^ C ^ D; + } + else if (t < 60) + { + return (B & C) | (B & D) | (C & D); + } + else + { + return B ^ C ^ D; + } +} + +static inline uint32_t S(uint32_t n, uint32_t X) +{ + return (X << n) | (X >> (32 - n)); +} + +static inline uint32_t K(uint32_t t) +{ + if (t < 20) + { + return 0x5a827999; + } + else if (t < 40) + { + return 0x6ed9eba1; + } + else if (t < 60) + { + return 0x8f1bbcdc; + } + else + { + return 0xca62c1d6; + } +} + +const int SecureHashAlgorithm::kDigestSizeBytes = 20; + +void SecureHashAlgorithm::Init() +{ + A = 0; + B = 0; + C = 0; + D = 0; + E = 0; + cursor = 0; + l = 0; + H[0] = 0x67452301; + H[1] = 0xefcdab89; + H[2] = 0x98badcfe; + H[3] = 0x10325476; + H[4] = 0xc3d2e1f0; +} + +void SecureHashAlgorithm::Final() +{ + Pad(); + Process(); + + for (int t = 0; t < 5; ++t) + H[t] = ByteSwap(H[t]); +} + +void SecureHashAlgorithm::Update(const void *data, size_t nbytes) +{ + const uint8_t *d = reinterpret_cast(data); + while (nbytes--) + { + M[cursor++] = *d++; + if (cursor >= 64) + Process(); + l += 8; + } +} + +void SecureHashAlgorithm::Pad() +{ + M[cursor++] = 0x80; + + if (cursor > 64 - 8) + { + // pad out to next block + while (cursor < 64) + M[cursor++] = 0; + + Process(); + } + + while (cursor < 64 - 8) + M[cursor++] = 0; + + M[cursor++] = (l >> 56) & 0xff; + M[cursor++] = (l >> 48) & 0xff; + M[cursor++] = (l >> 40) & 0xff; + M[cursor++] = (l >> 32) & 0xff; + M[cursor++] = (l >> 24) & 0xff; + M[cursor++] = (l >> 16) & 0xff; + M[cursor++] = (l >> 8) & 0xff; + M[cursor++] = l & 0xff; +} + +void SecureHashAlgorithm::Process() +{ + uint32_t t; + + // Each a...e corresponds to a section in the FIPS 180-3 algorithm. + + // a. + // + // W and M are in a union, so no need to memcpy. + // memcpy(W, M, sizeof(M)); + for (t = 0; t < 16; ++t) + W[t] = ByteSwap(W[t]); + + // b. + for (t = 16; t < 80; ++t) + W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + + // c. + A = H[0]; + B = H[1]; + C = H[2]; + D = H[3]; + E = H[4]; + + // d. + for (t = 0; t < 80; ++t) + { + uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); + E = D; + D = C; + C = S(30, B); + B = A; + A = TEMP; + } + + // e. + H[0] += A; + H[1] += B; + H[2] += C; + H[3] += D; + H[4] += E; + + cursor = 0; +} + +std::string SHA1HashString(const std::string &str) +{ + char hash[SecureHashAlgorithm::kDigestSizeBytes]; + SHA1HashBytes(reinterpret_cast(str.c_str()), str.length(), + reinterpret_cast(hash)); + return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes); +} + +void SHA1HashBytes(const unsigned char *data, size_t len, unsigned char *hash) +{ + SecureHashAlgorithm sha; + sha.Update(data, len); + sha.Final(); + + memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes); +} + +} // namespace base + +} // namespace angle diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h new file mode 100644 index 0000000000..a60908814f --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sha1.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium 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 ANGLEBASE_SHA1_H_ +#define ANGLEBASE_SHA1_H_ + +#include + +#include + +#include "anglebase/base_export.h" + +namespace angle +{ + +namespace base +{ + +// These functions perform SHA-1 operations. + +static const size_t kSHA1Length = 20; // Length in bytes of a SHA-1 hash. + +// Computes the SHA-1 hash of the input string |str| and returns the full +// hash. +ANGLEBASE_EXPORT std::string SHA1HashString(const std::string &str); + +// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash +// in |hash|. |hash| must be kSHA1Length bytes long. +ANGLEBASE_EXPORT void SHA1HashBytes(const unsigned char *data, size_t len, unsigned char *hash); + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_SHA1_H_ diff --git a/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h b/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h new file mode 100644 index 0000000000..43d1777f26 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/base/anglebase/sys_byteorder.h @@ -0,0 +1,49 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// sys_byteorder.h: Compatiblity hacks for importing Chromium's base/SHA1. + +#ifndef ANGLEBASE_SYS_BYTEORDER_H_ +#define ANGLEBASE_SYS_BYTEORDER_H_ + +namespace angle +{ + +namespace base +{ + +// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness. +inline uint16_t ByteSwap(uint16_t x) +{ +#if defined(_MSC_VER) + return _byteswap_ushort(x); +#else + return __builtin_bswap16(x); +#endif +} + +inline uint32_t ByteSwap(uint32_t x) +{ +#if defined(_MSC_VER) + return _byteswap_ulong(x); +#else + return __builtin_bswap32(x); +#endif +} + +inline uint64_t ByteSwap(uint64_t x) +{ +#if defined(_MSC_VER) + return _byteswap_uint64(x); +#else + return __builtin_bswap64(x); +#endif +} + +} // namespace base + +} // namespace angle + +#endif // ANGLEBASE_SYS_BYTEORDER_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/common/third_party/smhasher/LICENSE b/src/3rdparty/angle/src/common/third_party/smhasher/LICENSE new file mode 100644 index 0000000000..3f18a844ad --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/smhasher/LICENSE @@ -0,0 +1,23 @@ +All MurmurHash source files are placed in the public domain. + +The license below applies to all other code in SMHasher: + +Copyright (c) 2011 Google, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/3rdparty/angle/src/common/third_party/smhasher/README.angle b/src/3rdparty/angle/src/common/third_party/smhasher/README.angle new file mode 100644 index 0000000000..b84ea3249b --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/smhasher/README.angle @@ -0,0 +1,14 @@ +Name: SMHasher +URL: http://code.google.com/p/smhasher/ +Version: 0 +Revision: 147 +License: MIT, Public Domain +License File: LICENSE +Security Critical: yes + +Description: +This is a library containing the MurmurHash3 function, and a hashing function +test suite. + +Licenses are MIT (SMHasher) and Public Domain (MurmurHash). + diff --git a/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp b/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp new file mode 100644 index 0000000000..071bc31539 --- /dev/null +++ b/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp @@ -0,0 +1,320 @@ +/*----------------------------------------------------------------------------- + * MurmurHash3 was written by Austin Appleby, and is placed in the public + * domain. + * + * This implementation was written by Shane Day, and is also public domain. + * + * This is a portable ANSI C implementation of MurmurHash3_x86_32 (Murmur3A) + * with support for progressive processing. + */ + +/*----------------------------------------------------------------------------- + +If you want to understand the MurmurHash algorithm you would be much better +off reading the original source. Just point your browser at: +http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + + +What this version provides? + +1. Progressive data feeding. Useful when the entire payload to be hashed +does not fit in memory or when the data is streamed through the application. +Also useful when hashing a number of strings with a common prefix. A partial +hash of a prefix string can be generated and reused for each suffix string. + +2. Portability. Plain old C so that it should compile on any old compiler. +Both CPU endian and access-alignment neutral, but avoiding inefficient code +when possible depending on CPU capabilities. + +3. Drop in. I personally like nice self contained public domain code, making it +easy to pilfer without loads of refactoring to work properly in the existing +application code & makefile structure and mucking around with licence files. +Just copy PMurHash.h and PMurHash.c and you're ready to go. + + +How does it work? + +We can only process entire 32 bit chunks of input, except for the very end +that may be shorter. So along with the partial hash we need to give back to +the caller a carry containing up to 3 bytes that we were unable to process. +This carry also needs to record the number of bytes the carry holds. I use +the low 2 bits as a count (0..3) and the carry bytes are shifted into the +high byte in stream order. + +To handle endianess I simply use a macro that reads a uint32_t and define +that macro to be a direct read on little endian machines, a read and swap +on big endian machines, or a byte-by-byte read if the endianess is unknown. + +-----------------------------------------------------------------------------*/ + + +#include "PMurHash.h" + +/* I used ugly type names in the header to avoid potential conflicts with + * application or system typedefs & defines. Since I'm not including any more + * headers below here I can rename these so that the code reads like C99 */ +#undef uint32_t +#define uint32_t MH_UINT32 +#undef uint8_t +#define uint8_t MH_UINT8 + +/* MSVC warnings we choose to ignore */ +#if defined(_MSC_VER) + #pragma warning(disable: 4127) /* conditional expression is constant */ +#endif + +/*----------------------------------------------------------------------------- + * Endianess, misalignment capabilities and util macros + * + * The following 3 macros are defined in this section. The other macros defined + * are only needed to help derive these 3. + * + * READ_UINT32(x) Read a little endian unsigned 32-bit int + * UNALIGNED_SAFE Defined if READ_UINT32 works on non-word boundaries + * ROTL32(x,r) Rotate x left by r bits + */ + +/* Convention is to define __BYTE_ORDER == to one of these values */ +#if !defined(__BIG_ENDIAN) + #define __BIG_ENDIAN 4321 +#endif +#if !defined(__LITTLE_ENDIAN) + #define __LITTLE_ENDIAN 1234 +#endif + +/* I386 */ +#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(i386) + #define __BYTE_ORDER __LITTLE_ENDIAN + #define UNALIGNED_SAFE +#endif + +/* gcc 'may' define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ to 1 (Note the trailing __), + * or even _LITTLE_ENDIAN or _BIG_ENDIAN (Note the single _ prefix) */ +#if !defined(__BYTE_ORDER) + #if defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__==1 || defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN==1 + #define __BYTE_ORDER __LITTLE_ENDIAN + #elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 || defined(_BIG_ENDIAN) && _BIG_ENDIAN==1 + #define __BYTE_ORDER __BIG_ENDIAN + #endif +#endif + +/* gcc (usually) defines xEL/EB macros for ARM and MIPS endianess */ +#if !defined(__BYTE_ORDER) + #if defined(__ARMEL__) || defined(__MIPSEL__) + #define __BYTE_ORDER __LITTLE_ENDIAN + #endif + #if defined(__ARMEB__) || defined(__MIPSEB__) + #define __BYTE_ORDER __BIG_ENDIAN + #endif +#endif + +/* Now find best way we can to READ_UINT32 */ +#if __BYTE_ORDER==__LITTLE_ENDIAN + /* CPU endian matches murmurhash algorithm, so read 32-bit word directly */ + #define READ_UINT32(ptr) (*((uint32_t*)(ptr))) +#elif __BYTE_ORDER==__BIG_ENDIAN + /* TODO: Add additional cases below where a compiler provided bswap32 is available */ + #if defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3)) + #define READ_UINT32(ptr) (__builtin_bswap32(*((uint32_t*)(ptr)))) + #else + /* Without a known fast bswap32 we're just as well off doing this */ + #define READ_UINT32(ptr) (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24) + #define UNALIGNED_SAFE + #endif +#else + /* Unknown endianess so last resort is to read individual bytes */ + #define READ_UINT32(ptr) (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24) + + /* Since we're not doing word-reads we can skip the messing about with realignment */ + #define UNALIGNED_SAFE +#endif + +/* Find best way to ROTL32 */ +#if defined(_MSC_VER) + #include /* Microsoft put _rotl declaration in here */ + #define ROTL32(x,r) _rotl(x,r) +#else + /* gcc recognises this code and generates a rotate instruction for CPUs with one */ + #define ROTL32(x,r) (((uint32_t)x << r) | ((uint32_t)x >> (32 - r))) +#endif + + +/*----------------------------------------------------------------------------- + * Core murmurhash algorithm macros */ + +#define C1 (0xcc9e2d51) +#define C2 (0x1b873593) + +/* This is the main processing body of the algorithm. It operates + * on each full 32-bits of input. */ +#define DOBLOCK(h1, k1) do{ \ + k1 *= C1; \ + k1 = ROTL32(k1,15); \ + k1 *= C2; \ + \ + h1 ^= k1; \ + h1 = ROTL32(h1,13); \ + h1 = h1*5+0xe6546b64; \ + }while(0) + + +/* Append unaligned bytes to carry, forcing hash churn if we have 4 bytes */ +/* cnt=bytes to process, h1=name of h1 var, c=carry, n=bytes in c, ptr/len=payload */ +#define DOBYTES(cnt, h1, c, n, ptr, len) do{ \ + int _i = cnt; \ + while(_i--) { \ + c = c>>8 | *ptr++<<24; \ + n++; len--; \ + if(n==4) { \ + DOBLOCK(h1, c); \ + n = 0; \ + } \ + } }while(0) + +/*---------------------------------------------------------------------------*/ + +namespace angle +{ +/* Main hashing function. Initialise carry to 0 and h1 to 0 or an initial seed + * if wanted. Both ph1 and pcarry are required arguments. */ +void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int len) +{ + uint32_t h1 = *ph1; + uint32_t c = *pcarry; + + const uint8_t *ptr = (uint8_t*)key; + const uint8_t *end; + + /* Extract carry count from low 2 bits of c value */ + int n = c & 3; + +#if defined(UNALIGNED_SAFE) + /* This CPU handles unaligned word access */ + + /* Consume any carry bytes */ + int i = (4-n) & 3; + if(i && i <= len) { + DOBYTES(i, h1, c, n, ptr, len); + } + + /* Process 32-bit chunks */ + end = ptr + len/4*4; + for( ; ptr < end ; ptr+=4) { + uint32_t k1 = READ_UINT32(ptr); + DOBLOCK(h1, k1); + } + +#else /*UNALIGNED_SAFE*/ + /* This CPU does not handle unaligned word access */ + + /* Consume enough so that the next data byte is word aligned */ + int i = -(long)ptr & 3; + if(i && i <= len) { + DOBYTES(i, h1, c, n, ptr, len); + } + + /* We're now aligned. Process in aligned blocks. Specialise for each possible carry count */ + end = ptr + len/4*4; + switch(n) { /* how many bytes in c */ + case 0: /* c=[----] w=[3210] b=[3210]=w c'=[----] */ + for( ; ptr < end ; ptr+=4) { + uint32_t k1 = READ_UINT32(ptr); + DOBLOCK(h1, k1); + } + break; + case 1: /* c=[0---] w=[4321] b=[3210]=c>>24|w<<8 c'=[4---] */ + for( ; ptr < end ; ptr+=4) { + uint32_t k1 = c>>24; + c = READ_UINT32(ptr); + k1 |= c<<8; + DOBLOCK(h1, k1); + } + break; + case 2: /* c=[10--] w=[5432] b=[3210]=c>>16|w<<16 c'=[54--] */ + for( ; ptr < end ; ptr+=4) { + uint32_t k1 = c>>16; + c = READ_UINT32(ptr); + k1 |= c<<16; + DOBLOCK(h1, k1); + } + break; + case 3: /* c=[210-] w=[6543] b=[3210]=c>>8|w<<24 c'=[654-] */ + for( ; ptr < end ; ptr+=4) { + uint32_t k1 = c>>8; + c = READ_UINT32(ptr); + k1 |= c<<24; + DOBLOCK(h1, k1); + } + } +#endif /*UNALIGNED_SAFE*/ + + /* Advance over whole 32-bit chunks, possibly leaving 1..3 bytes */ + len -= len/4*4; + + /* Append any remaining bytes into carry */ + DOBYTES(len, h1, c, n, ptr, len); + + /* Copy out new running hash and carry */ + *ph1 = h1; + *pcarry = (c & ~0xff) | n; +} + +/*---------------------------------------------------------------------------*/ + +/* Finalize a hash. To match the original Murmur3A the total_length must be provided */ +uint32_t PMurHash32_Result(uint32_t h, uint32_t carry, uint32_t total_length) +{ + uint32_t k1; + int n = carry & 3; + if(n) { + k1 = carry >> (4-n)*8; + k1 *= C1; k1 = ROTL32(k1,15); k1 *= C2; h ^= k1; + } + h ^= total_length; + + /* fmix */ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +/*---------------------------------------------------------------------------*/ + +/* Murmur3A compatable all-at-once */ +uint32_t PMurHash32(uint32_t seed, const void *key, int len) +{ + uint32_t h1=seed, carry=0; + PMurHash32_Process(&h1, &carry, key, len); + return PMurHash32_Result(h1, carry, len); +} + +/*---------------------------------------------------------------------------*/ + +/* Provide an API suitable for smhasher */ +void PMurHash32_test(const void *key, int len, uint32_t seed, void *out) +{ + uint32_t h1=seed, carry=0; + const uint8_t *ptr = (uint8_t*)key; + const uint8_t *end = ptr + len; + +#if 0 /* Exercise the progressive processing */ + while(ptr < end) { + //const uint8_t *mid = ptr + rand()%(end-ptr)+1; + const uint8_t *mid = ptr + (rand()&0xF); + mid = mid= 199901L ) + #include + #define MH_UINT32 uint32_t +#endif + +/* Otherwise try testing against max value macros from limit.h */ +#if !defined(MH_UINT32) + #include + #if (USHRT_MAX == 0xffffffffUL) + #define MH_UINT32 unsigned short + #elif (UINT_MAX == 0xffffffffUL) + #define MH_UINT32 unsigned int + #elif (ULONG_MAX == 0xffffffffUL) + #define MH_UINT32 unsigned long + #endif +#endif + +#if !defined(MH_UINT32) + #error Unable to determine type name for unsigned 32-bit int +#endif + +/* I'm yet to work on a platform where 'unsigned char' is not 8 bits */ +#define MH_UINT8 unsigned char + + +/* ------------------------------------------------------------------------- */ +/* Prototypes */ + +namespace angle +{ +void PMurHash32_Process(MH_UINT32 *ph1, MH_UINT32 *pcarry, const void *key, int len); +MH_UINT32 PMurHash32_Result(MH_UINT32 h1, MH_UINT32 carry, MH_UINT32 total_length); +MH_UINT32 PMurHash32(MH_UINT32 seed, const void *key, int len); + +void PMurHash32_test(const void *key, int len, MH_UINT32 seed, void *out); +} diff --git a/src/3rdparty/angle/src/common/tls.cpp b/src/3rdparty/angle/src/common/tls.cpp index cb1b32d325..10a10252f4 100644 --- a/src/3rdparty/angle/src/common/tls.cpp +++ b/src/3rdparty/angle/src/common/tls.cpp @@ -56,7 +56,7 @@ TLSIndex CreateTLSIndex() #elif defined(ANGLE_PLATFORM_POSIX) // Create global pool key - if ((pthread_key_create(&index, NULL)) != 0) + if ((pthread_key_create(&index, nullptr)) != 0) { index = TLS_INVALID_INDEX; } @@ -133,7 +133,7 @@ void *GetTLSValue(TLSIndex index) assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); if (index == TLS_INVALID_INDEX) { - return NULL; + return nullptr; } #ifdef ANGLE_PLATFORM_WINDOWS diff --git a/src/3rdparty/angle/src/common/uniform_type_info_autogen.cpp b/src/3rdparty/angle/src/common/uniform_type_info_autogen.cpp new file mode 100644 index 0000000000..9c199128a4 --- /dev/null +++ b/src/3rdparty/angle/src/common/uniform_type_info_autogen.cpp @@ -0,0 +1,275 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_uniform_type_table.py. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Uniform type info table: +// Metadata about a particular uniform format, indexed by GL type. + +#include +#include "common/utilities.h" + +using namespace angle; + +namespace gl +{ + +namespace +{ +constexpr std::array kInfoTable = { + {{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, 0, 0, 0, 0, 0 * 0, 0 * 0, false, false, false}, + {GL_BOOL, GL_BOOL, GL_NONE, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, + sizeof(GLint) * 1, false, false, false}, + {GL_BOOL_VEC2, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC2, 1, 2, 2, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false}, + {GL_BOOL_VEC3, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC3, 1, 3, 3, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false}, + {GL_BOOL_VEC4, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC4, 1, 4, 4, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false}, + {GL_FLOAT, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL, 1, 1, 1, sizeof(GLfloat), sizeof(GLfloat) * 4, + sizeof(GLfloat) * 1, false, false, false}, + {GL_FLOAT_MAT2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2, GL_NONE, 2, 2, 4, sizeof(GLfloat), + sizeof(GLfloat) * 8, sizeof(GLfloat) * 4, false, true, false}, + {GL_FLOAT_MAT2x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x2, GL_NONE, 3, 2, 6, sizeof(GLfloat), + sizeof(GLfloat) * 12, sizeof(GLfloat) * 6, false, true, false}, + {GL_FLOAT_MAT2x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x2, GL_NONE, 4, 2, 8, sizeof(GLfloat), + sizeof(GLfloat) * 16, sizeof(GLfloat) * 8, false, true, false}, + {GL_FLOAT_MAT3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3, GL_NONE, 3, 3, 9, sizeof(GLfloat), + sizeof(GLfloat) * 12, sizeof(GLfloat) * 9, false, true, false}, + {GL_FLOAT_MAT3x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x3, GL_NONE, 2, 3, 6, sizeof(GLfloat), + sizeof(GLfloat) * 8, sizeof(GLfloat) * 6, false, true, false}, + {GL_FLOAT_MAT3x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x3, GL_NONE, 4, 3, 12, sizeof(GLfloat), + sizeof(GLfloat) * 16, sizeof(GLfloat) * 12, false, true, false}, + {GL_FLOAT_MAT4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4, GL_NONE, 4, 4, 16, sizeof(GLfloat), + sizeof(GLfloat) * 16, sizeof(GLfloat) * 16, false, true, false}, + {GL_FLOAT_MAT4x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x4, GL_NONE, 2, 4, 8, sizeof(GLfloat), + sizeof(GLfloat) * 8, sizeof(GLfloat) * 8, false, true, false}, + {GL_FLOAT_MAT4x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x4, GL_NONE, 3, 4, 12, sizeof(GLfloat), + sizeof(GLfloat) * 12, sizeof(GLfloat) * 12, false, true, false}, + {GL_FLOAT_VEC2, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC2, 1, 2, 2, sizeof(GLfloat), + sizeof(GLfloat) * 4, sizeof(GLfloat) * 2, false, false, false}, + {GL_FLOAT_VEC3, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC3, 1, 3, 3, sizeof(GLfloat), + sizeof(GLfloat) * 4, sizeof(GLfloat) * 3, false, false, false}, + {GL_FLOAT_VEC4, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC4, 1, 4, 4, sizeof(GLfloat), + sizeof(GLfloat) * 4, sizeof(GLfloat) * 4, false, false, false}, + {GL_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_INT, GL_INT, GL_NONE, GL_NONE, GL_BOOL, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, + sizeof(GLint) * 1, false, false, false}, + {GL_INT_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_INT_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_INT_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_INT_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true}, + {GL_INT_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_INT_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_INT_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_INT_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_INT_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_INT_VEC2, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2, 1, 2, 2, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false}, + {GL_INT_VEC3, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3, 1, 3, 3, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false}, + {GL_INT_VEC4, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4, 1, 4, 4, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false}, + {GL_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_2D_ARRAY_SHADOW, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_2D_RECT_ANGLE, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_2D_SHADOW, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_CUBE_SHADOW, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, sizeof(GLint), + sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_SAMPLER_EXTERNAL_OES, GL_INT, GL_TEXTURE_EXTERNAL_OES, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}, + {GL_UNSIGNED_INT, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL, 1, 1, 1, sizeof(GLuint), + sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, false}, + {GL_UNSIGNED_INT_ATOMIC_COUNTER, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, false}, + {GL_UNSIGNED_INT_IMAGE_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, true}, + {GL_UNSIGNED_INT_IMAGE_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, 1, + 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, true}, + {GL_UNSIGNED_INT_IMAGE_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, true}, + {GL_UNSIGNED_INT_IMAGE_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, true}, + {GL_UNSIGNED_INT_SAMPLER_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false}, + {GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, 1, + 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false}, + {GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, GL_UNSIGNED_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, + GL_NONE, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false}, + {GL_UNSIGNED_INT_SAMPLER_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false}, + {GL_UNSIGNED_INT_SAMPLER_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, 1, 1, 1, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false}, + {GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2, 1, 2, 2, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 2, false, false, false}, + {GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3, 1, 3, 3, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 3, false, false, false}, + {GL_UNSIGNED_INT_VEC4, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4, 1, 4, 4, + sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 4, false, false, false}}}; + +size_t GetTypeInfoIndex(GLenum uniformType) +{ + switch (uniformType) + { + case GL_NONE: + return 0; + case GL_BOOL: + return 1; + case GL_BOOL_VEC2: + return 2; + case GL_BOOL_VEC3: + return 3; + case GL_BOOL_VEC4: + return 4; + case GL_FLOAT: + return 5; + case GL_FLOAT_MAT2: + return 6; + case GL_FLOAT_MAT2x3: + return 7; + case GL_FLOAT_MAT2x4: + return 8; + case GL_FLOAT_MAT3: + return 9; + case GL_FLOAT_MAT3x2: + return 10; + case GL_FLOAT_MAT3x4: + return 11; + case GL_FLOAT_MAT4: + return 12; + case GL_FLOAT_MAT4x2: + return 13; + case GL_FLOAT_MAT4x3: + return 14; + case GL_FLOAT_VEC2: + return 15; + case GL_FLOAT_VEC3: + return 16; + case GL_FLOAT_VEC4: + return 17; + case GL_IMAGE_2D: + return 18; + case GL_IMAGE_2D_ARRAY: + return 19; + case GL_IMAGE_3D: + return 20; + case GL_IMAGE_CUBE: + return 21; + case GL_INT: + return 22; + case GL_INT_IMAGE_2D: + return 23; + case GL_INT_IMAGE_2D_ARRAY: + return 24; + case GL_INT_IMAGE_3D: + return 25; + case GL_INT_IMAGE_CUBE: + return 26; + case GL_INT_SAMPLER_2D: + return 27; + case GL_INT_SAMPLER_2D_ARRAY: + return 28; + case GL_INT_SAMPLER_2D_MULTISAMPLE: + return 29; + case GL_INT_SAMPLER_3D: + return 30; + case GL_INT_SAMPLER_CUBE: + return 31; + case GL_INT_VEC2: + return 32; + case GL_INT_VEC3: + return 33; + case GL_INT_VEC4: + return 34; + case GL_SAMPLER_2D: + return 35; + case GL_SAMPLER_2D_ARRAY: + return 36; + case GL_SAMPLER_2D_ARRAY_SHADOW: + return 37; + case GL_SAMPLER_2D_MULTISAMPLE: + return 38; + case GL_SAMPLER_2D_RECT_ANGLE: + return 39; + case GL_SAMPLER_2D_SHADOW: + return 40; + case GL_SAMPLER_3D: + return 41; + case GL_SAMPLER_CUBE: + return 42; + case GL_SAMPLER_CUBE_SHADOW: + return 43; + case GL_SAMPLER_EXTERNAL_OES: + return 44; + case GL_UNSIGNED_INT: + return 45; + case GL_UNSIGNED_INT_ATOMIC_COUNTER: + return 46; + case GL_UNSIGNED_INT_IMAGE_2D: + return 47; + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + return 48; + case GL_UNSIGNED_INT_IMAGE_3D: + return 49; + case GL_UNSIGNED_INT_IMAGE_CUBE: + return 50; + case GL_UNSIGNED_INT_SAMPLER_2D: + return 51; + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + return 52; + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + return 53; + case GL_UNSIGNED_INT_SAMPLER_3D: + return 54; + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return 55; + case GL_UNSIGNED_INT_VEC2: + return 56; + case GL_UNSIGNED_INT_VEC3: + return 57; + case GL_UNSIGNED_INT_VEC4: + return 58; + default: + UNREACHABLE(); + return 0; + } +} +} // anonymous namespace + +const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType) +{ + ASSERT(kInfoTable[GetTypeInfoIndex(uniformType)].type == uniformType); + return kInfoTable[GetTypeInfoIndex(uniformType)]; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp index 2ab913b10f..6dae9cc51f 100644 --- a/src/3rdparty/angle/src/common/utilities.cpp +++ b/src/3rdparty/angle/src/common/utilities.cpp @@ -124,24 +124,42 @@ GLenum VariableComponentType(GLenum type) return GL_FLOAT; case GL_INT: case GL_SAMPLER_2D: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_INT_VEC2: case GL_INT_VEC3: case GL_INT_VEC4: - return GL_INT; + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_ATOMIC_COUNTER: + return GL_INT; case GL_UNSIGNED_INT: case GL_UNSIGNED_INT_VEC2: case GL_UNSIGNED_INT_VEC3: @@ -211,7 +229,6 @@ int VariableRowCount(GLenum type) switch (type) { case GL_NONE: - case GL_STRUCT_ANGLEX: return 0; case GL_BOOL: case GL_FLOAT: @@ -234,19 +251,35 @@ int VariableRowCount(GLenum type) case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: + case GL_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: - return 1; + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_ATOMIC_COUNTER: + return 1; case GL_FLOAT_MAT2: case GL_FLOAT_MAT3x2: case GL_FLOAT_MAT4x2: @@ -271,7 +304,6 @@ int VariableColumnCount(GLenum type) switch (type) { case GL_NONE: - case GL_STRUCT_ANGLEX: return 0; case GL_BOOL: case GL_FLOAT: @@ -281,20 +313,36 @@ int VariableColumnCount(GLenum type) case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: - return 1; + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_ATOMIC_COUNTER: + return 1; case GL_BOOL_VEC2: case GL_FLOAT_VEC2: case GL_INT_VEC2: @@ -334,14 +382,19 @@ bool IsSamplerType(GLenum type) case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: @@ -351,6 +404,38 @@ bool IsSamplerType(GLenum type) return false; } +bool IsImageType(GLenum type) +{ + switch (type) + { + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + return true; + } + return false; +} + +bool IsAtomicCounterType(GLenum type) +{ + return type == GL_UNSIGNED_INT_ATOMIC_COUNTER; +} + +bool IsOpaqueType(GLenum type) +{ + // ESSL 3.10 section 4.1.7 defines opaque types as: samplers, images and atomic counters. + return IsImageType(type) || IsSamplerType(type) || IsAtomicCounterType(type); +} + GLenum SamplerTypeToTextureType(GLenum samplerType) { switch (samplerType) @@ -361,6 +446,9 @@ GLenum SamplerTypeToTextureType(GLenum samplerType) case GL_SAMPLER_2D_SHADOW: return GL_TEXTURE_2D; + case GL_SAMPLER_EXTERNAL_OES: + return GL_TEXTURE_EXTERNAL_OES; + case GL_SAMPLER_CUBE: case GL_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_CUBE: @@ -378,6 +466,14 @@ GLenum SamplerTypeToTextureType(GLenum samplerType) case GL_UNSIGNED_INT_SAMPLER_3D: return GL_TEXTURE_3D; + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + return GL_TEXTURE_2D_MULTISAMPLE; + + case GL_SAMPLER_2D_RECT_ANGLE: + return GL_TEXTURE_RECTANGLE_ANGLE; + default: UNREACHABLE(); return 0; @@ -531,6 +627,21 @@ bool IsTriangleMode(GLenum drawMode) return false; } +bool IsIntegerFormat(GLenum unsizedFormat) +{ + switch (unsizedFormat) + { + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_RED_INTEGER: + return true; + + default: + return false; + } +} + // [OpenGL ES SL 3.00.4] Section 11 p. 120 // Vertex Outs/Fragment Ins packing priorities int VariableSortOrder(GLenum type) @@ -586,21 +697,37 @@ int VariableSortOrder(GLenum type) case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_3D: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_CUBE_SHADOW: - return 6; + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_ATOMIC_COUNTER: + return 6; default: UNREACHABLE(); @@ -608,51 +735,128 @@ int VariableSortOrder(GLenum type) } } -std::string ParseUniformName(const std::string &name, size_t *outSubscript) +std::string ParseResourceName(const std::string &name, std::vector *outSubscripts) { - // 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 (outSubscripts) { - if (outSubscript) + outSubscripts->clear(); + } + // Strip any trailing array indexing operators and retrieve the subscripts. + size_t baseNameLength = name.length(); + bool hasIndex = true; + while (hasIndex) + { + size_t open = name.find_last_of('[', baseNameLength - 1); + size_t close = name.find_last_of(']', baseNameLength - 1); + hasIndex = (open != std::string::npos) && (close == baseNameLength - 1); + if (hasIndex) { - *outSubscript = GL_INVALID_INDEX; + baseNameLength = open; + if (outSubscripts) + { + int index = atoi(name.substr(open + 1).c_str()); + if (index >= 0) + { + outSubscripts->push_back(index); + } + else + { + outSubscripts->push_back(GL_INVALID_INDEX); + } + } } - return name; } - if (outSubscript) + return name.substr(0, baseNameLength); +} + +unsigned int ArraySizeProduct(const std::vector &arraySizes) +{ + unsigned int arraySizeProduct = 1u; + for (unsigned int arraySize : arraySizes) + { + arraySizeProduct *= arraySize; + } + return arraySizeProduct; +} + +unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut) +{ + ASSERT(nameLengthWithoutArrayIndexOut != nullptr); + + // Strip any trailing array operator and retrieve the subscript + size_t open = name.find_last_of('['); + if (open != std::string::npos && name.back() == ']') { - int index = atoi(name.substr(open + 1).c_str()); - if (index >= 0) + bool indexIsValidDecimalNumber = true; + for (size_t i = open + 1; i < name.length() - 1u; ++i) { - *outSubscript = index; + if (!isdigit(name[i])) + { + indexIsValidDecimalNumber = false; + break; + } } - else + if (indexIsValidDecimalNumber) { - *outSubscript = GL_INVALID_INDEX; + errno = 0; // reset global error flag. + unsigned long subscript = + strtoul(name.c_str() + open + 1, /*endptr*/ nullptr, /*radix*/ 10); + + // Check if resulting integer is out-of-range or conversion error. + if ((subscript <= static_cast(UINT_MAX)) && + !(subscript == ULONG_MAX && errno == ERANGE) && !(errno != 0 && subscript == 0)) + { + *nameLengthWithoutArrayIndexOut = open; + return static_cast(subscript); + } } } - return name.substr(0, open); + *nameLengthWithoutArrayIndexOut = name.length(); + return GL_INVALID_INDEX; } -unsigned int ParseAndStripArrayIndex(std::string *name) +const char *GetGenericErrorMessage(GLenum error) { - 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) + switch (error) { - subscript = atoi(name->c_str() + open + 1); - name->erase(open); + case GL_NO_ERROR: + return ""; + case GL_INVALID_ENUM: + return "Invalid enum."; + case GL_INVALID_VALUE: + return "Invalid value."; + case GL_INVALID_OPERATION: + return "Invalid operation."; + case GL_STACK_OVERFLOW: + return "Stack overflow."; + case GL_STACK_UNDERFLOW: + return "Stack underflow."; + case GL_OUT_OF_MEMORY: + return "Out of memory."; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "Invalid framebuffer operation."; + default: + UNREACHABLE(); + return "Unknown error."; } +} - return subscript; +unsigned int ElementTypeSize(GLenum elementType) +{ + switch (elementType) + { + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + default: + UNREACHABLE(); + return 0; + } } } // namespace gl @@ -710,8 +914,53 @@ bool IsRenderbufferTarget(EGLenum target) { return target == EGL_GL_RENDERBUFFER_KHR; } + +const char *GetGenericErrorMessage(EGLint error) +{ + switch (error) + { + case EGL_SUCCESS: + return ""; + case EGL_NOT_INITIALIZED: + return "Not initialized."; + case EGL_BAD_ACCESS: + return "Bad access."; + case EGL_BAD_ALLOC: + return "Bad allocation."; + case EGL_BAD_ATTRIBUTE: + return "Bad attribute."; + case EGL_BAD_CONFIG: + return "Bad config."; + case EGL_BAD_CONTEXT: + return "Bad context."; + case EGL_BAD_CURRENT_SURFACE: + return "Bad current surface."; + case EGL_BAD_DISPLAY: + return "Bad display."; + case EGL_BAD_MATCH: + return "Bad match."; + case EGL_BAD_NATIVE_WINDOW: + return "Bad native window."; + case EGL_BAD_PARAMETER: + return "Bad parameter."; + case EGL_BAD_SURFACE: + return "Bad surface."; + case EGL_CONTEXT_LOST: + return "Context lost."; + case EGL_BAD_STREAM_KHR: + return "Bad stream."; + case EGL_BAD_STATE_KHR: + return "Bad state."; + case EGL_BAD_DEVICE_EXT: + return "Bad device."; + default: + UNREACHABLE(); + return "Unknown error."; + } } +} // namespace egl + namespace egl_gl { GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget) @@ -748,7 +997,26 @@ GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer) { return static_cast(reinterpret_cast(buffer)); } +} // namespace egl_gl + +namespace gl_egl +{ +EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType) +{ + switch (glComponentType) + { + case GL_FLOAT: + return EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT; + + case GL_UNSIGNED_NORMALIZED: + return EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; + + default: + UNREACHABLE(); + return EGL_NONE; + } } +} // namespace gl_egl #if !defined(ANGLE_ENABLE_WINDOWS_STORE) std::string getTempPath() diff --git a/src/3rdparty/angle/src/common/utilities.h b/src/3rdparty/angle/src/common/utilities.h index dc09011a26..f2f9c63d0e 100644 --- a/src/3rdparty/angle/src/common/utilities.h +++ b/src/3rdparty/angle/src/common/utilities.h @@ -12,9 +12,10 @@ #include #include -#include "angle_gl.h" -#include #include +#include +#include +#include "angle_gl.h" #include "common/mathutil.h" @@ -26,10 +27,12 @@ GLenum VariableComponentType(GLenum type); size_t VariableComponentSize(GLenum type); size_t VariableInternalSize(GLenum type); size_t VariableExternalSize(GLenum type); -GLenum VariableBoolVectorType(GLenum type); int VariableRowCount(GLenum type); int VariableColumnCount(GLenum type); bool IsSamplerType(GLenum type); +bool IsImageType(GLenum type); +bool IsAtomicCounterType(GLenum type); +bool IsOpaqueType(GLenum type); GLenum SamplerTypeToTextureType(GLenum samplerType); bool IsMatrixType(GLenum type); GLenum TransposeMatrixType(GLenum type); @@ -37,6 +40,7 @@ int VariableRegisterCount(GLenum type); int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix); int MatrixComponentCount(GLenum type, bool isRowMajorMatrix); int VariableSortOrder(GLenum type); +GLenum VariableBoolVectorType(GLenum type); int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); @@ -46,9 +50,12 @@ 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); +// Parse the base resource name and array indices. Returns the base name of the resource. +// If the provided name doesn't index an array, the outSubscripts vector will be empty. +// If the provided name indexes an array, the outSubscripts vector will contain indices with +// outermost array indices in the back. If an array index is invalid, GL_INVALID_INDEX is added to +// outSubscripts. +std::string ParseResourceName(const std::string &name, std::vector *outSubscripts); // 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. @@ -61,14 +68,71 @@ IndexRange ComputeIndexRange(GLenum indexType, GLuint GetPrimitiveRestartIndex(GLenum indexType); bool IsTriangleMode(GLenum drawMode); +bool IsIntegerFormat(GLenum unsizedFormat); -// [OpenGL ES 3.0.2] Section 2.3.1 page 14 -// Data Conversion For State-Setting Commands -// Floating-point values are rounded to the nearest integer, instead of truncated, as done by static_cast. -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); } +// Returns the product of the sizes in the vector, or 1 if the vector is empty. Doesn't currently +// perform overflow checks. +unsigned int ArraySizeProduct(const std::vector &arraySizes); -unsigned int ParseAndStripArrayIndex(std::string *name); +// Return the array index at the end of name, and write the length of name before the final array +// index into nameLengthWithoutArrayIndexOut. In case name doesn't include an array index, return +// GL_INVALID_INDEX and write the length of the original string. +unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut); + +struct UniformTypeInfo final : angle::NonCopyable +{ + constexpr UniformTypeInfo(GLenum type, + GLenum componentType, + GLenum samplerTextureType, + GLenum transposedMatrixType, + GLenum boolVectorType, + int rowCount, + int columnCount, + int componentCount, + size_t componentSize, + size_t internalSize, + size_t externalSize, + bool isSampler, + bool isMatrixType, + bool isImageType) + : type(type), + componentType(componentType), + samplerTextureType(samplerTextureType), + transposedMatrixType(transposedMatrixType), + boolVectorType(boolVectorType), + rowCount(rowCount), + columnCount(columnCount), + componentCount(componentCount), + componentSize(componentSize), + internalSize(internalSize), + externalSize(externalSize), + isSampler(isSampler), + isMatrixType(isMatrixType), + isImageType(isImageType) + { + } + + GLenum type; + GLenum componentType; + GLenum samplerTextureType; + GLenum transposedMatrixType; + GLenum boolVectorType; + int rowCount; + int columnCount; + int componentCount; + size_t componentSize; + size_t internalSize; + size_t externalSize; + bool isSampler; + bool isMatrixType; + bool isImageType; +}; + +const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType); + +const char *GetGenericErrorMessage(GLenum error); + +unsigned int ElementTypeSize(GLenum elementType); } // namespace gl @@ -81,7 +145,9 @@ size_t CubeMapTextureTargetToLayerIndex(EGLenum target); EGLenum LayerIndexToCubeMapTextureTarget(size_t index); bool IsTextureTarget(EGLenum target); bool IsRenderbufferTarget(EGLenum target); -} + +const char *GetGenericErrorMessage(EGLint error); +} // namespace egl namespace egl_gl { @@ -90,6 +156,11 @@ GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget); GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer); } +namespace gl_egl +{ +EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType); +} // namespace gl_egl + #if !defined(ANGLE_ENABLE_WINDOWS_STORE) std::string getTempPath(); void writeFile(const char* path, const void* data, size_t size); diff --git a/src/3rdparty/angle/src/common/vector_utils.h b/src/3rdparty/angle/src/common/vector_utils.h new file mode 100644 index 0000000000..9f5bee1a4a --- /dev/null +++ b/src/3rdparty/angle/src/common/vector_utils.h @@ -0,0 +1,523 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// vector_utils.h: Utility classes implementing various vector operations + +#ifndef COMMON_VECTOR_UTILS_H_ +#define COMMON_VECTOR_UTILS_H_ + +#include +#include +#include +#include + +namespace angle +{ + +template +class Vector; + +using Vector2 = Vector<2, float>; +using Vector3 = Vector<3, float>; +using Vector4 = Vector<4, float>; + +using Vector2I = Vector<2, int>; +using Vector3I = Vector<3, int>; +using Vector4I = Vector<4, int>; + +using Vector2U = Vector<2, unsigned int>; +using Vector3U = Vector<3, unsigned int>; +using Vector4U = Vector<4, unsigned int>; + +template +class VectorBase +{ + public: + using VectorN = Vector; + + // Constructors + VectorBase() = default; + explicit VectorBase(Type element); + + template + VectorBase(const VectorBase &other); + + template + VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args); + + // Access the vector backing storage directly + const Type *data() const { return mData; } + Type *data() { return mData; } + constexpr size_t size() const { return Dimension; } + + // Load or store the pointer from / to raw data + static VectorN Load(const Type *source); + static void Store(const VectorN &source, Type *destination); + + // Index the vector + Type &operator[](size_t i) { return mData[i]; } + const Type &operator[](size_t i) const { return mData[i]; } + + // Basic arithmetic operations + VectorN operator+() const; + VectorN operator-() const; + VectorN operator+(const VectorN &other) const; + VectorN operator-(const VectorN &other) const; + VectorN operator*(const VectorN &other) const; + VectorN operator/(const VectorN &other) const; + VectorN operator*(Type other) const; + VectorN operator/(Type other) const; + friend VectorN operator*(Type a, const VectorN &b) { return b * a; } + + // Compound arithmetic operations + VectorN &operator+=(const VectorN &other); + VectorN &operator-=(const VectorN &other); + VectorN &operator*=(const VectorN &other); + VectorN &operator/=(const VectorN &other); + VectorN &operator*=(Type other); + VectorN &operator/=(Type other); + + // Comparison operators + bool operator==(const VectorN &other) const; + bool operator!=(const VectorN &other) const; + + // Other arithmetic operations + Type length() const; + Type lengthSquared() const; + Type dot(const VectorBase &other) const; + VectorN normalized() const; + + protected: + template + void initWithList(const Vector &arg1, const Args &... args); + + // Some old compilers consider this function an alternative for initWithList(Vector) + // when the variant above is more precise. Use SFINAE on the return value to hide + // this variant for non-arithmetic types. The return value is still void. + template + typename std::enable_if::value>::type initWithList( + OtherType arg1, + const Args &... args); + + template + void initWithList() const; + + template + friend class VectorBase; + + Type mData[Dimension]; +}; + +template +std::ostream &operator<<(std::ostream &ostream, const VectorBase &vector); + +template +class Vector<2, Type> : public VectorBase<2, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<2, Type>::VectorBase; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } +}; + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector); + +template +class Vector<3, Type> : public VectorBase<3, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<3, Type>::VectorBase; + + // Additional operations + Vector<3, Type> cross(const Vector<3, Type> &other) const; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + Type &z() { return this->mData[2]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } + const Type &z() const { return this->mData[2]; } +}; + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector); + +template +class Vector<4, Type> : public VectorBase<4, Type> +{ + public: + // Import the constructors defined in VectorBase + using VectorBase<4, Type>::VectorBase; + + // Element shorthands + Type &x() { return this->mData[0]; } + Type &y() { return this->mData[1]; } + Type &z() { return this->mData[2]; } + Type &w() { return this->mData[3]; } + + const Type &x() const { return this->mData[0]; } + const Type &y() const { return this->mData[1]; } + const Type &z() const { return this->mData[2]; } + const Type &w() const { return this->mData[3]; } +}; + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector); + +// Implementation of constructors and misc operations + +template +VectorBase::VectorBase(Type element) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] = element; + } +} + +template +template +VectorBase::VectorBase(const VectorBase &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] = static_cast(other.mData[i]); + } +} + +// Ideally we would like to have only two constructors: +// - a scalar constructor that takes Type as a parameter +// - a compound constructor +// However if we define the compound constructor for when it has a single arguments, then calling +// Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound +// constructor with a single argument, which is the copy constructor. We end up with three +// constructors: +// - the scalar constructor +// - the copy constructor +// - the compound constructor for two or more arguments, hence the arg1, and arg2 here. +template +template +VectorBase::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args) +{ + initWithList<0>(arg1, arg2, args...); +} + +template +template +void VectorBase::initWithList(const Vector &arg1, + const Args &... args) +{ + static_assert(CurrentIndex + OtherDimension <= Dimension, + "Too much data in the vector constructor."); + for (size_t i = 0; i < OtherDimension; ++i) + { + mData[CurrentIndex + i] = static_cast(arg1.mData[i]); + } + initWithList(args...); +} + +template +template +typename std::enable_if::value>::type +VectorBase::initWithList(OtherType arg1, const Args &... args) +{ + static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor."); + mData[CurrentIndex] = static_cast(arg1); + initWithList(args...); +} + +template +template +void VectorBase::initWithList() const +{ + static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor."); +} + +template +Vector VectorBase::Load(const Type *source) +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = source[i]; + } + return result; +} + +template +void VectorBase::Store(const Vector &source, Type *destination) +{ + for (size_t i = 0; i < Dimension; ++i) + { + destination[i] = source.mData[i]; + } +} + +// Implementation of basic arithmetic operations +template +Vector VectorBase::operator+() const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = +mData[i]; + } + return result; +} + +template +Vector VectorBase::operator-() const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = -mData[i]; + } + return result; +} + +template +Vector VectorBase::operator+( + const Vector &other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] + other.mData[i]; + } + return result; +} + +template +Vector VectorBase::operator-( + const Vector &other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] - other.mData[i]; + } + return result; +} + +template +Vector VectorBase::operator*( + const Vector &other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] * other.mData[i]; + } + return result; +} + +template +Vector VectorBase::operator/( + const Vector &other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] / other.mData[i]; + } + return result; +} + +template +Vector VectorBase::operator*(Type other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] * other; + } + return result; +} + +template +Vector VectorBase::operator/(Type other) const +{ + Vector result; + for (size_t i = 0; i < Dimension; ++i) + { + result.mData[i] = mData[i] / other; + } + return result; +} + +// Implementation of compound arithmetic operations +template +Vector &VectorBase::operator+=( + const Vector &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] += other.mData[i]; + } + return *reinterpret_cast *>(this); +} + +template +Vector &VectorBase::operator-=( + const Vector &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] -= other.mData[i]; + } + return *reinterpret_cast *>(this); +} + +template +Vector &VectorBase::operator*=( + const Vector &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] *= other.mData[i]; + } + return *reinterpret_cast *>(this); +} + +template +Vector &VectorBase::operator/=( + const Vector &other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] /= other.mData[i]; + } + return *reinterpret_cast *>(this); +} + +template +Vector &VectorBase::operator*=(Type other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] *= other; + } + return *reinterpret_cast *>(this); +} + +template +Vector &VectorBase::operator/=(Type other) +{ + for (size_t i = 0; i < Dimension; ++i) + { + mData[i] /= other; + } + return *reinterpret_cast *>(this); +} + +// Implementation of comparison operators +template +bool VectorBase::operator==(const Vector &other) const +{ + for (size_t i = 0; i < Dimension; ++i) + { + if (mData[i] != other.mData[i]) + { + return false; + } + } + return true; +} + +template +bool VectorBase::operator!=(const Vector &other) const +{ + return !(*this == other); +} + +// Implementation of other arithmetic operations +template +Type VectorBase::length() const +{ + static_assert(std::is_floating_point::value, + "VectorN::length is only defined for floating point vectors"); + return std::sqrt(lengthSquared()); +} + +template +Type VectorBase::lengthSquared() const +{ + return dot(*this); +} + +template +Type VectorBase::dot(const VectorBase &other) const +{ + Type sum = Type(); + for (size_t i = 0; i < Dimension; ++i) + { + sum += mData[i] * other.mData[i]; + } + return sum; +} + +template +std::ostream &operator<<(std::ostream &ostream, const VectorBase &vector) +{ + ostream << "[ "; + for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++) + { + if (elementIdx > 0) + { + ostream << ", "; + } + ostream << vector.data()[elementIdx]; + } + ostream << " ]"; + return ostream; +} + +template +Vector VectorBase::normalized() const +{ + static_assert(std::is_floating_point::value, + "VectorN::normalized is only defined for floating point vectors"); + return *this / length(); +} + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector) +{ + return ostream << static_cast &>(vector); +} + +template +Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const +{ + return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), + x() * other.y() - y() * other.x()); +} + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector) +{ + return ostream << static_cast &>(vector); +} + +template +std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector) +{ + return ostream << static_cast &>(vector); +} + +} // namespace angle + +#endif // COMMON_VECTOR_UTILS_H_ diff --git a/src/3rdparty/angle/src/compiler/fuzz/translator_fuzzer.cpp b/src/3rdparty/angle/src/compiler/fuzz/translator_fuzzer.cpp new file mode 100644 index 0000000000..910af8be6f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/fuzz/translator_fuzzer.cpp @@ -0,0 +1,179 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// translator_fuzzer.cpp: A libfuzzer fuzzer for the shader translator. + +#include +#include +#include +#include +#include + +#include "angle_gl.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/util.h" + +using namespace sh; + +struct TranslatorCacheKey +{ + bool operator==(const TranslatorCacheKey &other) const + { + return type == other.type && spec == other.spec && output == other.output; + } + + uint32_t type = 0; + uint32_t spec = 0; + uint32_t output = 0; +}; + +namespace std +{ + +template <> +struct hash +{ + std::size_t operator()(const TranslatorCacheKey &k) const + { + return (hash()(k.type) << 1) ^ (hash()(k.spec) >> 1) ^ + hash()(k.output); + } +}; +} // namespace std + +struct TCompilerDeleter +{ + void operator()(TCompiler *compiler) const { DeleteCompiler(compiler); } +}; + +using UniqueTCompiler = std::unique_ptr; + +static std::unordered_map translators; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + // Reserve some size for future compile options + const size_t kHeaderSize = 128; + + if (size <= kHeaderSize) + { + return 0; + } + + // Make sure the rest of data will be a valid C string so that we don't have to copy it. + if (data[size - 1] != 0) + { + return 0; + } + + uint32_t type = *reinterpret_cast(data); + uint32_t spec = *reinterpret_cast(data + 4); + uint32_t output = *reinterpret_cast(data + 8); + uint64_t options = *reinterpret_cast(data + 12); + + if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER) + { + return 0; + } + + if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC && + spec != SH_WEBGL2_SPEC) + { + return 0; + } + + ShShaderOutput shaderOutput = static_cast(output); + if (!(IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)) && + (options & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u) + { + // This compiler option is only available in ESSL and GLSL. + return 0; + } + + std::vector validOutputs; + validOutputs.push_back(SH_ESSL_OUTPUT); + validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT); + validOutputs.push_back(SH_GLSL_130_OUTPUT); + validOutputs.push_back(SH_GLSL_140_OUTPUT); + validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT); + validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT); + validOutputs.push_back(SH_HLSL_3_0_OUTPUT); + validOutputs.push_back(SH_HLSL_4_1_OUTPUT); + validOutputs.push_back(SH_HLSL_4_0_FL9_3_OUTPUT); + bool found = false; + for (auto valid : validOutputs) + { + found = found || (valid == output); + } + if (!found) + { + return 0; + } + + size -= kHeaderSize; + data += kHeaderSize; + + if (!sh::Initialize()) + { + return 0; + } + + TranslatorCacheKey key; + key.type = type; + key.spec = spec; + key.output = output; + + if (translators.find(key) == translators.end()) + { + UniqueTCompiler translator( + ConstructCompiler(type, static_cast(spec), shaderOutput)); + + if (translator == nullptr) + { + return 0; + } + + ShBuiltInResources resources; + sh::InitBuiltInResources(&resources); + + // Enable all the extensions to have more coverage + resources.OES_standard_derivatives = 1; + resources.OES_EGL_image_external = 1; + resources.OES_EGL_image_external_essl3 = 1; + resources.NV_EGL_stream_consumer_external = 1; + resources.ARB_texture_rectangle = 1; + resources.EXT_blend_func_extended = 1; + resources.EXT_draw_buffers = 1; + resources.EXT_frag_depth = 1; + resources.EXT_shader_texture_lod = 1; + resources.WEBGL_debug_shader_precision = 1; + resources.EXT_shader_framebuffer_fetch = 1; + resources.NV_shader_framebuffer_fetch = 1; + resources.ARM_shader_framebuffer_fetch = 1; + resources.EXT_YUV_target = 1; + resources.MaxDualSourceDrawBuffers = 1; + + if (!translator->Init(resources)) + { + return 0; + } + + translators[key] = std::move(translator); + } + + auto &translator = translators[key]; + + const char *shaderStrings[] = {reinterpret_cast(data)}; + translator->compile(shaderStrings, 1, options); + + return 0; +} diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp index 68c6e9cea4..c89bc9fa76 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.cpp @@ -4,9 +4,9 @@ // found in the LICENSE file. // -#include "DiagnosticsBase.h" +#include "compiler/preprocessor/DiagnosticsBase.h" -#include +#include "common/debug.h" namespace pp { @@ -15,122 +15,128 @@ Diagnostics::~Diagnostics() { } -void Diagnostics::report(ID id, - const SourceLocation &loc, - const std::string &text) +void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text) { - // TODO(alokp): Keep a count of errors and warnings. print(id, loc, text); } -Diagnostics::Severity Diagnostics::severity(ID id) +bool Diagnostics::isError(ID id) { if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END)) - return PP_ERROR; + return true; if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END)) - return PP_WARNING; + return false; - assert(false); - return PP_ERROR; + UNREACHABLE(); + return true; } -std::string Diagnostics::message(ID id) +const char *Diagnostics::message(ID id) { switch (id) { - // Errors begin. - case PP_INTERNAL_ERROR: - return "internal error"; - case PP_OUT_OF_MEMORY: - return "out of memory"; - case PP_INVALID_CHARACTER: - return "invalid character"; - case PP_INVALID_NUMBER: - return "invalid number"; - case PP_INTEGER_OVERFLOW: - return "integer overflow"; - case PP_FLOAT_OVERFLOW: - return "float overflow"; - case PP_TOKEN_TOO_LONG: - return "token too long"; - case PP_INVALID_EXPRESSION: - return "invalid expression"; - case PP_DIVISION_BY_ZERO: - return "division by zero"; - case PP_EOF_IN_COMMENT: - return "unexpected end of file found in comment"; - case PP_UNEXPECTED_TOKEN: - return "unexpected token"; - case PP_DIRECTIVE_INVALID_NAME: - return "invalid directive name"; - case PP_MACRO_NAME_RESERVED: - return "macro name is reserved"; - case PP_MACRO_REDEFINED: - return "macro redefined"; - case PP_MACRO_PREDEFINED_REDEFINED: - return "predefined macro redefined"; - case PP_MACRO_PREDEFINED_UNDEFINED: - return "predefined macro undefined"; - case PP_MACRO_UNTERMINATED_INVOCATION: - return "unterminated macro invocation"; - case PP_MACRO_TOO_FEW_ARGS: - 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: - return "unexpected #else found without a matching #if"; - case PP_CONDITIONAL_ELSE_AFTER_ELSE: - return "unexpected #else found after another #else"; - case PP_CONDITIONAL_ELIF_WITHOUT_IF: - return "unexpected #elif found without a matching #if"; - case PP_CONDITIONAL_ELIF_AFTER_ELSE: - return "unexpected #elif found after #else"; - case PP_CONDITIONAL_UNTERMINATED: - return "unexpected end of file found in conditional block"; - case PP_INVALID_EXTENSION_NAME: - return "invalid extension name"; - case PP_INVALID_EXTENSION_BEHAVIOR: - return "invalid extension behavior"; - case PP_INVALID_EXTENSION_DIRECTIVE: - return "invalid extension directive"; - case PP_INVALID_VERSION_NUMBER: - return "invalid version number"; - case PP_INVALID_VERSION_DIRECTIVE: - return "invalid version directive"; - case PP_VERSION_NOT_FIRST_STATEMENT: - return "#version directive must occur before anything else, " - "except for comments and white space"; - case PP_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: - return "unexpected end of file found in directive"; - case PP_CONDITIONAL_UNEXPECTED_TOKEN: - 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); - return ""; + // Errors begin. + case PP_INTERNAL_ERROR: + return "internal error"; + case PP_OUT_OF_MEMORY: + return "out of memory"; + case PP_INVALID_CHARACTER: + return "invalid character"; + case PP_INVALID_NUMBER: + return "invalid number"; + case PP_INTEGER_OVERFLOW: + return "integer overflow"; + case PP_FLOAT_OVERFLOW: + return "float overflow"; + case PP_TOKEN_TOO_LONG: + return "token too long"; + case PP_INVALID_EXPRESSION: + return "invalid expression"; + case PP_DIVISION_BY_ZERO: + return "division by zero"; + case PP_EOF_IN_COMMENT: + return "unexpected end of file found in comment"; + case PP_UNEXPECTED_TOKEN: + return "unexpected token"; + case PP_DIRECTIVE_INVALID_NAME: + return "invalid directive name"; + case PP_MACRO_NAME_RESERVED: + return "macro name is reserved"; + case PP_MACRO_REDEFINED: + return "macro redefined"; + case PP_MACRO_PREDEFINED_REDEFINED: + return "predefined macro redefined"; + case PP_MACRO_PREDEFINED_UNDEFINED: + return "predefined macro undefined"; + case PP_MACRO_UNTERMINATED_INVOCATION: + return "unterminated macro invocation"; + case PP_MACRO_UNDEFINED_WHILE_INVOKED: + return "macro undefined while being invoked"; + case PP_MACRO_TOO_FEW_ARGS: + 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_MACRO_INVOCATION_CHAIN_TOO_DEEP: + return "macro invocation chain too deep"; + case PP_CONDITIONAL_ENDIF_WITHOUT_IF: + return "unexpected #endif found without a matching #if"; + case PP_CONDITIONAL_ELSE_WITHOUT_IF: + return "unexpected #else found without a matching #if"; + case PP_CONDITIONAL_ELSE_AFTER_ELSE: + return "unexpected #else found after another #else"; + case PP_CONDITIONAL_ELIF_WITHOUT_IF: + return "unexpected #elif found without a matching #if"; + case PP_CONDITIONAL_ELIF_AFTER_ELSE: + return "unexpected #elif found after #else"; + case PP_CONDITIONAL_UNTERMINATED: + return "unexpected end of file found in conditional block"; + case PP_INVALID_EXTENSION_NAME: + return "invalid extension name"; + case PP_INVALID_EXTENSION_BEHAVIOR: + return "invalid extension behavior"; + case PP_INVALID_EXTENSION_DIRECTIVE: + return "invalid extension directive"; + case PP_INVALID_VERSION_NUMBER: + return "invalid version number"; + case PP_INVALID_VERSION_DIRECTIVE: + return "invalid version directive"; + case PP_VERSION_NOT_FIRST_STATEMENT: + return "#version directive must occur before anything else, " + "except for comments and white space"; + case PP_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"; + case PP_UNDEFINED_SHIFT: + return "shift exponent is negative or undefined"; + case PP_TOKENIZER_ERROR: + return "internal tokenizer error"; + // Errors end. + // Warnings begin. + case PP_EOF_IN_DIRECTIVE: + return "unexpected end of file found in directive"; + case PP_CONDITIONAL_UNEXPECTED_TOKEN: + 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: + UNREACHABLE(); + return ""; } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h index d26c174f01..ea37614606 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -19,11 +19,6 @@ struct SourceLocation; class Diagnostics { public: - enum Severity - { - PP_ERROR, - PP_WARNING - }; enum ID { PP_ERROR_BEGIN, @@ -44,9 +39,11 @@ class Diagnostics PP_MACRO_PREDEFINED_REDEFINED, PP_MACRO_PREDEFINED_UNDEFINED, PP_MACRO_UNTERMINATED_INVOCATION, + PP_MACRO_UNDEFINED_WHILE_INVOKED, PP_MACRO_TOO_FEW_ARGS, PP_MACRO_TOO_MANY_ARGS, PP_MACRO_DUPLICATE_PARAMETER_NAMES, + PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, PP_CONDITIONAL_ENDIF_WITHOUT_IF, PP_CONDITIONAL_ELSE_WITHOUT_IF, PP_CONDITIONAL_ELSE_AFTER_ELSE, @@ -65,6 +62,8 @@ class Diagnostics PP_INVALID_FILE_NUMBER, PP_INVALID_LINE_DIRECTIVE, PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3, + PP_UNDEFINED_SHIFT, + PP_TOKENIZER_ERROR, PP_ERROR_END, PP_WARNING_BEGIN, @@ -80,12 +79,10 @@ class Diagnostics void report(ID id, const SourceLocation &loc, const std::string &text); protected: - Severity severity(ID id); - std::string message(ID id); + bool isError(ID id); + const char *message(ID id); - virtual void print(ID id, - const SourceLocation &loc, - const std::string &text) = 0; + virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp index ef35c6ed50..049dae9071 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // -#include "DirectiveHandlerBase.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" namespace pp { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index cf67895764..6c81d015f5 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -23,8 +23,7 @@ class DirectiveHandler public: virtual ~DirectiveHandler(); - virtual void handleError(const SourceLocation &loc, - const std::string &msg) = 0; + virtual void handleError(const SourceLocation &loc, const std::string &msg) = 0; // Handle pragma of form: #pragma name[(value)] virtual void handlePragma(const SourceLocation &loc, @@ -36,8 +35,7 @@ class DirectiveHandler const std::string &name, const std::string &behavior) = 0; - virtual void handleVersion(const SourceLocation &loc, - int version) = 0; + virtual void handleVersion(const SourceLocation &loc, int version) = 0; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp index 2faa331378..f6c5763990 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp @@ -4,21 +4,22 @@ // found in the LICENSE file. // -#include "DirectiveParser.h" +#include "compiler/preprocessor/DirectiveParser.h" #include -#include #include #include -#include "DiagnosticsBase.h" -#include "DirectiveHandlerBase.h" -#include "ExpressionParser.h" -#include "MacroExpander.h" -#include "Token.h" -#include "Tokenizer.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" +#include "compiler/preprocessor/ExpressionParser.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" -namespace { +namespace +{ enum DirectiveType { DIRECTIVE_NONE, @@ -39,19 +40,19 @@ enum DirectiveType DirectiveType getDirective(const pp::Token *token) { - const char kDirectiveDefine[] = "define"; - const char kDirectiveUndef[] = "undef"; - const char kDirectiveIf[] = "if"; - const char kDirectiveIfdef[] = "ifdef"; - const char kDirectiveIfndef[] = "ifndef"; - const char kDirectiveElse[] = "else"; - const char kDirectiveElif[] = "elif"; - const char kDirectiveEndif[] = "endif"; - const char kDirectiveError[] = "error"; - const char kDirectivePragma[] = "pragma"; + const char kDirectiveDefine[] = "define"; + const char kDirectiveUndef[] = "undef"; + const char kDirectiveIf[] = "if"; + const char kDirectiveIfdef[] = "ifdef"; + const char kDirectiveIfndef[] = "ifndef"; + const char kDirectiveElse[] = "else"; + const char kDirectiveElif[] = "elif"; + const char kDirectiveEndif[] = "endif"; + const char kDirectiveError[] = "error"; + const char kDirectivePragma[] = "pragma"; const char kDirectiveExtension[] = "extension"; - const char kDirectiveVersion[] = "version"; - const char kDirectiveLine[] = "line"; + const char kDirectiveVersion[] = "version"; + const char kDirectiveLine[] = "line"; if (token->type != pp::Token::IDENTIFIER) return DIRECTIVE_NONE; @@ -90,15 +91,15 @@ bool isConditionalDirective(DirectiveType directive) { switch (directive) { - case DIRECTIVE_IF: - case DIRECTIVE_IFDEF: - case DIRECTIVE_IFNDEF: - case DIRECTIVE_ELSE: - case DIRECTIVE_ELIF: - case DIRECTIVE_ENDIF: - return true; - default: - return false; + case DIRECTIVE_IF: + case DIRECTIVE_IFDEF: + case DIRECTIVE_IFNDEF: + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ENDIF: + return true; + default: + return false; } } @@ -110,7 +111,7 @@ bool isEOD(const pp::Token *token) void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) { - while(!isEOD(token)) + while (!isEOD(token)) { lexer->lex(token); } @@ -118,8 +119,8 @@ void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) bool isMacroNameReserved(const std::string &name) { - // Names prefixed with "GL_" are reserved. - return (name.substr(0, 3) == "GL_"); + // Names prefixed with "GL_" and the name "defined" are reserved. + return name == "defined" || (name.substr(0, 3) == "GL_"); } bool hasDoubleUnderscores(const std::string &name) @@ -127,11 +128,10 @@ bool hasDoubleUnderscores(const std::string &name) return (name.find("__") != std::string::npos); } -bool isMacroPredefined(const std::string &name, - const pp::MacroSet ¯oSet) +bool isMacroPredefined(const std::string &name, const pp::MacroSet ¯oSet) { pp::MacroSet::const_iterator iter = macroSet.find(name); - return iter != macroSet.end() ? iter->second.predefined : false; + return iter != macroSet.end() ? iter->second->predefined : false; } } // namespace anonymous @@ -139,17 +139,83 @@ 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: + void lex(Token *token) override + { + 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) + DirectiveHandler *directiveHandler, + int maxMacroExpansionDepth) : mPastFirstStatement(false), mSeenNonPreprocessorToken(false), mTokenizer(tokenizer), mMacroSet(macroSet), mDiagnostics(diagnostics), mDirectiveHandler(directiveHandler), - mShaderVersion(100) + mShaderVersion(100), + mMaxMacroExpansionDepth(maxMacroExpansionDepth) +{ +} + +DirectiveParser::~DirectiveParser() { } @@ -174,21 +240,20 @@ void DirectiveParser::lex(Token *token) if (!mConditionalStack.empty()) { const ConditionalBlock &block = mConditionalStack.back(); - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, - block.location, block.type); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location, + block.type); } break; } - } - while (skipping() || (token->type == '\n')); + } while (skipping() || (token->type == '\n')); mPastFirstStatement = true; } void DirectiveParser::parseDirective(Token *token) { - assert(token->type == Token::PP_HASH); + ASSERT(token->type == Token::PP_HASH); mTokenizer->lex(token); if (isEOD(token)) @@ -207,86 +272,83 @@ void DirectiveParser::parseDirective(Token *token) return; } - switch(directive) + switch (directive) { - case DIRECTIVE_NONE: - mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, - token->location, token->text); - skipUntilEOD(mTokenizer, token); - break; - case DIRECTIVE_DEFINE: - parseDefine(token); - break; - case DIRECTIVE_UNDEF: - parseUndef(token); - break; - case DIRECTIVE_IF: - parseIf(token); - break; - case DIRECTIVE_IFDEF: - parseIfdef(token); - break; - case DIRECTIVE_IFNDEF: - parseIfndef(token); - break; - case DIRECTIVE_ELSE: - parseElse(token); - break; - case DIRECTIVE_ELIF: - parseElif(token); - break; - case DIRECTIVE_ENDIF: - parseEndif(token); - break; - case DIRECTIVE_ERROR: - parseError(token); - break; - case DIRECTIVE_PRAGMA: - parsePragma(token); - break; - case DIRECTIVE_EXTENSION: - parseExtension(token); - break; - case DIRECTIVE_VERSION: - parseVersion(token); - break; - case DIRECTIVE_LINE: - parseLine(token); - break; - default: - assert(false); - break; + case DIRECTIVE_NONE: + mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location, + token->text); + skipUntilEOD(mTokenizer, token); + break; + case DIRECTIVE_DEFINE: + parseDefine(token); + break; + case DIRECTIVE_UNDEF: + parseUndef(token); + break; + case DIRECTIVE_IF: + parseIf(token); + break; + case DIRECTIVE_IFDEF: + parseIfdef(token); + break; + case DIRECTIVE_IFNDEF: + parseIfndef(token); + break; + case DIRECTIVE_ELSE: + parseElse(token); + break; + case DIRECTIVE_ELIF: + parseElif(token); + break; + case DIRECTIVE_ENDIF: + parseEndif(token); + break; + case DIRECTIVE_ERROR: + parseError(token); + break; + case DIRECTIVE_PRAGMA: + parsePragma(token); + break; + case DIRECTIVE_EXTENSION: + parseExtension(token); + break; + case DIRECTIVE_VERSION: + parseVersion(token); + break; + case DIRECTIVE_LINE: + parseLine(token); + break; + default: + UNREACHABLE(); + break; } skipUntilEOD(mTokenizer, token); if (token->type == Token::LAST) { - mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text); } } void DirectiveParser::parseDefine(Token *token) { - assert(getDirective(token) == DIRECTIVE_DEFINE); + ASSERT(getDirective(token) == DIRECTIVE_DEFINE); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } if (isMacroPredefined(token->text, *mMacroSet)) { - mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location, + token->text); return; } if (isMacroNameReserved(token->text)) { - mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text); return; } // Using double underscores is allowed, but may result in unintended @@ -300,39 +362,37 @@ void DirectiveParser::parseDefine(Token *token) token->text); } - Macro macro; - macro.type = Macro::kTypeObj; - macro.name = token->text; + std::shared_ptr macro = std::make_shared(); + macro->type = Macro::kTypeObj; + macro->name = token->text; mTokenizer->lex(token); if (token->type == '(' && !token->hasLeadingSpace()) { // Function-like macro. Collect arguments. - macro.type = Macro::kTypeFunc; + macro->type = Macro::kTypeFunc; do { mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) break; - if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end()) + 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); + macro->parameters.push_back(token->text); mTokenizer->lex(token); // Get ','. - } - while (token->type == ','); + } while (token->type == ','); if (token->type != ')') { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, - token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } mTokenizer->lex(token); // Get ')'. @@ -344,47 +404,51 @@ void DirectiveParser::parseDefine(Token *token) // list. Resetting it also allows us to reuse Token::equals() to // compare macros. token->location = SourceLocation(); - macro.replacements.push_back(*token); + macro->replacements.push_back(*token); mTokenizer->lex(token); } - if (!macro.replacements.empty()) + if (!macro->replacements.empty()) { // Whitespace preceding the replacement list is not considered part of // the replacement list for either form of macro. - macro.replacements.front().setHasLeadingSpace(false); + macro->replacements.front().setHasLeadingSpace(false); } // Check for macro redefinition. - MacroSet::const_iterator iter = mMacroSet->find(macro.name); - if (iter != mMacroSet->end() && !macro.equals(iter->second)) + MacroSet::const_iterator iter = mMacroSet->find(macro->name); + if (iter != mMacroSet->end() && !macro->equals(*iter->second)) { - mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, - token->location, - macro.name); + mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name); return; } - mMacroSet->insert(std::make_pair(macro.name, macro)); + mMacroSet->insert(std::make_pair(macro->name, macro)); } void DirectiveParser::parseUndef(Token *token) { - assert(getDirective(token) == DIRECTIVE_UNDEF); + ASSERT(getDirective(token) == DIRECTIVE_UNDEF); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); return; } MacroSet::iterator iter = mMacroSet->find(token->text); if (iter != mMacroSet->end()) { - if (iter->second.predefined) + if (iter->second->predefined) { - mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location, + token->text); + return; + } + else if (iter->second->expansionCount > 0) + { + mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location, + token->text); + return; } else { @@ -395,38 +459,37 @@ void DirectiveParser::parseUndef(Token *token) mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseIf(Token *token) { - assert(getDirective(token) == DIRECTIVE_IF); + ASSERT(getDirective(token) == DIRECTIVE_IF); parseConditionalIf(token); } void DirectiveParser::parseIfdef(Token *token) { - assert(getDirective(token) == DIRECTIVE_IFDEF); + ASSERT(getDirective(token) == DIRECTIVE_IFDEF); parseConditionalIf(token); } void DirectiveParser::parseIfndef(Token *token) { - assert(getDirective(token) == DIRECTIVE_IFNDEF); + ASSERT(getDirective(token) == DIRECTIVE_IFNDEF); parseConditionalIf(token); } void DirectiveParser::parseElse(Token *token) { - assert(getDirective(token) == DIRECTIVE_ELSE); + ASSERT(getDirective(token) == DIRECTIVE_ELSE); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -440,34 +503,34 @@ void DirectiveParser::parseElse(Token *token) } if (block.foundElseGroup) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } - block.foundElseGroup = true; - block.skipGroup = block.foundValidGroup; + block.foundElseGroup = true; + block.skipGroup = block.foundValidGroup; block.foundValidGroup = true; // Check if there are extra tokens after #else. mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseElif(Token *token) { - assert(getDirective(token) == DIRECTIVE_ELIF); + ASSERT(getDirective(token) == DIRECTIVE_ELIF); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -481,8 +544,8 @@ void DirectiveParser::parseElif(Token *token) } if (block.foundElseGroup) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -495,19 +558,19 @@ void DirectiveParser::parseElif(Token *token) return; } - int expression = parseExpressionIf(token); - block.skipGroup = expression == 0; + int expression = parseExpressionIf(token); + block.skipGroup = expression == 0; block.foundValidGroup = expression != 0; } void DirectiveParser::parseEndif(Token *token) { - assert(getDirective(token) == DIRECTIVE_ENDIF); + ASSERT(getDirective(token) == DIRECTIVE_ENDIF); if (mConditionalStack.empty()) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -518,15 +581,15 @@ void DirectiveParser::parseEndif(Token *token) mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } } void DirectiveParser::parseError(Token *token) { - assert(getDirective(token) == DIRECTIVE_ERROR); + ASSERT(getDirective(token) == DIRECTIVE_ERROR); std::ostringstream stream; mTokenizer->lex(token); @@ -541,7 +604,7 @@ void DirectiveParser::parseError(Token *token) // Parses pragma of form: #pragma name[(value)]. void DirectiveParser::parsePragma(Token *token) { - assert(getDirective(token) == DIRECTIVE_PRAGMA); + ASSERT(getDirective(token) == DIRECTIVE_PRAGMA); enum State { @@ -563,25 +626,25 @@ void DirectiveParser::parsePragma(Token *token) } while ((token->type != '\n') && (token->type != Token::LAST)) { - switch(state++) + switch (state++) { - case PRAGMA_NAME: - name = token->text; - valid = valid && (token->type == Token::IDENTIFIER); - break; - case LEFT_PAREN: - valid = valid && (token->type == '('); - break; - case PRAGMA_VALUE: - value = token->text; - valid = valid && (token->type == Token::IDENTIFIER); - break; - case RIGHT_PAREN: - valid = valid && (token->type == ')'); - break; - default: - valid = false; - break; + case PRAGMA_NAME: + name = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case LEFT_PAREN: + valid = valid && (token->type == '('); + break; + case PRAGMA_VALUE: + value = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case RIGHT_PAREN: + valid = valid && (token->type == ')'); + break; + default: + valid = false; + break; } mTokenizer->lex(token); } @@ -591,8 +654,7 @@ void DirectiveParser::parsePragma(Token *token) (state == RIGHT_PAREN + 1)); // With value. if (!valid) { - mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, - token->location, name); + mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name); } else if (state > PRAGMA_NAME) // Do not notify for empty pragma. { @@ -602,7 +664,7 @@ void DirectiveParser::parsePragma(Token *token) void DirectiveParser::parseExtension(Token *token) { - assert(getDirective(token) == DIRECTIVE_EXTENSION); + ASSERT(getDirective(token) == DIRECTIVE_EXTENSION); enum State { @@ -620,47 +682,49 @@ void DirectiveParser::parseExtension(Token *token) { switch (state++) { - case EXT_NAME: - if (valid && (token->type != Token::IDENTIFIER)) - { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, - token->location, token->text); - valid = false; - } - if (valid) name = token->text; - break; - case COLON: - if (valid && (token->type != ':')) - { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - } - break; - case EXT_BEHAVIOR: - if (valid && (token->type != Token::IDENTIFIER)) - { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR, - token->location, token->text); - valid = false; - } - if (valid) behavior = token->text; - break; - default: - if (valid) - { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - } - break; + case EXT_NAME: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location, + token->text); + valid = false; + } + if (valid) + name = token->text; + break; + case COLON: + if (valid && (token->type != ':')) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); + valid = false; + } + break; + case EXT_BEHAVIOR: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR, + token->location, token->text); + valid = false; + } + if (valid) + behavior = token->text; + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); + valid = false; + } + break; } mTokenizer->lex(token); } if (valid && (state != EXT_BEHAVIOR + 1)) { - mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location, + token->text); valid = false; } if (valid && mSeenNonPreprocessorToken) @@ -683,12 +747,12 @@ void DirectiveParser::parseExtension(Token *token) void DirectiveParser::parseVersion(Token *token) { - assert(getDirective(token) == DIRECTIVE_VERSION); + ASSERT(getDirective(token) == DIRECTIVE_VERSION); if (mPastFirstStatement) { - mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location, + token->text); skipUntilEOD(mTokenizer, token); return; } @@ -700,47 +764,47 @@ void DirectiveParser::parseVersion(Token *token) VERSION_ENDLINE }; - bool valid = true; + bool valid = true; int version = 0; - int state = VERSION_NUMBER; + int state = VERSION_NUMBER; mTokenizer->lex(token); while (valid && (token->type != '\n') && (token->type != Token::LAST)) { switch (state) { - case VERSION_NUMBER: - if (token->type != Token::CONST_INT) - { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, - token->location, token->text); - valid = false; - } - if (valid && !token->iValue(&version)) - { - mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, - token->location, token->text); - valid = false; - } - if (valid) - { - state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; - } - break; - case VERSION_PROFILE: - if (token->type != Token::IDENTIFIER || token->text != "es") - { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, - token->location, token->text); + case VERSION_NUMBER: + if (token->type != Token::CONST_INT) + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location, + token->text); + valid = false; + } + if (valid && !token->iValue(&version)) + { + mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location, + token->text); + valid = false; + } + if (valid) + { + state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; + } + break; + case VERSION_PROFILE: + if (token->type != Token::IDENTIFIER || token->text != "es") + { + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); + valid = false; + } + state = VERSION_ENDLINE; + break; + default: + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); valid = false; - } - state = VERSION_ENDLINE; - break; - default: - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); - valid = false; - break; + break; } mTokenizer->lex(token); @@ -748,15 +812,15 @@ void DirectiveParser::parseVersion(Token *token) if (valid && (state != VERSION_ENDLINE)) { - mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location, + token->text); valid = false; } if (valid && version >= 300 && token->location.line > 1) { - mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location, + token->text); valid = false; } @@ -770,13 +834,13 @@ void DirectiveParser::parseVersion(Token *token) void DirectiveParser::parseLine(Token *token) { - assert(getDirective(token) == DIRECTIVE_LINE); + ASSERT(getDirective(token) == DIRECTIVE_LINE); - bool valid = true; + bool valid = true; bool parsedFileNumber = false; int line = 0, file = 0; - MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false); + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth); // Lex the first token after "#line" so we can check it for EOD. macroExpander.lex(token); @@ -814,8 +878,8 @@ void DirectiveParser::parseLine(Token *token) { if (valid) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, + token->text); valid = false; } skipUntilEOD(mTokenizer, token); @@ -835,14 +899,14 @@ bool DirectiveParser::skipping() const if (mConditionalStack.empty()) return false; - const ConditionalBlock& block = mConditionalStack.back(); + const ConditionalBlock &block = mConditionalStack.back(); return block.skipBlock || block.skipGroup; } void DirectiveParser::parseConditionalIf(Token *token) { ConditionalBlock block; - block.type = token->text; + block.type = token->text; block.location = token->location; if (skipping()) @@ -861,20 +925,20 @@ void DirectiveParser::parseConditionalIf(Token *token) int expression = 0; switch (directive) { - case DIRECTIVE_IF: - expression = parseExpressionIf(token); - break; - case DIRECTIVE_IFDEF: - expression = parseExpressionIfdef(token); - break; - case DIRECTIVE_IFNDEF: - expression = parseExpressionIfdef(token) == 0 ? 1 : 0; - break; - default: - assert(false); - break; + case DIRECTIVE_IF: + expression = parseExpressionIf(token); + break; + case DIRECTIVE_IFDEF: + expression = parseExpressionIfdef(token); + break; + case DIRECTIVE_IFNDEF: + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; + break; + default: + UNREACHABLE(); + break; } - block.skipGroup = expression == 0; + block.skipGroup = expression == 0; block.foundValidGroup = expression != 0; } mConditionalStack.push_back(block); @@ -882,16 +946,16 @@ void DirectiveParser::parseConditionalIf(Token *token) int DirectiveParser::parseExpressionIf(Token *token) { - assert((getDirective(token) == DIRECTIVE_IF) || - (getDirective(token) == DIRECTIVE_ELIF)); + ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF)); - MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true); + DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); + MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics, mMaxMacroExpansionDepth); ExpressionParser expressionParser(¯oExpander, mDiagnostics); int expression = 0; ExpressionParser::ErrorSettings errorSettings; errorSettings.integerLiteralsMustFit32BitSignedRange = false; - errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN; + errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN; bool valid = true; expressionParser.parse(token, &expression, false, errorSettings, &valid); @@ -899,8 +963,8 @@ int DirectiveParser::parseExpressionIf(Token *token) // Check if there are tokens after #if expression. if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } @@ -909,27 +973,25 @@ int DirectiveParser::parseExpressionIf(Token *token) int DirectiveParser::parseExpressionIfdef(Token *token) { - assert((getDirective(token) == DIRECTIVE_IFDEF) || - (getDirective(token) == DIRECTIVE_IFNDEF)); + ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF)); mTokenizer->lex(token); if (token->type != Token::IDENTIFIER) { - mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); skipUntilEOD(mTokenizer, token); return 0; } MacroSet::const_iterator iter = mMacroSet->find(token->text); - int expression = iter != mMacroSet->end() ? 1 : 0; + int expression = iter != mMacroSet->end() ? 1 : 0; // Check if there are tokens after #ifdef expression. mTokenizer->lex(token); if (!isEOD(token)) { - mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, - token->location, token->text); + mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location, + token->text); skipUntilEOD(mTokenizer, token); } return expression; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h index 2888e289ce..29c30a8239 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h @@ -7,10 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ #define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ -#include "Lexer.h" -#include "Macro.h" -#include "pp_utils.h" -#include "SourceLocation.h" +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/SourceLocation.h" namespace pp { @@ -25,13 +24,13 @@ class DirectiveParser : public Lexer DirectiveParser(Tokenizer *tokenizer, MacroSet *macroSet, Diagnostics *diagnostics, - DirectiveHandler *directiveHandler); + DirectiveHandler *directiveHandler, + int maxMacroExpansionDepth); + ~DirectiveParser() override; void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); - void parseDirective(Token *token); void parseDefine(Token *token); void parseUndef(Token *token); @@ -62,22 +61,21 @@ class DirectiveParser : public Lexer bool foundElseGroup; ConditionalBlock() - : skipBlock(false), - skipGroup(false), - foundValidGroup(false), - foundElseGroup(false) + : skipBlock(false), skipGroup(false), foundValidGroup(false), foundElseGroup(false) { } }; 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. + 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; + int mMaxMacroExpansionDepth; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h index 841c67b61c..0f2901b878 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h @@ -7,8 +7,8 @@ #ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ #define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ -#include "DiagnosticsBase.h" -#include "pp_utils.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/DiagnosticsBase.h" namespace pp { @@ -16,7 +16,7 @@ namespace pp class Lexer; struct Token; -class ExpressionParser +class ExpressionParser : angle::NonCopyable { public: struct ErrorSettings @@ -34,8 +34,6 @@ class ExpressionParser bool *valid); private: - PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); - Lexer *mLexer; Diagnostics *mDiagnostics; }; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y index 7b5d9e9cee..68d7cc3958 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y @@ -41,17 +41,15 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. #include #include +#include #include "DiagnosticsBase.h" #include "Lexer.h" #include "Token.h" +#include "common/mathutil.h" -#if defined(_MSC_VER) -typedef __int64 YYSTYPE; -#else -#include -typedef intmax_t YYSTYPE; -#endif // _MSC_VER +typedef int32_t YYSTYPE; +typedef uint32_t UNSIGNED_TYPE; #define YYENABLE_NLS 0 #define YYLTYPE_IS_TRIVIAL 1 @@ -196,16 +194,57 @@ expression $$ = $1 < $3; } | expression TOK_OP_RIGHT expression { - $$ = $1 >> $3; + if ($3 < 0 || $3 > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << $1 << " >> " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, + text.c_str()); + *(context->valid) = false; + } + $$ = static_cast(0); + } + else if ($1 < 0) + { + // Logical shift right. + $$ = static_cast(static_cast($1) >> $3); + } + else + { + $$ = $1 >> $3; + } } | expression TOK_OP_LEFT expression { - $$ = $1 << $3; + if ($3 < 0 || $3 > 31) + { + if (!context->isIgnoringErrors()) + { + std::ostringstream stream; + stream << $1 << " << " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT, + context->token->location, + text.c_str()); + *(context->valid) = false; + } + $$ = static_cast(0); + } + else + { + // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer + // overflow, which some tools treat as an error. + $$ = static_cast(static_cast($1) << $3); + } } | expression '-' expression { - $$ = $1 - $3; + $$ = gl::WrappingDiff($1, $3); } | expression '+' expression { - $$ = $1 + $3; + $$ = gl::WrappingSum($1, $3); } | expression '%' expression { if ($3 == 0) @@ -222,6 +261,12 @@ expression } $$ = static_cast(0); } + else if (($1 == std::numeric_limits::min()) && ($3 == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this has undefined results. + $$ = 0; + } else { $$ = $1 % $3; @@ -242,13 +287,20 @@ expression } $$ = static_cast(0); } + else if (($1 == std::numeric_limits::min()) && ($3 == -1)) + { + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this leads to integer overflow in C++, which + // has undefined results. + $$ = std::numeric_limits::max(); + } else { $$ = $1 / $3; } } | expression '*' expression { - $$ = $1 * $3; + $$ = gl::WrappingMul($1, $3); } | '!' expression %prec TOK_UNARY { $$ = ! $2; @@ -257,7 +309,16 @@ expression $$ = ~ $2; } | '-' expression %prec TOK_UNARY { - $$ = - $2; + // Check for negation of minimum representable integer to prevent undefined signed int + // overflow. + if ($2 == std::numeric_limits::min()) + { + $$ = std::numeric_limits::min(); + } + else + { + $$ = -$2; + } } | '+' expression %prec TOK_UNARY { $$ = + $2; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp index 5541d46f72..0f2327b823 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.cpp @@ -4,12 +4,13 @@ // found in the LICENSE file. // -#include "Input.h" +#include "compiler/preprocessor/Input.h" #include -#include #include +#include "common/debug.h" + namespace pp { @@ -17,9 +18,12 @@ Input::Input() : mCount(0), mString(0) { } -Input::Input(size_t count, const char *const string[], const int length[]) : - mCount(count), - mString(string) +Input::~Input() +{ +} + +Input::Input(size_t count, const char *const string[], const int length[]) + : mCount(count), mString(string) { mLength.reserve(mCount); for (size_t i = 0; i < mCount; ++i) @@ -32,7 +36,7 @@ Input::Input(size_t count, const char *const string[], const int length[]) : const char *Input::skipChar() { // This function should only be called when there is a character to skip. - assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); + ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); ++mReadLoc.cIndex; if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) { @@ -61,6 +65,11 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) { // Line continuation of backslash + newline. skipChar(); + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } ++(*lineNo); } else if (c != nullptr && (*c) == '\r') @@ -71,6 +80,11 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) { skipChar(); } + // Fake an EOF if the line number would overflow. + if (*lineNo == INT_MAX) + { + return 0; + } ++(*lineNo); } else @@ -86,7 +100,7 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) while ((nRead < maxRead) && (mReadLoc.sIndex < mCount)) { size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; - size = std::min(size, maxSize); + size = std::min(size, maxSize); for (size_t i = 0; i < size; ++i) { // Stop if a possible line continuation is encountered. @@ -94,7 +108,7 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) // and increments line number if necessary. if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\') { - size = i; + size = i; maxRead = nRead + size; // Stop reading right before the backslash. } } @@ -113,4 +127,3 @@ size_t Input::read(char *buf, size_t maxSize, int *lineNo) } } // namespace pp - diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h index a1de7ddd86..8c7c7ee19e 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h @@ -7,7 +7,7 @@ #ifndef COMPILER_PREPROCESSOR_INPUT_H_ #define COMPILER_PREPROCESSOR_INPUT_H_ -#include +#include #include namespace pp @@ -18,20 +18,12 @@ class Input { public: Input(); + ~Input(); Input(size_t count, const char *const string[], const int length[]); - size_t count() const - { - return mCount; - } - const char *string(size_t index) const - { - return mString[index]; - } - size_t length(size_t index) const - { - return mLength[index]; - } + size_t count() const { return mCount; } + const char *string(size_t index) const { return mString[index]; } + size_t length(size_t index) const { return mLength[index]; } size_t read(char *buf, size_t maxSize, int *lineNo); @@ -40,11 +32,7 @@ class Input size_t sIndex; // String index; size_t cIndex; // Char index. - Location() - : sIndex(0), - cIndex(0) - { - } + Location() : sIndex(0), cIndex(0) {} }; const Location &readLoc() const { return mReadLoc; } @@ -55,7 +43,7 @@ class Input // Input. size_t mCount; - const char * const *mString; + const char *const *mString; std::vector mLength; Location mReadLoc; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp index 7c663ee761..89cb3cf44e 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // -#include "Lexer.h" +#include "compiler/preprocessor/Lexer.h" namespace pp { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h index 990dc5e21d..775bc0a202 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h @@ -7,12 +7,14 @@ #ifndef COMPILER_PREPROCESSOR_LEXER_H_ #define COMPILER_PREPROCESSOR_LEXER_H_ +#include "common/angleutils.h" + namespace pp { struct Token; -class Lexer +class Lexer : angle::NonCopyable { public: virtual ~Lexer(); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp index 4c4d5fd2e2..52e2312fe6 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.cpp @@ -4,40 +4,41 @@ // found in the LICENSE file. // -#include "Macro.h" +#include "compiler/preprocessor/Macro.h" -#include - -#include "Token.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/Token.h" namespace pp { +Macro::Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj) +{ +} + +Macro::~Macro() +{ +} + bool Macro::equals(const Macro &other) const { - return (type == other.type) && - (name == other.name) && - (parameters == other.parameters) && + return (type == other.type) && (name == other.name) && (parameters == other.parameters) && (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(); + token.text = ToString(value); - Macro macro; - macro.predefined = true; - macro.type = Macro::kTypeObj; - macro.name = name; - macro.replacements.push_back(token); + std::shared_ptr macro = std::make_shared(); + 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 31ee22c26a..c42e172ef9 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h @@ -8,6 +8,7 @@ #define COMPILER_PREPROCESSOR_MACRO_H_ #include +#include #include #include @@ -26,16 +27,13 @@ struct Macro typedef std::vector Parameters; typedef std::vector Replacements; - Macro() - : predefined(false), - disabled(false), - type(kTypeObj) - { - } + Macro(); + ~Macro(); bool equals(const Macro &other) const; bool predefined; mutable bool disabled; + mutable int expansionCount; Type type; std::string name; @@ -43,7 +41,7 @@ struct Macro Replacements replacements; }; -typedef std::map MacroSet; +typedef std::map> MacroSet; void PredefineMacro(MacroSet *macroSet, const char *name, int value); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp index e878ee345a..d88d3a6853 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp @@ -4,20 +4,25 @@ // found in the LICENSE file. // -#include "MacroExpander.h" +#include "compiler/preprocessor/MacroExpander.h" #include -#include -#include "DiagnosticsBase.h" -#include "Token.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" namespace pp { +namespace +{ + +const size_t kMaxContextTokens = 10000; + class TokenLexer : public Lexer { - public: + public: typedef std::vector TokenVector; TokenLexer(TokenVector *tokens) @@ -39,26 +44,61 @@ class TokenLexer : public Lexer } } - private: - PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); - + private: TokenVector mTokens; TokenVector::const_iterator mIter; }; +} // anonymous namespace + +class MacroExpander::ScopedMacroReenabler final : angle::NonCopyable +{ + public: + ScopedMacroReenabler(MacroExpander *expander); + ~ScopedMacroReenabler(); + + private: + MacroExpander *mExpander; +}; + +MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander) + : mExpander(expander) +{ + mExpander->mDeferReenablingMacros = true; +} + +MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler() +{ + mExpander->mDeferReenablingMacros = false; + for (auto macro : mExpander->mMacrosToReenable) + { + // Copying the string here by using substr is a check for use-after-free. It detects + // use-after-free more reliably than just toggling the disabled flag. + ASSERT(macro->name.substr() != ""); + macro->disabled = false; + } + mExpander->mMacrosToReenable.clear(); +} + MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, - bool parseDefined) - : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mParseDefined(parseDefined) + int allowedMacroExpansionDepth) + : mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mTotalTokensInContexts(0), + mAllowedMacroExpansionDepth(allowedMacroExpansionDepth), + mDeferReenablingMacros(false) { } MacroExpander::~MacroExpander() { - for (std::size_t i = 0; i < mContextStack.size(); ++i) + ASSERT(mMacrosToReenable.empty()); + for (MacroContext *context : mContextStack) { - delete mContextStack[i]; + delete context; } } @@ -66,54 +106,11 @@ 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; @@ -121,17 +118,22 @@ void MacroExpander::lex(Token *token) if (iter == mMacroSet->end()) break; - const Macro& macro = iter->second; - if (macro.disabled) + std::shared_ptr macro = iter->second; + if (macro->disabled) { // If a particular token is not expanded, it is never expanded. token->setExpansionDisabled(true); break; } - if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) + + // Bump the expansion count before peeking if the next token is a '(' + // otherwise there could be a #undef of the macro before the next token. + macro->expansionCount++; + if ((macro->type == Macro::kTypeFunc) && !isNextTokenLeftParen()) { // If the token immediately after the macro name is not a '(', // this macro should not be expanded. + macro->expansionCount--; break; } @@ -160,6 +162,7 @@ void MacroExpander::getToken(Token *token) } else { + ASSERT(mTotalTokensInContexts == 0); mLexer->lex(token); } } @@ -170,11 +173,11 @@ void MacroExpander::ungetToken(const Token &token) { MacroContext *context = mContextStack.back(); context->unget(); - assert(context->replacements[context->index] == token); + ASSERT(context->replacements[context->index] == token); } else { - assert(!mReserveToken.get()); + ASSERT(!mReserveToken.get()); mReserveToken.reset(new Token(token)); } } @@ -190,37 +193,48 @@ bool MacroExpander::isNextTokenLeftParen() return lparen; } -bool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) +bool MacroExpander::pushMacro(std::shared_ptr macro, const Token &identifier) { - assert(!macro.disabled); - assert(!identifier.expansionDisabled()); - assert(identifier.type == Token::IDENTIFIER); - assert(identifier.text == macro.name); + ASSERT(!macro->disabled); + ASSERT(!identifier.expansionDisabled()); + ASSERT(identifier.type == Token::IDENTIFIER); + ASSERT(identifier.text == macro->name); std::vector replacements; - if (!expandMacro(macro, identifier, &replacements)) + if (!expandMacro(*macro, identifier, &replacements)) return false; // Macro is disabled for expansion until it is popped off the stack. - macro.disabled = true; + macro->disabled = true; MacroContext *context = new MacroContext; - context->macro = ¯o; + context->macro = macro; context->replacements.swap(replacements); mContextStack.push_back(context); + mTotalTokensInContexts += context->replacements.size(); return true; } void MacroExpander::popMacro() { - assert(!mContextStack.empty()); + ASSERT(!mContextStack.empty()); MacroContext *context = mContextStack.back(); mContextStack.pop_back(); - assert(context->empty()); - assert(context->macro->disabled); - context->macro->disabled = false; + ASSERT(context->empty()); + ASSERT(context->macro->disabled); + ASSERT(context->macro->expansionCount > 0); + if (mDeferReenablingMacros) + { + mMacrosToReenable.push_back(context->macro); + } + else + { + context->macro->disabled = false; + } + context->macro->expansionCount--; + mTotalTokensInContexts -= context->replacements.size(); delete context; } @@ -237,33 +251,28 @@ bool MacroExpander::expandMacro(const Macro ¯o, SourceLocation replacementLocation = identifier.location; if (macro.type == Macro::kTypeObj) { - replacements->assign(macro.replacements.begin(), - macro.replacements.end()); + replacements->assign(macro.replacements.begin(), macro.replacements.end()); if (macro.predefined) { const char kLine[] = "__LINE__"; const char kFile[] = "__FILE__"; - assert(replacements->size() == 1); - Token& repl = replacements->front(); + ASSERT(replacements->size() == 1); + Token &repl = replacements->front(); if (macro.name == kLine) { - std::ostringstream stream; - stream << identifier.location.line; - repl.text = stream.str(); + repl.text = ToString(identifier.location.line); } else if (macro.name == kFile) { - std::ostringstream stream; - stream << identifier.location.file; - repl.text = stream.str(); + repl.text = ToString(identifier.location.file); } } } else { - assert(macro.type == Macro::kTypeFunc); + ASSERT(macro.type == Macro::kTypeFunc); std::vector args; args.reserve(macro.parameters.size()); if (!collectMacroArgs(macro, identifier, &args, &replacementLocation)) @@ -274,7 +283,7 @@ bool MacroExpander::expandMacro(const Macro ¯o, for (std::size_t i = 0; i < replacements->size(); ++i) { - Token& repl = replacements->at(i); + Token &repl = replacements->at(i); if (i == 0) { // The first token in the replacement list inherits the padding @@ -294,45 +303,52 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, { Token token; getToken(&token); - assert(token.type == '('); + ASSERT(token.type == '('); args->push_back(MacroArg()); - for (int openParens = 1; openParens != 0; ) + + // Defer reenabling macros until args collection is finished to avoid the possibility of + // infinite recursion. Otherwise infinite recursion might happen when expanding the args after + // macros have been popped from the context stack when parsing the args. + ScopedMacroReenabler deferReenablingMacros(this); + + int openParens = 1; + while (openParens != 0) { getToken(&token); if (token.type == Token::LAST) { - mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, - identifier.location, identifier.text); + mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, identifier.location, + identifier.text); // Do not lose EOF token. ungetToken(token); return false; } - bool isArg = false; // True if token is part of the current argument. + bool isArg = false; // True if token is part of the current argument. switch (token.type) { - case '(': - ++openParens; - isArg = true; - break; - case ')': - --openParens; - isArg = openParens != 0; - *closingParenthesisLocation = token.location; - break; - case ',': - // The individual arguments are separated by comma tokens, but - // the comma tokens between matching inner parentheses do not - // seperate arguments. - if (openParens == 1) - args->push_back(MacroArg()); - isArg = openParens != 1; - break; - default: - isArg = true; - break; + case '(': + ++openParens; + isArg = true; + break; + case ')': + --openParens; + isArg = openParens != 0; + *closingParenthesisLocation = token.location; + break; + case ',': + // The individual arguments are separated by comma tokens, but + // the comma tokens between matching inner parentheses do not + // seperate arguments. + if (openParens == 1) + args->push_back(MacroArg()); + isArg = openParens != 1; + break; + default: + isArg = true; + break; } if (isArg) { @@ -353,9 +369,9 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, // Validate the number of arguments. if (args->size() != params.size()) { - Diagnostics::ID id = args->size() < macro.parameters.size() ? - Diagnostics::PP_MACRO_TOO_FEW_ARGS : - Diagnostics::PP_MACRO_TOO_MANY_ARGS; + Diagnostics::ID id = args->size() < macro.parameters.size() + ? Diagnostics::PP_MACRO_TOO_FEW_ARGS + : Diagnostics::PP_MACRO_TOO_MANY_ARGS; mDiagnostics->report(id, identifier.location, identifier.text); return false; } @@ -363,11 +379,17 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, // Pre-expand each argument before substitution. // This step expands each argument individually before they are // inserted into the macro body. - for (std::size_t i = 0; i < args->size(); ++i) + size_t numTokens = 0; + for (auto &arg : *args) { - MacroArg &arg = args->at(i); TokenLexer lexer(&arg); - MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mParseDefined); + if (mAllowedMacroExpansionDepth < 1) + { + mDiagnostics->report(Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP, token.location, + token.text); + return false; + } + MacroExpander expander(&lexer, mMacroSet, mDiagnostics, mAllowedMacroExpansionDepth - 1); arg.clear(); expander.lex(&token); @@ -375,6 +397,12 @@ bool MacroExpander::collectMacroArgs(const Macro ¯o, { arg.push_back(token); expander.lex(&token); + numTokens++; + if (numTokens + mTotalTokensInContexts > kMaxContextTokens) + { + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return false; + } } } return true; @@ -386,6 +414,14 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, { for (std::size_t i = 0; i < macro.replacements.size(); ++i) { + if (!replacements->empty() && + replacements->size() + mTotalTokensInContexts > kMaxContextTokens) + { + const Token &token = replacements->back(); + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return; + } + const Token &repl = macro.replacements[i]; if (repl.type != Token::IDENTIFIER) { @@ -396,15 +432,15 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, // TODO(alokp): Optimize this. // There is no need to search for macro params every time. // The param index can be cached with the replacement token. - Macro::Parameters::const_iterator iter = std::find( - macro.parameters.begin(), macro.parameters.end(), repl.text); + Macro::Parameters::const_iterator iter = + std::find(macro.parameters.begin(), macro.parameters.end(), repl.text); if (iter == macro.parameters.end()) { replacements->push_back(repl); continue; } - std::size_t iArg = std::distance(macro.parameters.begin(), iter); + std::size_t iArg = std::distance(macro.parameters.begin(), iter); const MacroArg &arg = args[iArg]; if (arg.empty()) { @@ -418,5 +454,28 @@ void MacroExpander::replaceMacroParams(const Macro ¯o, } } -} // namespace pp +MacroExpander::MacroContext::MacroContext() : macro(0), index(0) +{ +} +MacroExpander::MacroContext::~MacroContext() +{ +} + +bool MacroExpander::MacroContext::empty() const +{ + return index == replacements.size(); +} + +const Token &MacroExpander::MacroContext::get() +{ + return replacements[index++]; +} + +void MacroExpander::MacroContext::unget() +{ + ASSERT(index > 0); + --index; +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index dc870f626f..fae7676fb0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -7,13 +7,11 @@ #ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_ #define COMPILER_PREPROCESSOR_MACROEXPANDER_H_ -#include #include #include -#include "Lexer.h" -#include "Macro.h" -#include "pp_utils.h" +#include "compiler/preprocessor/Lexer.h" +#include "compiler/preprocessor/Macro.h" namespace pp { @@ -24,24 +22,23 @@ struct SourceLocation; class MacroExpander : public Lexer { public: - MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics, bool parseDefined); + MacroExpander(Lexer *lexer, + MacroSet *macroSet, + Diagnostics *diagnostics, + int allowedMacroExpansionDepth); ~MacroExpander() override; void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); - void getToken(Token *token); void ungetToken(const Token &token); bool isNextTokenLeftParen(); - bool pushMacro(const Macro ¯o, const Token &identifier); + bool pushMacro(std::shared_ptr macro, const Token &identifier); void popMacro(); - bool expandMacro(const Macro ¯o, - const Token &identifier, - std::vector *replacements); + bool expandMacro(const Macro ¯o, const Token &identifier, std::vector *replacements); typedef std::vector MacroArg; bool collectMacroArgs(const Macro ¯o, @@ -54,37 +51,31 @@ class MacroExpander : public Lexer struct MacroContext { - const Macro *macro; + MacroContext(); + ~MacroContext(); + bool empty() const; + const Token &get(); + void unget(); + + std::shared_ptr macro; std::size_t index; std::vector replacements; - - MacroContext() - : macro(0), - index(0) - { - } - bool empty() const - { - return index == replacements.size(); - } - const Token &get() - { - return replacements[index++]; - } - void unget() - { - assert(index > 0); - --index; - } }; Lexer *mLexer; MacroSet *mMacroSet; Diagnostics *mDiagnostics; - bool mParseDefined; std::unique_ptr mReserveToken; std::vector mContextStack; + size_t mTotalTokensInContexts; + + int mAllowedMacroExpansionDepth; + + bool mDeferReenablingMacros; + std::vector> mMacrosToReenable; + + class ScopedMacroReenabler; }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp index aeb9c46f9d..349c7b06c7 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.cpp @@ -4,16 +4,15 @@ // found in the LICENSE file. // -#include "Preprocessor.h" +#include "compiler/preprocessor/Preprocessor.h" -#include - -#include "DiagnosticsBase.h" -#include "DirectiveParser.h" -#include "Macro.h" -#include "MacroExpander.h" -#include "Token.h" -#include "Tokenizer.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/DirectiveParser.h" +#include "compiler/preprocessor/Macro.h" +#include "compiler/preprocessor/MacroExpander.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/preprocessor/Tokenizer.h" namespace pp { @@ -26,19 +25,26 @@ struct PreprocessorImpl DirectiveParser directiveParser; MacroExpander macroExpander; - PreprocessorImpl(Diagnostics *diag, DirectiveHandler *directiveHandler) + PreprocessorImpl(Diagnostics *diag, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) : diagnostics(diag), tokenizer(diag), - directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), - macroExpander(&directiveParser, ¯oSet, diag, false) + directiveParser(&tokenizer, + ¯oSet, + diag, + directiveHandler, + settings.maxMacroExpansionDepth), + macroExpander(&directiveParser, ¯oSet, diag, settings.maxMacroExpansionDepth) { } }; Preprocessor::Preprocessor(Diagnostics *diagnostics, - DirectiveHandler *directiveHandler) + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings) { - mImpl = new PreprocessorImpl(diagnostics, directiveHandler); + mImpl = new PreprocessorImpl(diagnostics, directiveHandler, settings); } Preprocessor::~Preprocessor() @@ -46,9 +52,7 @@ Preprocessor::~Preprocessor() delete mImpl; } -bool Preprocessor::init(size_t count, - const char * const string[], - const int length[]) +bool Preprocessor::init(size_t count, const char *const string[], const int length[]) { static const int kDefaultGLSLVersion = 100; @@ -74,23 +78,23 @@ void Preprocessor::lex(Token *token) mImpl->macroExpander.lex(token); switch (token->type) { - // We should not be returning internal preprocessing tokens. - // Convert preprocessing tokens to compiler tokens or report - // diagnostics. - case Token::PP_HASH: - assert(false); - break; - case Token::PP_NUMBER: - mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER, - token->location, token->text); - break; - case Token::PP_OTHER: - mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER, - token->location, token->text); - break; - default: - validToken = true; - break; + // We should not be returning internal preprocessing tokens. + // Convert preprocessing tokens to compiler tokens or report + // diagnostics. + case Token::PP_HASH: + UNREACHABLE(); + break; + case Token::PP_NUMBER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER, token->location, + token->text); + break; + case Token::PP_OTHER: + mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER, token->location, + token->text); + break; + default: + validToken = true; + break; } } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h index fe25daa123..2fe504f7f9 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h @@ -7,9 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_ #define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ -#include +#include -#include "pp_utils.h" +#include "common/angleutils.h" namespace pp { @@ -19,10 +19,18 @@ class DirectiveHandler; struct PreprocessorImpl; struct Token; -class Preprocessor +struct PreprocessorSettings : private angle::NonCopyable +{ + PreprocessorSettings() : maxMacroExpansionDepth(1000) {} + int maxMacroExpansionDepth; +}; + +class Preprocessor : angle::NonCopyable { public: - Preprocessor(Diagnostics *diagnostics, DirectiveHandler *directiveHandler); + Preprocessor(Diagnostics *diagnostics, + DirectiveHandler *directiveHandler, + const PreprocessorSettings &settings); ~Preprocessor(); // count: specifies the number of elements in the string and length arrays. @@ -34,7 +42,7 @@ class Preprocessor // Each element in the length array may contain the length of the // corresponding string or a value less than 0 to indicate that the string // is null terminated. - bool init(size_t count, const char * const string[], const int length[]); + bool init(size_t count, const char *const string[], const int length[]); // Adds a pre-defined macro. void predefineMacro(const char *name, int value); @@ -44,8 +52,6 @@ class Preprocessor void setMaxTokenSize(size_t maxTokenSize); private: - PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); - PreprocessorImpl *mImpl; }; diff --git a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h index af8a8d5d19..51908a3b4b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h @@ -12,16 +12,8 @@ namespace pp struct SourceLocation { - SourceLocation() - : file(0), - line(0) - { - } - SourceLocation(int f, int l) - : file(f), - line(l) - { - } + SourceLocation() : file(0), line(0) {} + SourceLocation(int f, int l) : file(f), line(l) {} bool equals(const SourceLocation &other) const { diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp index d102654747..ce0ce94f49 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.cpp @@ -4,28 +4,25 @@ // found in the LICENSE file. // -#include "Token.h" +#include "compiler/preprocessor/Token.h" -#include - -#include "numeric_lex.h" +#include "common/debug.h" +#include "compiler/preprocessor/numeric_lex.h" namespace pp { void Token::reset() { - type = 0; - flags = 0; + type = 0; + flags = 0; location = SourceLocation(); text.clear(); } bool Token::equals(const Token &other) const { - return (type == other.type) && - (flags == other.flags) && - (location == other.location) && + return (type == other.type) && (flags == other.flags) && (location == other.location) && (text == other.text); } @@ -55,19 +52,19 @@ void Token::setExpansionDisabled(bool disable) bool Token::iValue(int *value) const { - assert(type == CONST_INT); + ASSERT(type == CONST_INT); return numeric_lex_int(text, value); } bool Token::uValue(unsigned int *value) const { - assert(type == CONST_INT); + ASSERT(type == CONST_INT); return numeric_lex_int(text, value); } bool Token::fValue(float *value) const { - assert(type == CONST_FLOAT); + ASSERT(type == CONST_FLOAT); return numeric_lex_float(text, value); } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/Token.h index 347c47e307..26732ab64d 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.h @@ -10,7 +10,7 @@ #include #include -#include "SourceLocation.h" +#include "compiler/preprocessor/SourceLocation.h" namespace pp { @@ -19,7 +19,9 @@ struct Token { enum Type { - LAST = 0, // EOF. + // Calling this ERROR causes a conflict with wingdi.h + GOT_ERROR = -1, + LAST = 0, // EOF. IDENTIFIER = 258, @@ -62,33 +64,20 @@ struct Token EXPANSION_DISABLED = 1 << 2 }; - Token() - : type(0), - flags(0) - { - } + Token() : type(0), flags(0) {} void reset(); bool equals(const Token &other) const; // Returns true if this is the first token on line. // It disregards any leading whitespace. - bool atStartOfLine() const - { - return (flags & AT_START_OF_LINE) != 0; - } + bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } void setAtStartOfLine(bool start); - bool hasLeadingSpace() const - { - return (flags & HAS_LEADING_SPACE) != 0; - } + bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } void setHasLeadingSpace(bool space); - bool expansionDisabled() const - { - return (flags & EXPANSION_DISABLED) != 0; - } + bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } void setExpansionDisabled(bool disable); // Converts text into numeric value for CONST_INT and CONST_FLOAT token. @@ -113,7 +102,7 @@ inline bool operator!=(const Token &lhs, const Token &rhs) return !lhs.equals(rhs); } -extern std::ostream &operator<<(std::ostream &out, const Token &token); +std::ostream &operator<<(std::ostream &out, const Token &token); } // namepsace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h index 49e64fa209..af4fd7ce7b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h @@ -7,9 +7,9 @@ #ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_ #define COMPILER_PREPROCESSOR_TOKENIZER_H_ -#include "Input.h" -#include "Lexer.h" -#include "pp_utils.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/Input.h" +#include "compiler/preprocessor/Lexer.h" namespace pp { @@ -34,9 +34,9 @@ class Tokenizer : public Lexer }; Tokenizer(Diagnostics *diagnostics); - ~Tokenizer(); + ~Tokenizer() override; - bool init(size_t count, const char * const string[], const int length[]); + bool init(size_t count, const char *const string[], const int length[]); void setFileNumber(int file); void setLineNumber(int line); @@ -45,13 +45,12 @@ class Tokenizer : public Lexer void lex(Token *token) override; private: - PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); bool initScanner(); void destroyScanner(); - void *mHandle; // Scanner handle. - Context mContext; // Scanner extra. - size_t mMaxTokenSize; // Maximum token size + void *mHandle; // Scanner handle. + Context mContext; // Scanner extra. + size_t mMaxTokenSize; // Maximum token size }; } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l index d316da88b1..096812d45f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l @@ -27,10 +27,10 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. #pragma warning(disable: 4005) #endif -#include "Tokenizer.h" +#include "compiler/preprocessor/Tokenizer.h" -#include "DiagnosticsBase.h" -#include "Token.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" #if defined(__GNUC__) // Triggered by the auto-generated yy_fatal_error function. @@ -110,7 +110,14 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") "/*" { BEGIN(COMMENT); } [^*\r\n]+ "*" -{NEWLINE} { ++yylineno; } +{NEWLINE} { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return pp::Token::GOT_ERROR; + } + ++yylineno; +} "*/" { yyextra->leadingSpace = true; BEGIN(INITIAL); @@ -237,13 +244,16 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") [ \t\v\f]+ { yyextra->leadingSpace = true; } {NEWLINE} { + if (yylineno == INT_MAX) + { + *yylval = "Integer overflow on line number"; + return pp::Token::GOT_ERROR; + } ++yylineno; yylval->assign(1, '\n'); return '\n'; } -\\{NEWLINE} { ++yylineno; } - . { yylval->assign(1, yytext[0]); return pp::Token::PP_OTHER; @@ -267,11 +277,17 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") yylloc->line = yylineno; yylval->clear(); - if (YY_START == COMMENT) + // Line number overflows fake EOFs to exit early, check for this case. + if (yylineno == INT_MAX) { + yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR, + pp::SourceLocation(yyfileno, yylineno), + "Integer overflow on line number"); + } + else if (YY_START == COMMENT) { yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT, pp::SourceLocation(yyfileno, yylineno), - ""); + "EOF while in a comment"); } yyterminate(); } @@ -280,9 +296,7 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") namespace pp { -Tokenizer::Tokenizer(Diagnostics *diagnostics) - : mHandle(0), - mMaxTokenSize(256) +Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256) { mContext.diagnostics = diagnostics; } @@ -320,7 +334,18 @@ void Tokenizer::setMaxTokenSize(size_t maxTokenSize) void Tokenizer::lex(Token *token) { - token->type = yylex(&token->text, &token->location, mHandle); + int tokenType = yylex(&token->text, &token->location, mHandle); + + if (tokenType == Token::GOT_ERROR) + { + mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text); + token->type = Token::LAST; + } + else + { + token->type = tokenType; + } + if (token->text.size() > mMaxTokenSize) { mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG, @@ -339,7 +364,7 @@ void Tokenizer::lex(Token *token) bool Tokenizer::initScanner() { - if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) + if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle)) return false; yyrestart(0, mHandle); @@ -348,11 +373,11 @@ bool Tokenizer::initScanner() void Tokenizer::destroyScanner() { - if (mHandle == NULL) + if (mHandle == nullptr) return; yylex_destroy(mHandle); - mHandle = NULL; + mHandle = nullptr; } } // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h index b32e42253f..6ea779ab8f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h @@ -9,15 +9,15 @@ #ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_ #define COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#include #include -namespace pp { +namespace pp +{ inline std::ios::fmtflags numeric_base_int(const std::string &str) { - if ((str.size() >= 2) && - (str[0] == '0') && - (str[1] == 'x' || str[1] == 'X')) + if ((str.size() >= 2) && (str[0] == '0') && (str[1] == 'x' || str[1] == 'X')) { return std::ios::hex; } @@ -33,7 +33,7 @@ inline std::ios::fmtflags numeric_base_int(const std::string &str) // of the correct form. They can only fail if the parsed value is too big, // in which case false is returned. -template +template bool numeric_lex_int(const std::string &str, IntType *value) { std::istringstream stream(str); @@ -45,7 +45,7 @@ bool numeric_lex_int(const std::string &str, IntType *value) return !stream.fail(); } -template +template bool numeric_lex_float(const std::string &str, FloatType *value) { // On 64-bit Intel Android, istringstream is broken. Until this is fixed in @@ -63,10 +63,10 @@ bool numeric_lex_float(const std::string &str, FloatType *value) stream.imbue(std::locale::classic()); stream >> (*value); - return !stream.fail(); + return !stream.fail() && std::isfinite(*value); #endif } -} // namespace pp. +} // namespace pp. -#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h b/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h deleted file mode 100644 index 9fba9385c5..0000000000 --- a/src/3rdparty/angle/src/compiler/preprocessor/pp_utils.h +++ /dev/null @@ -1,18 +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. -// - -// pp_utils.h: Common preprocessor utilities - -#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_ -#define COMPILER_PREPROCESSOR_PPUTILS_H_ - -// A macro to disallow the copy constructor and operator= functions -// This must be used in the private: declarations for a class. -#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &); \ - void operator=(const TypeName &) - -#endif // COMPILER_PREPROCESSOR_PPUTILS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp index 31bfae9966..b04fc28259 100644 --- a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.cpp @@ -9,8 +9,12 @@ #include "compiler/translator/ASTMetadataHLSL.h" #include "compiler/translator/CallDAG.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/SymbolTable.h" +namespace sh +{ + namespace { @@ -29,9 +33,22 @@ class PullGradient : public TIntermTraverser mDag(dag) { ASSERT(index < metadataList->size()); + + // ESSL 100 builtin gradient functions + mGradientBuiltinFunctions.insert("texture2D"); + mGradientBuiltinFunctions.insert("texture2DProj"); + mGradientBuiltinFunctions.insert("textureCube"); + + // ESSL 300 builtin gradient functions + mGradientBuiltinFunctions.insert("texture"); + mGradientBuiltinFunctions.insert("textureProj"); + mGradientBuiltinFunctions.insert("textureOffset"); + mGradientBuiltinFunctions.insert("textureProjOffset"); + + // ESSL 310 doesn't add builtin gradient functions } - void traverse(TIntermAggregate *node) + void traverse(TIntermFunctionDefinition *node) { node->traverse(this); ASSERT(mParents.empty()); @@ -59,7 +76,7 @@ class PullGradient : public TIntermTraverser 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()) + if (mMetadata->mControlFlowsContainingGradient.count(node) > 0 && !mParents.empty()) { mMetadata->mControlFlowsContainingGradient.insert(mParents.back()); } @@ -72,9 +89,9 @@ class PullGradient : public TIntermTraverser return true; } - bool visitSelection(Visit visit, TIntermSelection *selection) override + bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override { - visitControlFlow(visit, selection); + visitControlFlow(visit, ifElse); return true; } @@ -84,11 +101,12 @@ class PullGradient : public TIntermTraverser { switch (node->getOp()) { - case EOpDFdx: - case EOpDFdy: - onGradient(); - default: - break; + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + onGradient(); + default: + break; } } @@ -99,28 +117,22 @@ class PullGradient : public TIntermTraverser { if (visit == PreVisit) { - if (node->getOp() == EOpFunctionCall) + if (node->getOp() == EOpCallFunctionInAST) { - if (node->isUserDefined()) - { - size_t calleeIndex = mDag.findIndex(node); - ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); - UNUSED_ASSERTION_VARIABLE(mIndex); + size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); - if ((*mMetadataList)[calleeIndex].mUsesGradient) { - onGradient(); - } + if ((*mMetadataList)[calleeIndex].mUsesGradient) + { + onGradient(); } - else + } + else if (node->getOp() == EOpCallBuiltInFunction) + { + if (mGradientBuiltinFunctions.find(node->getFunctionSymbolInfo()->getName()) != + mGradientBuiltinFunctions.end()) { - TString name = TFunction::unmangleName(node->getName()); - - if (name == "texture2D" || - name == "texture2DProj" || - name == "textureCube") - { - onGradient(); - } + onGradient(); } } } @@ -136,7 +148,10 @@ class PullGradient : public TIntermTraverser // 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; + std::vector mParents; + + // A list of builtin functions that use gradients + std::set mGradientBuiltinFunctions; }; // Traverses the AST of a function definition to compute the the discontinuous loops @@ -157,7 +172,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser { } - void traverse(TIntermAggregate *node) + void traverse(TIntermFunctionDefinition *node) { node->traverse(this); ASSERT(mLoopsAndSwitches.empty()); @@ -196,7 +211,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser return true; } - bool visitSelection(Visit visit, TIntermSelection *node) override + bool visitIfElse(Visit visit, TIntermIfElse *node) override { if (visit == PreVisit) { @@ -222,7 +237,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser { switch (node->getFlowOp()) { - case EOpBreak: + case EOpBreak: { ASSERT(!mLoopsAndSwitches.empty()); TIntermLoop *loop = mLoopsAndSwitches.back()->getAsLoopNode(); @@ -232,11 +247,11 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser } } break; - case EOpContinue: + case EOpContinue: { ASSERT(!mLoopsAndSwitches.empty()); TIntermLoop *loop = nullptr; - size_t i = mLoopsAndSwitches.size(); + size_t i = mLoopsAndSwitches.size(); while (loop == nullptr && i > 0) { --i; @@ -246,23 +261,23 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser 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) + case EOpKill: + case EOpReturn: + // A return or discard jumps out of all the enclosing loops + if (!mLoopsAndSwitches.empty()) { - TIntermLoop *loop = intermNode->getAsLoopNode(); - if (loop) + for (TIntermNode *intermNode : mLoopsAndSwitches) { - mMetadata->mDiscontinuousLoops.insert(loop); + TIntermLoop *loop = intermNode->getAsLoopNode(); + if (loop) + { + mMetadata->mDiscontinuousLoops.insert(loop); + } } } - } - break; - default: - UNREACHABLE(); + break; + default: + UNREACHABLE(); } } @@ -271,18 +286,14 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser bool visitAggregate(Visit visit, TIntermAggregate *node) override { - if (visit == PreVisit && node->getOp() == EOpFunctionCall) + if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST) { - if (node->isUserDefined()) - { - size_t calleeIndex = mDag.findIndex(node); - ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); - UNUSED_ASSERTION_VARIABLE(mIndex); + size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); - if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph) - { - onGradientLoop(); - } + if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph) + { + onGradientLoop(); } } @@ -309,8 +320,8 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser size_t mIndex; const CallDAG &mDag; - std::vector mLoopsAndSwitches; - std::vector mIfs; + std::vector mLoopsAndSwitches; + std::vector mIfs; }; // Tags all the functions called in a discontinuous loop @@ -327,7 +338,7 @@ class PushDiscontinuousLoops : public TIntermTraverser { } - void traverse(TIntermAggregate *node) + void traverse(TIntermFunctionDefinition *node) { node->traverse(this); ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0)); @@ -353,18 +364,17 @@ class PushDiscontinuousLoops : public TIntermTraverser { 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); + case EOpCallFunctionInAST: + if (visit == PreVisit && mNestedDiscont > 0) + { + size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); - (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true; - } - break; - default: - break; + (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true; + } + break; + default: + break; } return true; } @@ -377,7 +387,6 @@ class PushDiscontinuousLoops : public TIntermTraverser int mNestedDiscont; }; - } bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node) @@ -385,7 +394,7 @@ bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node) return mControlFlowsContainingGradient.count(node) > 0; } -bool ASTMetadataHLSL::hasGradientLoop(TIntermSelection *node) +bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node) { return mIfsContainingGradientLoop.count(node) > 0; } @@ -449,3 +458,5 @@ MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag) return metadataList; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h index 39e671e3e0..550a522b86 100644 --- a/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/ASTMetadataHLSL.h @@ -12,9 +12,12 @@ #include #include +namespace sh +{ + class CallDAG; class TIntermNode; -class TIntermSelection; +class TIntermIfElse; class TIntermLoop; struct ASTMetadataHLSL @@ -30,21 +33,21 @@ struct ASTMetadataHLSL // 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); + bool hasGradientLoop(TIntermIfElse *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; + 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; + std::set mDiscontinuousLoops; + std::set mIfsContainingGradientLoop; // Will we need to generate a Lod0 version of the function. bool mNeedsLod0; @@ -55,4 +58,6 @@ 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_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp b/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp new file mode 100644 index 0000000000..6a05104233 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2016 The ANGLE Project 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/AddAndTrueToLoopCondition.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that rewrites for and while loops by replacing "condition" with +// "condition && true" to work around condition bug on Intel Mac. +class AddAndTrueToLoopConditionTraverser : public TIntermTraverser +{ + public: + AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {} + + bool visitLoop(Visit, TIntermLoop *loop) override + { + // do-while loop doesn't have this bug. + if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile) + { + return true; + } + + // For loop may not have a condition. + if (loop->getCondition() == nullptr) + { + return true; + } + + // Constant true. + TConstantUnion *trueConstant = new TConstantUnion(); + trueConstant->setBConst(true); + TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, TType(EbtBool)); + + // CONDITION && true. + TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue); + loop->setCondition(andOp); + + return true; + } +}; + +} // anonymous namespace + +void AddAndTrueToLoopCondition(TIntermNode *root) +{ + AddAndTrueToLoopConditionTraverser traverser; + root->traverse(&traverser); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.h b/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.h new file mode 100644 index 0000000000..34debe0ed9 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/AddAndTrueToLoopCondition.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Rewrite condition in for and while loops to work around driver bug on Intel Mac. + +#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ +#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ + +class TIntermNode; +namespace sh +{ + +void AddAndTrueToLoopCondition(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.cpp b/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.cpp new file mode 100644 index 0000000000..4dfe60c0bc --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// AddDefaultReturnStatements.cpp: Add default return statements to functions that do not end in a +// return. +// + +#include "compiler/translator/AddDefaultReturnStatements.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +bool NeedsReturnStatement(TIntermFunctionDefinition *node, TType *returnType) +{ + *returnType = node->getFunctionPrototype()->getType(); + if (returnType->getBasicType() == EbtVoid) + { + return false; + } + + TIntermBlock *bodyNode = node->getBody(); + TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode(); + if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn) + { + return false; + } + + return true; +} + +} // anonymous namespace + +void AddDefaultReturnStatements(TIntermBlock *root) +{ + TType returnType; + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *definition = node->getAsFunctionDefinition(); + if (definition != nullptr && NeedsReturnStatement(definition, &returnType)) + { + TIntermBranch *branch = new TIntermBranch(EOpReturn, CreateZeroNode(returnType)); + + TIntermBlock *bodyNode = definition->getBody(); + bodyNode->getSequence()->push_back(branch); + } + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.h b/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.h new file mode 100644 index 0000000000..40a70ad8c2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/AddDefaultReturnStatements.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// AddDefaultReturnStatements.h: Add default return statements to functions that do not end in a +// return. +// + +#ifndef COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ + +class TIntermBlock; + +namespace sh +{ + +void AddDefaultReturnStatements(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp index 510ade84c1..17721fb0dc 100644 --- a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp @@ -3,17 +3,23 @@ // 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. +// 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" +#include + +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ namespace { -void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to) +void CopyAggregateChildren(TIntermAggregateBase *from, TIntermAggregateBase *to) { const TIntermSequence *fromSequence = from->getSequence(); for (size_t ii = 0; ii < fromSequence->size(); ++ii) @@ -22,156 +28,153 @@ void CopyAggregateChildren(TIntermAggregate *from, TIntermAggregate *to) } } -TIntermSymbol *CreateReturnValueSymbol(const TType &type) +TIntermSymbol *CreateReturnValueSymbol(const TSymbolUniqueId &id, const TType &type) { - TIntermSymbol *node = new TIntermSymbol(0, "angle_return", type); + TIntermSymbol *node = new TIntermSymbol(id, "angle_return", type); node->setInternal(true); + node->getTypePointer()->setQualifier(EvqOut); return node; } -TIntermSymbol *CreateReturnValueOutSymbol(const TType &type) +TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, + TIntermTyped *returnValueTarget) { - 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) + TIntermSequence *replacementArguments = new TIntermSequence(); + TIntermSequence *originalArguments = originalCall->getSequence(); + for (auto &arg : *originalArguments) { - replacementParameters->push_back(param); + replacementArguments->push_back(arg); } - replacementParameters->push_back(returnValueTarget); + replacementArguments->push_back(returnValueTarget); + TIntermAggregate *replacementCall = TIntermAggregate::CreateFunctionCall( + TType(EbtVoid), originalCall->getFunctionSymbolInfo()->getId(), + originalCall->getFunctionSymbolInfo()->getNameObj(), replacementArguments); + replacementCall->setLine(originalCall->getLine()); return replacementCall; } class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser { public: - static void apply(TIntermNode *root, unsigned int *temporaryIndex); + static void apply(TIntermNode *root, TSymbolTable *symbolTable); + private: - ArrayReturnValueToOutParameterTraverser(); + ArrayReturnValueToOutParameterTraverser(TSymbolTable *symbolTable); + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override; bool visitBranch(Visit visit, TIntermBranch *node) override; bool visitBinary(Visit visit, TIntermBinary *node) override; - bool mInFunctionWithArrayReturnValue; + // Set when traversal is inside a function with array return value. + TIntermFunctionDefinition *mFunctionWithArrayReturnValue; + + // Map from function symbol ids to array return value ids. + std::map mReturnValueIds; }; -void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, unsigned int *temporaryIndex) +void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, TSymbolTable *symbolTable) { - ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam; - arrayReturnValueToOutParam.useTemporaryIndex(temporaryIndex); + ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam(symbolTable); root->traverse(&arrayReturnValueToOutParam); arrayReturnValueToOutParam.updateTree(); } -ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser() - : TIntermTraverser(true, false, true), - mInFunctionWithArrayReturnValue(false) +ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser( + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFunctionWithArrayReturnValue(nullptr) { } -bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition( + Visit visit, + TIntermFunctionDefinition *node) +{ + if (node->getFunctionPrototype()->isArray() && visit == PreVisit) + { + // Replacing the function header is done on visitFunctionPrototype(). + mFunctionWithArrayReturnValue = node; + } + if (visit == PostVisit) + { + mFunctionWithArrayReturnValue = nullptr; + } + return true; +} + +bool ArrayReturnValueToOutParameterTraverser::visitFunctionPrototype(Visit visit, + TIntermFunctionPrototype *node) { - if (visit == PreVisit) + if (visit == PreVisit && node->isArray()) { - if (node->isArray()) + // Replace the whole prototype node with another node that has the out parameter + // added. Also set the function to return void. + TIntermFunctionPrototype *replacement = + new TIntermFunctionPrototype(TType(EbtVoid), node->getFunctionSymbolInfo()->getId()); + CopyAggregateChildren(node, replacement); + const TSymbolUniqueId &functionId = node->getFunctionSymbolInfo()->getId(); + if (mReturnValueIds.find(functionId.get()) == mReturnValueIds.end()) { - 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; - } + mReturnValueIds[functionId.get()] = new TSymbolUniqueId(mSymbolTable); } + replacement->getSequence()->push_back( + CreateReturnValueSymbol(*mReturnValueIds[functionId.get()], node->getType())); + *replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo(); + replacement->setLine(node->getLine()); + + queueReplacement(replacement, OriginalNode::IS_DROPPED); } - else if (visit == PostVisit) + return false; +} + +bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + ASSERT(!node->isArray() || node->getOp() != EOpCallInternalRawFunction); + if (visit == PreVisit && node->isArray() && node->getOp() == EOpCallFunctionInAST) { - if (node->getOp() == EOpFunction) + // 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. + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + if (parentBlock) { - mInFunctionWithArrayReturnValue = false; + nextTemporaryId(); + TIntermSequence replacements; + replacements.push_back(createTempDeclaration(node->getType())); + TIntermSymbol *returnSymbol = createTempSymbol(node->getType()); + replacements.push_back(CreateReplacementCall(node, returnSymbol)); + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); } + return false; } return true; } bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node) { - if (mInFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn) + if (mFunctionWithArrayReturnValue && 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()); + const TSymbolUniqueId &functionId = + mFunctionWithArrayReturnValue->getFunctionSymbolInfo()->getId(); + ASSERT(mReturnValueIds.find(functionId.get()) != mReturnValueIds.end()); + const TSymbolUniqueId &returnValueId = *mReturnValueIds[functionId.get()]; + TIntermSymbol *returnValueSymbol = + CreateReturnValueSymbol(returnValueId, expression->getType()); + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, returnValueSymbol, expression); replacementAssignment->setLine(expression->getLine()); replacements.push_back(replacementAssignment); @@ -179,7 +182,8 @@ bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBr replacementBranch->setLine(node->getLine()); replacements.push_back(replacementBranch); - mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsAggregate(), node, replacements)); + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements)); } return false; } @@ -189,18 +193,21 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi if (node->getOp() == EOpAssign && node->getLeft()->isArray()) { TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); - if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined()) + ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpCallInternalRawFunction); + if (rightAgg != nullptr && rightAgg->getOp() == EOpCallFunctionInAST) { TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft()); - mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false)); + queueReplacement(replacementCall, OriginalNode::IS_DROPPED); } } return false; } -} // namespace +} // namespace -void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex) +void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable) { - ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex); + ArrayReturnValueToOutParameterTraverser::apply(root, symbolTable); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h index 983e203e62..469c7a3b14 100644 --- a/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h +++ b/src/3rdparty/angle/src/compiler/translator/ArrayReturnValueToOutParameter.h @@ -3,14 +3,20 @@ // 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. +// 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_ +namespace sh +{ + class TIntermNode; +class TSymbolTable; + +void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable); -void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex); +} // namespace sh #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 0ed6d0e62f..b2070f3baf 100644 --- a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h +++ b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h @@ -7,7 +7,14 @@ #ifndef COMPILER_TRANSLATOR_BASETYPES_H_ #define COMPILER_TRANSLATOR_BASETYPES_H_ +#include +#include + #include "common/debug.h" +#include "GLSLANG/ShaderLang.h" + +namespace sh +{ // // Precision qualifiers @@ -24,14 +31,18 @@ enum TPrecision EbpLast }; -inline const char* getPrecisionString(TPrecision p) +inline const char *getPrecisionString(TPrecision p) { - switch(p) + switch (p) { - case EbpHigh: return "highp"; break; - case EbpMedium: return "mediump"; break; - case EbpLow: return "lowp"; break; - default: return "mediump"; break; // Safest fallback + case EbpHigh: + return "highp"; + case EbpMedium: + return "mediump"; + case EbpLow: + return "lowp"; + default: + return "mediump"; // Safest fallback } } @@ -54,69 +65,243 @@ enum TBasicType EbtIVec, // non type: represents ivec2, ivec3, and ivec4 EbtUVec, // non type: represents uvec2, uvec3, and uvec4 EbtBVec, // non type: represents bvec2, bvec3, and bvec4 + EbtYuvCscStandardEXT, // Only valid if EXT_YUV_target exists. EbtGuardSamplerBegin, // non type: see implementation of IsSampler() EbtSampler2D, EbtSampler3D, EbtSamplerCube, EbtSampler2DArray, - EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. - EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. + EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. + EbtSamplerExternal2DY2YEXT, // Only valid if GL_EXT_YUV_target exists. + EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. + EbtSampler2DMS, EbtISampler2D, EbtISampler3D, EbtISamplerCube, EbtISampler2DArray, + EbtISampler2DMS, EbtUSampler2D, EbtUSampler3D, EbtUSamplerCube, EbtUSampler2DArray, + EbtUSampler2DMS, EbtSampler2DShadow, EbtSamplerCubeShadow, EbtSampler2DArrayShadow, - EbtGuardSamplerEnd, // non type: see implementation of IsSampler() - EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D - EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D - EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube - EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and usampler2DArray + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D + EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D + EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube + EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and + // usampler2DArray + EbtGSampler2DMS, // non type: represents sampler2DMS, isampler2DMS, and usampler2DMS + + // images + EbtGuardImageBegin, + EbtImage2D, + EbtIImage2D, + EbtUImage2D, + EbtImage3D, + EbtIImage3D, + EbtUImage3D, + EbtImage2DArray, + EbtIImage2DArray, + EbtUImage2DArray, + EbtImageCube, + EbtIImageCube, + EbtUImageCube, + EbtGuardImageEnd, + + EbtGuardGImageBegin, + EbtGImage2D, // non type: represents image2D, uimage2D, iimage2D + EbtGImage3D, // non type: represents image3D, uimage3D, iimage3D + EbtGImage2DArray, // non type: represents image2DArray, uimage2DArray, iimage2DArray + EbtGImageCube, // non type: represents imageCube, uimageCube, iimageCube + EbtGuardGImageEnd, + EbtStruct, EbtInterfaceBlock, - EbtAddress, // should be deprecated?? + EbtAddress, // should be deprecated?? + + EbtAtomicCounter, // end of list EbtLast }; -const char* getBasicString(TBasicType t); +inline TBasicType convertGImageToFloatImage(TBasicType type) +{ + switch (type) + { + case EbtGImage2D: + return EbtImage2D; + case EbtGImage3D: + return EbtImage3D; + case EbtGImage2DArray: + return EbtImage2DArray; + case EbtGImageCube: + return EbtImageCube; + default: + UNREACHABLE(); + } + return EbtLast; +} + +inline TBasicType convertGImageToIntImage(TBasicType type) +{ + switch (type) + { + case EbtGImage2D: + return EbtIImage2D; + case EbtGImage3D: + return EbtIImage3D; + case EbtGImage2DArray: + return EbtIImage2DArray; + case EbtGImageCube: + return EbtIImageCube; + default: + UNREACHABLE(); + } + return EbtLast; +} + +inline TBasicType convertGImageToUnsignedImage(TBasicType type) +{ + switch (type) + { + case EbtGImage2D: + return EbtUImage2D; + case EbtGImage3D: + return EbtUImage3D; + case EbtGImage2DArray: + return EbtUImage2DArray; + case EbtGImageCube: + return EbtUImageCube; + default: + UNREACHABLE(); + } + return EbtLast; +} + +const char *getBasicString(TBasicType t); inline bool IsSampler(TBasicType type) { return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; } +inline bool IsImage(TBasicType type) +{ + return type > EbtGuardImageBegin && type < EbtGuardImageEnd; +} + +inline bool IsGImage(TBasicType type) +{ + return type > EbtGuardGImageBegin && type < EbtGuardGImageEnd; +} + +inline bool IsAtomicCounter(TBasicType type) +{ + return type == EbtAtomicCounter; +} + +inline bool IsOpaqueType(TBasicType type) +{ + return IsSampler(type) || IsImage(type) || IsAtomicCounter(type); +} + inline bool IsIntegerSampler(TBasicType type) { switch (type) { - case EbtISampler2D: - case EbtISampler3D: - case EbtISamplerCube: - case EbtISampler2DArray: - case EbtUSampler2D: - case EbtUSampler3D: - case EbtUSamplerCube: - case EbtUSampler2DArray: - return true; - case EbtSampler2D: - case EbtSampler3D: - case EbtSamplerCube: - case EbtSamplerExternalOES: - case EbtSampler2DRect: - case EbtSampler2DArray: - case EbtSampler2DShadow: - case EbtSamplerCubeShadow: - case EbtSampler2DArrayShadow: - return false; - default: - assert(!IsSampler(type)); + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + case EbtSampler2DMS: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler2DMS(TBasicType type) +{ + switch (type) + { + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return true; + default: + return false; + } +} + +inline bool IsFloatImage(TBasicType type) +{ + switch (type) + { + case EbtImage2D: + case EbtImage3D: + case EbtImage2DArray: + case EbtImageCube: + return true; + default: + break; + } + + return false; +} + +inline bool IsIntegerImage(TBasicType type) +{ + + switch (type) + { + case EbtIImage2D: + case EbtIImage3D: + case EbtIImage2DArray: + case EbtIImageCube: + return true; + default: + break; + } + + return false; +} + +inline bool IsUnsignedImage(TBasicType type) +{ + + switch (type) + { + case EbtUImage2D: + case EbtUImage3D: + case EbtUImage2DArray: + case EbtUImageCube: + return true; + default: + break; } return false; @@ -126,27 +311,31 @@ inline bool IsSampler2D(TBasicType type) { switch (type) { - case EbtSampler2D: - case EbtISampler2D: - case EbtUSampler2D: - case EbtSampler2DArray: - case EbtISampler2DArray: - case EbtUSampler2DArray: - case EbtSampler2DRect: - case EbtSamplerExternalOES: - case EbtSampler2DShadow: - case EbtSampler2DArrayShadow: - return true; - case EbtSampler3D: - case EbtISampler3D: - case EbtUSampler3D: - case EbtISamplerCube: - case EbtUSamplerCube: - case EbtSamplerCube: - case EbtSamplerCubeShadow: - return false; - default: - assert(!IsSampler(type)); + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return true; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); } return false; @@ -156,27 +345,31 @@ inline bool IsSamplerCube(TBasicType type) { switch (type) { - case EbtSamplerCube: - case EbtISamplerCube: - case EbtUSamplerCube: - case EbtSamplerCubeShadow: - return true; - case EbtSampler2D: - case EbtSampler3D: - case EbtSamplerExternalOES: - case EbtSampler2DRect: - case EbtSampler2DArray: - case EbtISampler2D: - case EbtISampler3D: - case EbtISampler2DArray: - case EbtUSampler2D: - case EbtUSampler3D: - case EbtUSampler2DArray: - case EbtSampler2DShadow: - case EbtSampler2DArrayShadow: - return false; - default: - assert(!IsSampler(type)); + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + case EbtISampler2D: + case EbtISampler3D: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); } return false; @@ -186,27 +379,31 @@ inline bool IsSampler3D(TBasicType type) { switch (type) { - case EbtSampler3D: - case EbtISampler3D: - case EbtUSampler3D: - return true; - case EbtSampler2D: - case EbtSamplerCube: - case EbtSamplerExternalOES: - case EbtSampler2DRect: - case EbtSampler2DArray: - case EbtISampler2D: - case EbtISamplerCube: - case EbtISampler2DArray: - case EbtUSampler2D: - case EbtUSamplerCube: - case EbtUSampler2DArray: - case EbtSampler2DShadow: - case EbtSamplerCubeShadow: - case EbtSampler2DArrayShadow: - return false; - default: - assert(!IsSampler(type)); + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + return true; + case EbtSampler2D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + case EbtISampler2D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtUSampler2D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); } return false; @@ -216,27 +413,31 @@ inline bool IsSamplerArray(TBasicType type) { switch (type) { - case EbtSampler2DArray: - case EbtISampler2DArray: - case EbtUSampler2DArray: - case EbtSampler2DArrayShadow: - return true; - case EbtSampler2D: - case EbtISampler2D: - case EbtUSampler2D: - case EbtSampler2DRect: - case EbtSamplerExternalOES: - case EbtSampler3D: - case EbtISampler3D: - case EbtUSampler3D: - case EbtISamplerCube: - case EbtUSamplerCube: - case EbtSamplerCube: - case EbtSampler2DShadow: - case EbtSamplerCubeShadow: - return false; - default: - assert(!IsSampler(type)); + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return false; + default: + assert(!IsSampler(type)); } return false; @@ -246,27 +447,131 @@ inline bool IsShadowSampler(TBasicType type) { switch (type) { - case EbtSampler2DShadow: - case EbtSamplerCubeShadow: - case EbtSampler2DArrayShadow: - return true; - case EbtISampler2D: - case EbtISampler3D: - case EbtISamplerCube: - case EbtISampler2DArray: - case EbtUSampler2D: - case EbtUSampler3D: - case EbtUSamplerCube: - case EbtUSampler2DArray: - case EbtSampler2D: - case EbtSampler3D: - case EbtSamplerCube: - case EbtSamplerExternalOES: - case EbtSampler2DRect: - case EbtSampler2DArray: - return false; - default: - assert(!IsSampler(type)); + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsImage2D(TBasicType type) +{ + switch (type) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + return true; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImage3D(TBasicType type) +{ + switch (type) + { + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImage2DArray(TBasicType type) +{ + switch (type) + { + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImageCube(TBasicType type) +{ + switch (type) + { + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return false; + default: + assert(!IsImage(type)); } return false; @@ -279,7 +584,7 @@ inline bool IsInteger(TBasicType type) inline bool SupportsPrecision(TBasicType type) { - return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); + return type == EbtFloat || type == EbtInt || type == EbtUInt || IsOpaqueType(type); } // @@ -297,6 +602,7 @@ enum TQualifier EvqVaryingIn, // readonly, fragment shaders only EvqVaryingOut, // vertex shaders only read/write EvqUniform, // Readonly, vertex and fragment + EvqBuffer, // read/write, vertex, fragment and compute shader EvqVertexIn, // Vertex shader input EvqFragmentOut, // Fragment shader output @@ -311,6 +617,7 @@ enum TQualifier // built-ins read by vertex shader EvqInstanceID, + EvqVertexID, // built-ins written by vertex shader EvqPosition, @@ -331,24 +638,77 @@ enum TQualifier EvqSecondaryFragColorEXT, // EXT_blend_func_extended EvqSecondaryFragDataEXT, // EXT_blend_func_extended + EvqViewIDOVR, // OVR_multiview + EvqViewportIndex, // gl_ViewportIndex + // 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 - EvqSmoothOut = EvqSmooth, - EvqFlatOut = EvqFlat, + EvqSmooth, // Incomplete qualifier, smooth is the default + EvqFlat, // Incomplete qualifier + EvqCentroid, // Incomplete qualifier + EvqSmoothOut, + EvqFlatOut, EvqCentroidOut, // Implies smooth EvqSmoothIn, EvqFlatIn, EvqCentroidIn, // Implies smooth + // GLSL ES 3.1 compute shader special variables + EvqShared, + EvqComputeIn, + EvqNumWorkGroups, + EvqWorkGroupSize, + EvqWorkGroupID, + EvqLocalInvocationID, + EvqGlobalInvocationID, + EvqLocalInvocationIndex, + + // GLSL ES 3.1 memory qualifiers + EvqReadOnly, + EvqWriteOnly, + EvqCoherent, + EvqRestrict, + EvqVolatile, + + // GLSL ES 3.1 extension OES_geometry_shader qualifiers + EvqGeometryIn, + EvqGeometryOut, + EvqPerVertexIn, // gl_in + EvqPrimitiveIDIn, // gl_PrimitiveIDIn + EvqInvocationID, // gl_InvocationID + EvqPrimitiveID, // gl_PrimitiveID + EvqLayer, // gl_Layer + // end of list EvqLast }; +inline bool IsQualifierUnspecified(TQualifier qualifier) +{ + return (qualifier == EvqTemporary || qualifier == EvqGlobal); +} + +enum TLayoutImageInternalFormat +{ + EiifUnspecified, + EiifRGBA32F, + EiifRGBA16F, + EiifR32F, + EiifRGBA32UI, + EiifRGBA16UI, + EiifRGBA8UI, + EiifR32UI, + EiifRGBA32I, + EiifRGBA16I, + EiifRGBA8I, + EiifR32I, + EiifRGBA8, + EiifRGBA8_SNORM +}; + enum TLayoutMatrixPacking { EmpUnspecified, @@ -361,36 +721,165 @@ enum TLayoutBlockStorage EbsUnspecified, EbsShared, EbsPacked, - EbsStd140 + EbsStd140, + EbsStd430 +}; + +enum TYuvCscStandardEXT +{ + EycsUndefined, + EycsItu601, + EycsItu601FullRange, + EycsItu709 +}; + +enum TLayoutPrimitiveType +{ + EptUndefined, + EptPoints, + EptLines, + EptLinesAdjacency, + EptTriangles, + EptTrianglesAdjacency, + EptLineStrip, + EptTriangleStrip }; struct TLayoutQualifier { + // Must have a trivial default constructor since it is used in YYSTYPE. + TLayoutQualifier() = default; + + constexpr static TLayoutQualifier Create() { return TLayoutQualifier(0); } + + bool isEmpty() const + { + return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false && + matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified && + !localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified && + primitiveType == EptUndefined && invocations == 0 && maxVertices == -1; + } + + bool isCombinationValid() const + { + bool workSizeSpecified = localSize.isAnyValueSet(); + bool numViewsSet = (numViews != -1); + bool geometryShaderSpecified = + (primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1); + bool otherLayoutQualifiersSpecified = + (location != -1 || binding != -1 || matrixPacking != EmpUnspecified || + blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified); + + // we can have either the work group size specified, or number of views, + // or yuv layout qualifier, or the other layout qualifiers. + return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) + + (otherLayoutQualifiersSpecified ? 1 : 0) + (geometryShaderSpecified ? 1 : 0) <= + 1; + } + + bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const + { + return localSize.isWorkGroupSizeMatching(localSizeIn); + } + int location; + unsigned int locationsSpecified; TLayoutMatrixPacking matrixPacking; TLayoutBlockStorage blockStorage; - static TLayoutQualifier create() - { - TLayoutQualifier layoutQualifier; + // Compute shader layout qualifiers. + sh::WorkGroupSize localSize; + + int binding; + int offset; + + // Image format layout qualifier + TLayoutImageInternalFormat imageInternalFormat; + + // OVR_multiview num_views. + int numViews; + + // EXT_YUV_target yuv layout qualifier. + bool yuv; - layoutQualifier.location = -1; - layoutQualifier.matrixPacking = EmpUnspecified; - layoutQualifier.blockStorage = EbsUnspecified; + // OES_geometry_shader layout qualifiers. + TLayoutPrimitiveType primitiveType; + int invocations; + int maxVertices; - return layoutQualifier; + private: + explicit constexpr TLayoutQualifier(int /*placeholder*/) + : location(-1), + locationsSpecified(0), + matrixPacking(EmpUnspecified), + blockStorage(EbsUnspecified), + localSize(-1), + binding(-1), + offset(-1), + imageInternalFormat(EiifUnspecified), + numViews(-1), + yuv(false), + primitiveType(EptUndefined), + invocations(0), + maxVertices(-1) + { } +}; + +struct TMemoryQualifier +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + TMemoryQualifier() = default; bool isEmpty() const { - return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified; + return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier; + } + + constexpr static TMemoryQualifier Create() { return TMemoryQualifier(0); } + + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + // An image can be qualified as both readonly and writeonly. It still can be can be used with + // imageSize(). + bool readonly; + bool writeonly; + bool coherent; + + // restrict and volatile are reserved keywords in C/C++ + bool restrictQualifier; + bool volatileQualifier; + + private: + explicit constexpr TMemoryQualifier(int /*placeholder*/) + : readonly(false), + writeonly(false), + coherent(false), + restrictQualifier(false), + volatileQualifier(false) + { } }; +inline const char *getWorkGroupSizeString(size_t dimension) +{ + switch (dimension) + { + case 0u: + return "local_size_x"; + case 1u: + return "local_size_y"; + case 2u: + return "local_size_z"; + default: + UNREACHABLE(); + return "dimension out of bounds"; + } +} + // -// This is just for debug print out, carried along with the definitions above. +// This is just for debug and error message print out, carried along with the definitions above. // -inline const char* getQualifierString(TQualifier q) +inline const char *getQualifierString(TQualifier q) { // clang-format off switch(q) @@ -402,6 +891,7 @@ inline const char* getQualifierString(TQualifier q) case EvqVaryingIn: return "varying"; case EvqVaryingOut: return "varying"; case EvqUniform: return "uniform"; + case EvqBuffer: return "buffer"; case EvqVertexIn: return "in"; case EvqFragmentOut: return "out"; case EvqVertexOut: return "out"; @@ -411,6 +901,7 @@ inline const char* getQualifierString(TQualifier q) case EvqInOut: return "inout"; case EvqConstReadOnly: return "const"; case EvqInstanceID: return "InstanceID"; + case EvqVertexID: return "VertexID"; case EvqPosition: return "Position"; case EvqPointSize: return "PointSize"; case EvqFragCoord: return "FragCoord"; @@ -422,54 +913,161 @@ inline const char* getQualifierString(TQualifier q) case EvqFragDepth: return "FragDepth"; case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT"; case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT"; + case EvqViewIDOVR: return "ViewIDOVR"; + case EvqViewportIndex: return "ViewportIndex"; + case EvqLayer: return "Layer"; case EvqLastFragColor: return "LastFragColor"; case EvqLastFragData: return "LastFragData"; case EvqSmoothOut: return "smooth out"; - case EvqCentroidOut: return "centroid out"; + case EvqCentroidOut: return "smooth centroid out"; case EvqFlatOut: return "flat out"; case EvqSmoothIn: return "smooth in"; case EvqFlatIn: return "flat in"; - case EvqCentroidIn: return "centroid in"; + case EvqCentroidIn: return "smooth centroid in"; + case EvqCentroid: return "centroid"; + case EvqFlat: return "flat"; + case EvqSmooth: return "smooth"; + case EvqShared: return "shared"; + case EvqComputeIn: return "in"; + case EvqNumWorkGroups: return "NumWorkGroups"; + case EvqWorkGroupSize: return "WorkGroupSize"; + case EvqWorkGroupID: return "WorkGroupID"; + case EvqLocalInvocationID: return "LocalInvocationID"; + case EvqGlobalInvocationID: return "GlobalInvocationID"; + case EvqLocalInvocationIndex: return "LocalInvocationIndex"; + case EvqReadOnly: return "readonly"; + case EvqWriteOnly: return "writeonly"; + case EvqGeometryIn: return "in"; + case EvqGeometryOut: return "out"; + case EvqPerVertexIn: return "gl_in"; default: UNREACHABLE(); return "unknown qualifier"; } // clang-format on } -inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) +inline const char *getMatrixPackingString(TLayoutMatrixPacking mpq) { switch (mpq) { - case EmpUnspecified: return "mp_unspecified"; - case EmpRowMajor: return "row_major"; - case EmpColumnMajor: return "column_major"; - default: UNREACHABLE(); return "unknown matrix packing"; + case EmpUnspecified: + return "mp_unspecified"; + case EmpRowMajor: + return "row_major"; + case EmpColumnMajor: + return "column_major"; + default: + UNREACHABLE(); + return "unknown matrix packing"; } } -inline const char* getBlockStorageString(TLayoutBlockStorage bsq) +inline const char *getBlockStorageString(TLayoutBlockStorage bsq) { switch (bsq) { - case EbsUnspecified: return "bs_unspecified"; - case EbsShared: return "shared"; - case EbsPacked: return "packed"; - case EbsStd140: return "std140"; - default: UNREACHABLE(); return "unknown block storage"; + case EbsUnspecified: + return "bs_unspecified"; + case EbsShared: + return "shared"; + case EbsPacked: + return "packed"; + case EbsStd140: + return "std140"; + case EbsStd430: + return "std430"; + default: + UNREACHABLE(); + return "unknown block storage"; } } -inline const char* getInterpolationString(TQualifier q) +inline const char *getImageInternalFormatString(TLayoutImageInternalFormat iifq) { - switch(q) + switch (iifq) + { + case EiifRGBA32F: + return "rgba32f"; + case EiifRGBA16F: + return "rgba16f"; + case EiifR32F: + return "r32f"; + case EiifRGBA32UI: + return "rgba32ui"; + case EiifRGBA16UI: + return "rgba16ui"; + case EiifRGBA8UI: + return "rgba8ui"; + case EiifR32UI: + return "r32ui"; + case EiifRGBA32I: + return "rgba32i"; + case EiifRGBA16I: + return "rgba16i"; + case EiifRGBA8I: + return "rgba8i"; + case EiifR32I: + return "r32i"; + case EiifRGBA8: + return "rgba8"; + case EiifRGBA8_SNORM: + return "rgba8_snorm"; + default: + UNREACHABLE(); + return "unknown internal image format"; + } +} + +inline TYuvCscStandardEXT getYuvCscStandardEXT(const std::string &str) +{ + if (str == "itu_601") + return EycsItu601; + else if (str == "itu_601_full_range") + return EycsItu601FullRange; + else if (str == "itu_709") + return EycsItu709; + return EycsUndefined; +} + +inline const char *getYuvCscStandardEXTString(TYuvCscStandardEXT ycsq) +{ + switch (ycsq) + { + case EycsItu601: + return "itu_601"; + case EycsItu601FullRange: + return "itu_601_full_range"; + case EycsItu709: + return "itu_709"; + default: + UNREACHABLE(); + return "unknown color space conversion standard"; + } +} + +inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) { - case EvqSmoothOut: return "smooth"; break; - case EvqCentroidOut: return "centroid"; break; - case EvqFlatOut: return "flat"; break; - case EvqSmoothIn: return "smooth"; break; - case EvqCentroidIn: return "centroid"; break; - case EvqFlatIn: return "flat"; break; - default: UNREACHABLE(); return "unknown interpolation"; + case EptPoints: + return "points"; + case EptLines: + return "lines"; + case EptTriangles: + return "triangles"; + case EptLinesAdjacency: + return "lines_adjacency"; + case EptTrianglesAdjacency: + return "triangles_adjacency"; + case EptLineStrip: + return "line_strip"; + case EptTriangleStrip: + return "triangle_strip"; + default: + UNREACHABLE(); + return "unknown geometry shader primitive type"; } } -#endif // COMPILER_TRANSLATOR_BASETYPES_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BASETYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp b/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp new file mode 100644 index 0000000000..d6a1e025de --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#include "BreakVariableAliasingInInnerLoops.h" + +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" + +// A HLSL compiler developer gave us more details on the root cause and the workaround needed: +// The root problem is that if the HLSL compiler is applying aliasing information even on +// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment +// that comes from a series of assignments, possibly with swizzled or ternary operators with +// known conditionals, where the source is before the loop. +// So, a workaround is to add a +0 term to variables the first time they are assigned to in +// an inner loop (if they are declared in an outside scope, otherwise there is no need). +// This will break the aliasing chain. + +// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because +// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure +// assignment don't need a workaround. + +namespace sh +{ + +namespace +{ + +class AliasingBreaker : public TIntermTraverser +{ + public: + AliasingBreaker() : TIntermTraverser(true, false, true) {} + + protected: + bool visitBinary(Visit visit, TIntermBinary *binary) + { + if (visit != PreVisit) + { + return false; + } + + if (mLoopLevel < 2 || !binary->isAssignment()) + { + return true; + } + + TIntermTyped *B = binary->getRight(); + TType type = B->getType(); + + if (!type.isScalar() && !type.isVector() && !type.isMatrix()) + { + return true; + } + + if (type.isArray() || IsSampler(type.getBasicType())) + { + return true; + } + + // We have a scalar / vector / matrix assignment with loop depth 2. + // Transform it from + // A = B + // to + // A = (B + typeof(0)); + + TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type)); + bPlusZero->setLine(B->getLine()); + + binary->replaceChildNode(B, bPlusZero); + + return true; + } + + bool visitLoop(Visit visit, TIntermLoop *loop) + { + if (visit == PreVisit) + { + mLoopLevel++; + } + else + { + ASSERT(mLoopLevel > 0); + mLoopLevel--; + } + + return true; + } + + private: + int mLoopLevel = 0; +}; + +} // anonymous namespace + +void BreakVariableAliasingInInnerLoops(TIntermNode *root) +{ + AliasingBreaker breaker; + root->traverse(&breaker); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h b/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h new file mode 100644 index 0000000000..b1d906f919 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ +#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ + +class TIntermNode; + +namespace sh +{ + +void BreakVariableAliasingInInnerLoops(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp index 0c7f149ee6..905e634fd1 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -4,16 +4,20 @@ // found in the LICENSE file. // -#include "angle_gl.h" #include "compiler/translator/BuiltInFunctionEmulator.h" +#include "angle_gl.h" +#include "compiler/translator/Cache.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/SymbolTable.h" +namespace sh +{ + class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser { public: BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator) - : TIntermTraverser(true, false, false), - mEmulator(emulator) + : TIntermTraverser(true, false, false), mEmulator(emulator) { } @@ -21,7 +25,8 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr { if (visit == PreVisit) { - bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType()); + bool needToEmulate = + mEmulator.setFunctionCalled(node->getOp(), node->getOperand()->getType()); if (needToEmulate) node->setUseEmulatedFunction(); } @@ -32,48 +37,23 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr { if (visit == PreVisit) { - // Here we handle all the built-in functions instead of the ones we + // Here we handle all the built-in functions mapped to ops, not just the ones that are // currently identified as problematic. - switch (node->getOp()) + if (node->isConstructor() || node->isFunctionCall()) { - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - case EOpVectorEqual: - case EOpVectorNotEqual: - case EOpMod: - case EOpPow: - case EOpAtan: - case EOpMin: - case EOpMax: - case EOpClamp: - case EOpMix: - case EOpStep: - case EOpSmoothStep: - case EOpDistance: - case EOpDot: - case EOpCross: - case EOpFaceForward: - case EOpReflect: - case EOpRefract: - case EOpOuterProduct: - case EOpMul: - break; - default: - return true; + return true; } const TIntermSequence &sequence = *(node->getSequence()); - bool needToEmulate = false; - // Right now we only handle built-in functions with two or three parameters. + bool needToEmulate = false; + // Right now we only handle built-in functions with two to four parameters. if (sequence.size() == 2) { TIntermTyped *param1 = sequence[0]->getAsTyped(); TIntermTyped *param2 = sequence[1]->getAsTyped(); if (!param1 || !param2) return true; - needToEmulate = mEmulator.SetFunctionCalled( - node->getOp(), param1->getType(), param2->getType()); + needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(), + param2->getType()); } else if (sequence.size() == 3) { @@ -82,8 +62,20 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr TIntermTyped *param3 = sequence[2]->getAsTyped(); if (!param1 || !param2 || !param3) return true; - needToEmulate = mEmulator.SetFunctionCalled( - node->getOp(), param1->getType(), param2->getType(), param3->getType()); + needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(), + param2->getType(), param3->getType()); + } + else if (sequence.size() == 4) + { + TIntermTyped *param1 = sequence[0]->getAsTyped(); + TIntermTyped *param2 = sequence[1]->getAsTyped(); + TIntermTyped *param3 = sequence[2]->getAsTyped(); + TIntermTyped *param4 = sequence[3]->getAsTyped(); + if (!param1 || !param2 || !param3 || !param4) + return true; + needToEmulate = + mEmulator.setFunctionCalled(node->getOp(), param1->getType(), param2->getType(), + param3->getType(), param4->getType()); } else { @@ -101,130 +93,245 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr }; BuiltInFunctionEmulator::BuiltInFunctionEmulator() -{} +{ +} -void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param, - const char *emulatedFunctionDefinition) +FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, + const TType *param, + const char *emulatedFunctionDefinition) { - mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition); + FunctionId id(op, param); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + return id; } -void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, - const char *emulatedFunctionDefinition) +FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const char *emulatedFunctionDefinition) { - mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition); + FunctionId id(op, param1, param2); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + return id; } -void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, - const TType *param3, const char *emulatedFunctionDefinition) +FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( + const FunctionId &dependency, + TOperator op, + const TType *param1, + const TType *param2, + const char *emulatedFunctionDefinition) { - mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition); + FunctionId id(op, param1, param2); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + mFunctionDependencies[id] = dependency; + return id; } -bool BuiltInFunctionEmulator::IsOutputEmpty() const +FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const char *emulatedFunctionDefinition) +{ + FunctionId id(op, param1, param2, param3); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + return id; +} + +FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const TType *param4, + const char *emulatedFunctionDefinition) +{ + FunctionId id(op, param1, param2, param3, param4); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + return id; +} + +FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( + const FunctionId &dependency, + TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const TType *param4, + const char *emulatedFunctionDefinition) +{ + FunctionId id(op, param1, param2, param3, param4); + mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition); + mFunctionDependencies[id] = dependency; + return id; +} + +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 (const auto &function : mFunctions) { - out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n"; + const char *body = findEmulatedFunction(function); + ASSERT(body); + out << body; + out << "\n\n"; } } -bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m) +bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, const TType ¶m) { - return SetFunctionCalled(FunctionId(op, ¶m)); + return setFunctionCalled(FunctionId(op, ¶m)); } -bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2) +bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, + const TType ¶m1, + const TType ¶m2) { - return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2)); + return setFunctionCalled(FunctionId(op, ¶m1, ¶m2)); } -bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, - const TType ¶m1, const TType ¶m2, const TType ¶m3) +bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, + const TType ¶m1, + const TType ¶m2, + const TType ¶m3) { - return SetFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3)); + return setFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3)); } -bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId) +bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, + const TType ¶m1, + const TType ¶m2, + const TType ¶m3, + const TType ¶m4) { - if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end()) + return setFunctionCalled(FunctionId(op, ¶m1, ¶m2, ¶m3, ¶m4)); +} + +const char *BuiltInFunctionEmulator::findEmulatedFunction(const FunctionId &functionId) const +{ + for (const auto &queryFunction : mQueryFunctions) { - for (size_t i = 0; i < mFunctions.size(); ++i) + const char *result = queryFunction(functionId); + if (result) { - if (mFunctions[i] == functionId) - return true; + return result; } - // 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; + + const auto &result = mEmulatedFunctions.find(functionId); + if (result != mEmulatedFunctions.end()) + { + return result->second.c_str(); + } + + return nullptr; +} + +bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId) +{ + if (!findEmulatedFunction(functionId)) + { + return false; + } + + for (size_t i = 0; i < mFunctions.size(); ++i) + { + if (mFunctions[i] == functionId) + return true; + } + // If the function depends on another, mark the dependency as called. + auto dependency = mFunctionDependencies.find(functionId); + if (dependency != mFunctionDependencies.end()) + { + setFunctionCalled((*dependency).second); + } + // 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; } -void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root) +void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root) { ASSERT(root); - if (mEmulatedFunctions.empty()) + if (mEmulatedFunctions.empty() && mQueryFunctions.empty()) return; BuiltInFunctionEmulationMarker marker(*this); root->traverse(&marker); } -void BuiltInFunctionEmulator::Cleanup() +void BuiltInFunctionEmulator::cleanup() { mFunctions.clear(); + mFunctionDependencies.clear(); +} + +void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc) +{ + mQueryFunctions.push_back(queryFunc); +} + +// static +void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name) +{ + ASSERT(name[strlen(name) - 1] != '('); + out << name << "_emu"; } -//static -TString BuiltInFunctionEmulator::GetEmulatedFunctionName( - const TString &name) +FunctionId::FunctionId() + : mOp(EOpNull), + mParam1(TCache::getType(EbtVoid)), + mParam2(TCache::getType(EbtVoid)), + mParam3(TCache::getType(EbtVoid)), + mParam4(TCache::getType(EbtVoid)) { - ASSERT(name[name.length() - 1] == '('); - return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; } -BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param) +FunctionId::FunctionId(TOperator op, const TType *param) : mOp(op), mParam1(param), - mParam2(new TType(EbtVoid)), - mParam3(new TType(EbtVoid)) + mParam2(TCache::getType(EbtVoid)), + mParam3(TCache::getType(EbtVoid)), + mParam4(TCache::getType(EbtVoid)) { } -BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2) +FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2) : mOp(op), mParam1(param1), mParam2(param2), - mParam3(new TType(EbtVoid)) + mParam3(TCache::getType(EbtVoid)), + mParam4(TCache::getType(EbtVoid)) { } -BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, - const TType *param1, const TType *param2, const TType *param3) - : mOp(op), - mParam1(param1), - mParam2(param2), - mParam3(param3) +FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3) + : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(TCache::getType(EbtVoid)) { } -bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const +FunctionId::FunctionId(TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const TType *param4) + : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(param4) { - return (mOp == other.mOp && - *mParam1 == *other.mParam1 && - *mParam2 == *other.mParam2 && - *mParam3 == *other.mParam3); } -bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulator::FunctionId &other) const +bool FunctionId::operator==(const FunctionId &other) const +{ + return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 && + *mParam3 == *other.mParam3 && *mParam4 == *other.mParam4); +} + +bool FunctionId::operator<(const FunctionId &other) const { if (mOp != other.mOp) return mOp < other.mOp; @@ -233,11 +340,16 @@ bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulato if (*mParam2 != *other.mParam2) return *mParam2 < *other.mParam2; if (*mParam3 != *other.mParam3) - return *mParam3 < *other.mParam3; - return false; // all fields are equal + return *mParam3 < *other.mParam3; + if (*mParam4 != *other.mParam4) + return *mParam4 < *other.mParam4; + return false; // all fields are equal } -BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const +FunctionId FunctionId::getCopy() const { - return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3)); + return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3), + new TType(*mParam4)); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h index 6976edfd57..5f15f66224 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h @@ -9,77 +9,175 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/ParamType.h" + +namespace sh +{ + +struct MiniFunctionId +{ + constexpr MiniFunctionId(TOperator op = EOpNull, + ParamType paramType1 = ParamType::Void, + ParamType paramType2 = ParamType::Void, + ParamType paramType3 = ParamType::Void, + ParamType paramType4 = ParamType::Void) + : op(op), + paramType1(paramType1), + paramType2(paramType2), + paramType3(paramType3), + paramType4(paramType4) + { + } + + TOperator op; + ParamType paramType1; + ParamType paramType2; + ParamType paramType3; + ParamType paramType4; +}; + +class FunctionId final +{ + public: + FunctionId(); + 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 *param1, + const TType *param2, + const TType *param3, + const TType *param4); + + FunctionId(const FunctionId &) = default; + FunctionId &operator=(const FunctionId &) = default; + + bool operator==(const FunctionId &other) const; + bool operator<(const FunctionId &other) const; + + FunctionId getCopy() const; + + private: + friend bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId); + TOperator mOp; + + // 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; + const TType *mParam4; +}; + +inline bool operator==(ParamType paramType, const TType *type) +{ + return SameParamType(paramType, type->getBasicType(), type->getNominalSize(), + type->getSecondarySize()); +} + +inline bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId) +{ + return miniId.op == functionId.mOp && miniId.paramType1 == functionId.mParam1 && + miniId.paramType2 == functionId.mParam2 && miniId.paramType3 == functionId.mParam3 && + miniId.paramType4 == functionId.mParam4; +} + +using BuiltinQueryFunc = const char *(const FunctionId &); // -// This class decides which built-in functions need to be replaced with the -// emulated ones. -// It can be used to work around driver bugs or implement functions that are -// not natively implemented on a specific platform. +// This class decides which built-in functions need to be replaced with the emulated ones. It can be +// used to work around driver bugs or implement functions that are not natively implemented on a +// specific platform. // class BuiltInFunctionEmulator { public: BuiltInFunctionEmulator(); - void MarkBuiltInFunctionsForEmulation(TIntermNode *root); + void markBuiltInFunctionsForEmulation(TIntermNode *root); - void Cleanup(); + void cleanup(); - // "name(" becomes "webgl_name_emu(". - static TString GetEmulatedFunctionName(const TString &name); + // "name" gets written as "name_emu". + static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name); - bool IsOutputEmpty() const; + bool isOutputEmpty() const; - // Output function emulation definition. This should be before any other - // shader source. - void OutputEmulatedFunctions(TInfoSinkBase &out) const; + // Output function emulation definition. This should be before any other shader source. + void outputEmulatedFunctions(TInfoSinkBase &out) const; // Add functions that need to be emulated. - void addEmulatedFunction(TOperator op, const TType *param, const char *emulatedFunctionDefinition); - void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, - const char *emulatedFunctionDefinition); - void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, const TType *param3, - const char *emulatedFunctionDefinition); + FunctionId addEmulatedFunction(TOperator op, + const TType *param, + const char *emulatedFunctionDefinition); + FunctionId addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const char *emulatedFunctionDefinition); + FunctionId addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const char *emulatedFunctionDefinition); + FunctionId addEmulatedFunction(TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const TType *param4, + const char *emulatedFunctionDefinition); + + FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency, + TOperator op, + const TType *param1, + const TType *param2, + const char *emulatedFunctionDefinition); + FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency, + TOperator op, + const TType *param1, + const TType *param2, + const TType *param3, + const TType *param4, + const char *emulatedFunctionDefinition); + + void addFunctionMap(BuiltinQueryFunc queryFunc); private: class BuiltInFunctionEmulationMarker; - // Records that a function is called by the shader and might need to be - // emulated. If the function is not in mEmulatedFunctions, this becomes a - // no-op. Returns true if the function call needs to be replaced with an - // emulated one. - bool SetFunctionCalled(TOperator op, const TType ¶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); - - bool operator==(const FunctionId &other) const; - bool operator<(const FunctionId &other) const; - - FunctionId getCopy() const; - private: - TOperator mOp; - - // 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); + // Records that a function is called by the shader and might need to be emulated. If the + // function is not in mEmulatedFunctions, this becomes a no-op. Returns true if the function + // call needs to be replaced with an emulated one. + bool setFunctionCalled(TOperator op, const TType ¶m); + bool setFunctionCalled(TOperator op, const TType ¶m1, const TType ¶m2); + bool setFunctionCalled(TOperator op, + const TType ¶m1, + const TType ¶m2, + const TType ¶m3); + bool setFunctionCalled(TOperator op, + const TType ¶m1, + const TType ¶m2, + const TType ¶m3, + const TType ¶m4); + + bool setFunctionCalled(const FunctionId &functionId); + + const char *findEmulatedFunction(const FunctionId &functionId) const; // Map from function id to emulated function definition std::map mEmulatedFunctions; + // Map from dependent functions to their dependencies. This structure allows each function to + // have at most one dependency. + std::map mFunctionDependencies; + // Called function ids std::vector mFunctions; + + // Constexpr function tables. + std::vector mQueryFunctions; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp index 098560d110..27ee04da35 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp @@ -11,47 +11,147 @@ #include "compiler/translator/SymbolTable.h" #include "compiler/translator/VersionGLSL.h" -void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType) +namespace sh { - // we use macros here instead of function definitions to work around more GLSL - // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are - // problematic because if the argument has side-effects they will be repeatedly - // evaluated. This is unlikely to show up in real shaders, but is something to - // consider. + +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType) +{ + if (shaderType == GL_VERTEX_SHADER) + { + const TType *int1 = TCache::getType(EbtInt); + emu->addEmulatedFunction(EOpAbs, int1, "int abs_emu(int x) { return x * sign(x); }"); + } +} + +void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion) +{ + // isnan() is supported since GLSL 1.3. + if (targetGLSLVersion < GLSL_VERSION_130) + return; 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) + // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false. + emu->addEmulatedFunction( + EOpIsNan, float1, + "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }"); + emu->addEmulatedFunction( + EOpIsNan, float2, + "bvec2 isnan_emu(vec2 x)\n" + "{\n" + " bvec2 isnan;\n" + " for (int i = 0; i < 2; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + emu->addEmulatedFunction( + EOpIsNan, float3, + "bvec3 isnan_emu(vec3 x)\n" + "{\n" + " bvec3 isnan;\n" + " for (int i = 0; i < 3; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + emu->addEmulatedFunction( + EOpIsNan, float4, + "bvec4 isnan_emu(vec4 x)\n" + "{\n" + " bvec4 isnan;\n" + " for (int i = 0; i < 4; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); +} + +void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu) +{ + const TType *float1 = TCache::getType(EbtFloat); + auto floatFuncId = emu->addEmulatedFunction( + EOpAtan, float1, float1, + "emu_precision float atan_emu(emu_precision float y, emu_precision " + "float x)\n" + "{\n" + " if (x > 0.0) return atan(y / x);\n" + " else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n" + " else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n" + " else return 1.57079632 * sign(y);\n" + "}\n"); + for (int dim = 2; dim <= 4; ++dim) { - emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }"); - emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }"); - emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }"); - emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }"); + const TType *floatVec = TCache::getType(EbtFloat, static_cast(dim)); + std::stringstream ss; + ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim + << " y, emu_precision vec" << dim << " x)\n" + << "{\n" + " return vec" + << dim << "("; + for (int i = 0; i < dim; ++i) + { + ss << "atan_emu(y[" << i << "], x[" << i << "])"; + if (i < dim - 1) + { + ss << ", "; + } + } + ss << ");\n" + "}\n"; + emu->addEmulatedFunctionWithDependency(floatFuncId, EOpAtan, floatVec, floatVec, + ss.str().c_str()); } - emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))"); - emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))"); - emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))"); - emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))"); - emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))"); } // Emulate built-in functions missing from GLSL 1.30 and higher -void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType, +void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType, int targetGLSLVersion) { + // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10) + if (targetGLSLVersion < GLSL_VERSION_410) + { + const TType *float2 = TCache::getType(EbtFloat, 2); + const TType *uint1 = TCache::getType(EbtUInt); + + // clang-format off + emu->addEmulatedFunction(EOpPackUnorm2x16, float2, + "uint packUnorm2x16_emu(vec2 v)\n" + "{\n" + " int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n" + " int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n" + " return uint((y << 16) | (x & 0xFFFF));\n" + "}\n"); + + emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1, + "vec2 unpackUnorm2x16_emu(uint u)\n" + "{\n" + " float x = float(u & 0xFFFFu) / 65535.0;\n" + " float y = float(u >> 16) / 65535.0;\n" + " return vec2(x, y);\n" + "}\n"); + // clang-format on + } + // 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); + const TType *uint1 = TCache::getType(EbtUInt); // clang-format off emu->addEmulatedFunction(EOpPackSnorm2x16, float2, - "uint webgl_packSnorm2x16_emu(vec2 v)\n" + "uint packSnorm2x16_emu(vec2 v)\n" "{\n" " #if defined(GL_ARB_shading_language_packing)\n" " return packSnorm2x16(v);\n" @@ -63,28 +163,28 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator "}\n"); emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1, "#if !defined(GL_ARB_shading_language_packing)\n" - " float webgl_fromSnorm(uint x)\n" + " float 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" + "vec2 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" + " return vec2(fromSnorm(x), fromSnorm(y));\n" " #endif\n" "}\n"); - // Functions uint webgl_f32tof16(float val) and float webgl_f16tof32(uint val) are + // Functions uint f32tof16(float val) and float 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" + " uint f32tof16(float val)\n" " {\n" " uint f32 = floatBitsToUint(val);\n" " uint f16 = 0u;\n" @@ -119,19 +219,19 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator " }\n" "#endif\n" "\n" - "uint webgl_packHalf2x16_emu(vec2 v)\n" + "uint 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" + " uint x = f32tof16(v.x);\n" + " uint y = 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" + " float f16tof32(uint val)\n" " {\n" " uint sign = (val & 0x8000u) << 16;\n" " int exponent = int((val & 0x7C00u) >> 10);\n" @@ -155,7 +255,9 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator " float scale;\n" " if(exponent < 0)\n" " {\n" - " scale = 1.0 / (1 << -exponent);\n" + " // The negative unary operator is buggy on OSX.\n" + " // Work around this by using abs instead.\n" + " scale = 1.0 / (1 << abs(exponent));\n" " }\n" " else\n" " {\n" @@ -174,16 +276,18 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator " }\n" "#endif\n" "\n" - "vec2 webgl_unpackHalf2x16_emu(uint u)\n" + "vec2 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" + " return vec2(f16tof32(x), f16tof32(y));\n" " #endif\n" "}\n"); // clang-format on } } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h index 56242598af..e1b4779bd5 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h @@ -9,17 +9,32 @@ #include "GLSLANG/ShaderLang.h" +namespace sh +{ class BuiltInFunctionEmulator; // -// This is only a workaround for OpenGL driver bugs, and isn't needed in general. +// This works around bug in Intel Mac drivers. // -void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType); +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType); + +// +// This works around isnan() bug in Intel Mac drivers +// +void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); +// +// This works around atan(y, x) bug in NVIDIA drivers. +// +void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu); // // This function is emulating built-in functions missing from GLSL 1.30 and higher. // -void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType, +void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType, int targetGLSLVersion); +} // namespace sh #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 50e15cbc28..e78d86d00a 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp @@ -8,434 +8,177 @@ #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/VersionGLSL.h" -void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) +namespace sh +{ + +// Defined in emulated_builtin_functions_hlsl_autogen.cpp. +const char *FindHLSLFunction(const FunctionId &functionID); + +void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion) { + if (targetGLSLVersion < GLSL_VERSION_130) + return; + 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" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float2, float2, - "float2 webgl_mod_emu(float2 x, float2 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float2, float1, - "float2 webgl_mod_emu(float2 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float3, float3, - "float3 webgl_mod_emu(float3 x, float3 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float3, float1, - "float3 webgl_mod_emu(float3 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float4, float4, - "float4 webgl_mod_emu(float4 x, float4 y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpMod, float4, float1, - "float4 webgl_mod_emu(float4 x, float y)\n" - "{\n" - " return x - y * floor(x / y);\n" - "}\n" - "\n"); + emu->addEmulatedFunction(EOpIsNan, float1, + "bool isnan_emu(float x)\n" + "{\n" + " return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n" + "}\n" + "\n"); - emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1, - "float webgl_faceforward_emu(float N, float I, float Nref)\n" + emu->addEmulatedFunction( + EOpIsNan, float2, + "bool2 isnan_emu(float2 x)\n" "{\n" - " if(dot(Nref, I) >= 0)\n" + " bool2 isnan;\n" + " for (int i = 0; i < 2; i++)\n" " {\n" - " return -N;\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpFaceForward, float2, float2, float2, - "float2 webgl_faceforward_emu(float2 N, float2 I, float2 Nref)\n" - "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpFaceForward, float3, float3, float3, - "float3 webgl_faceforward_emu(float3 N, float3 I, float3 Nref)\n" + " return isnan;\n" + "}\n"); + + emu->addEmulatedFunction( + EOpIsNan, float3, + "bool3 isnan_emu(float3 x)\n" "{\n" - " if(dot(Nref, I) >= 0)\n" + " bool3 isnan;\n" + " for (int i = 0; i < 3; i++)\n" " {\n" - " return -N;\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" " }\n" - " else\n" - " {\n" - " return N;\n" - " }\n" - "}\n" - "\n"); - emu->addEmulatedFunction(EOpFaceForward, float4, float4, float4, - "float4 webgl_faceforward_emu(float4 N, float4 I, float4 Nref)\n" + " return isnan;\n" + "}\n"); + + emu->addEmulatedFunction( + EOpIsNan, float4, + "bool4 isnan_emu(float4 x)\n" "{\n" - " if(dot(Nref, I) >= 0)\n" - " {\n" - " return -N;\n" - " }\n" - " else\n" + " bool4 isnan;\n" + " for (int i = 0; i < 4; i++)\n" " {\n" - " return N;\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" " }\n" - "}\n" - "\n"); - - emu->addEmulatedFunction(EOpAtan, float1, float1, - "float webgl_atan_emu(float y, float x)\n" - "{\n" - " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN - " return atan2(y, x);\n" - "}\n"); - emu->addEmulatedFunction(EOpAtan, float2, float2, - "float2 webgl_atan_emu(float2 y, float2 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" - "}\n"); - emu->addEmulatedFunction(EOpAtan, float3, float3, - "float3 webgl_atan_emu(float3 y, float3 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" - " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" - "}\n"); - emu->addEmulatedFunction(EOpAtan, float4, float4, - "float4 webgl_atan_emu(float4 y, float4 x)\n" - "{\n" - " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" - " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" - " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" - " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" - " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" - "}\n"); - - emu->addEmulatedFunction(EOpAsinh, float1, - "float webgl_asinh_emu(in float x) {\n" - " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAsinh, float2, - "float2 webgl_asinh_emu(in float2 x) {\n" - " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAsinh, float3, - "float3 webgl_asinh_emu(in float3 x) {\n" - " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAsinh, float4, - "float4 webgl_asinh_emu(in float4 x) {\n" - " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" - "}\n"); - - emu->addEmulatedFunction(EOpAcosh, float1, - "float webgl_acosh_emu(in float x) {\n" - " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAcosh, float2, - "float2 webgl_acosh_emu(in float2 x) {\n" - " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAcosh, float3, - "float3 webgl_acosh_emu(in float3 x) {\n" - " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" - "}\n"); - emu->addEmulatedFunction(EOpAcosh, float4, - "float4 webgl_acosh_emu(in float4 x) {\n" - " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" - "}\n"); - - emu->addEmulatedFunction(EOpAtanh, float1, - "float webgl_atanh_emu(in float x) {\n" - " return 0.5 * log((1.0 + x) / (1.0 - x));\n" - "}\n"); - emu->addEmulatedFunction(EOpAtanh, float2, - "float2 webgl_atanh_emu(in float2 x) {\n" - " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + " return isnan;\n" "}\n"); - emu->addEmulatedFunction(EOpAtanh, float3, - "float3 webgl_atanh_emu(in float3 x) {\n" - " return 0.5 * log((1.0 + x) / (1.0 - x));\n" - "}\n"); - emu->addEmulatedFunction(EOpAtanh, float4, - "float4 webgl_atanh_emu(in float4 x) {\n" - " return 0.5 * log((1.0 + x) / (1.0 - x));\n" - "}\n"); - - emu->addEmulatedFunction(EOpRoundEven, float1, - "float webgl_roundEven_emu(in float x) {\n" - " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n" - "}\n"); - emu->addEmulatedFunction(EOpRoundEven, float2, - "float2 webgl_roundEven_emu(in float2 x) {\n" - " float2 v;\n" - " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" - " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" - " return v;\n" - "}\n"); - emu->addEmulatedFunction(EOpRoundEven, float3, - "float3 webgl_roundEven_emu(in float3 x) {\n" - " float3 v;\n" - " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" - " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" - " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" - " return v;\n" - "}\n"); - emu->addEmulatedFunction(EOpRoundEven, float4, - "float4 webgl_roundEven_emu(in float4 x) {\n" - " float4 v;\n" - " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" - " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" - " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" - " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n" - " return v;\n" - "}\n"); - - emu->addEmulatedFunction(EOpPackSnorm2x16, float2, - "int webgl_toSnorm(in float x) {\n" - " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n" - "}\n" - "\n" - "uint webgl_packSnorm2x16_emu(in float2 v) {\n" - " int x = webgl_toSnorm(v.x);\n" - " int y = webgl_toSnorm(v.y);\n" - " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n" - "}\n"); - emu->addEmulatedFunction(EOpPackUnorm2x16, float2, - "uint webgl_toUnorm(in float x) {\n" - " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n" - "}\n" - "\n" - "uint webgl_packUnorm2x16_emu(in float2 v) {\n" - " uint x = webgl_toUnorm(v.x);\n" - " uint y = webgl_toUnorm(v.y);\n" - " return (y << 16) | x;\n" - "}\n"); - emu->addEmulatedFunction(EOpPackHalf2x16, float2, - "uint webgl_packHalf2x16_emu(in float2 v) {\n" - " uint x = f32tof16(v.x);\n" - " uint y = f32tof16(v.y);\n" - " return (y << 16) | x;\n" - "}\n"); - - TType *uint1 = new TType(EbtUInt); - - emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1, - "float webgl_fromSnorm(in uint x) {\n" - " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n" - " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" - "}\n" - "\n" - "float2 webgl_unpackSnorm2x16_emu(in uint u) {\n" - " uint y = (u >> 16);\n" - " uint x = u;\n" - " return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n" - "}\n"); - emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1, - "float webgl_fromUnorm(in uint x) {\n" - " return float(x) / 65535.0;\n" - "}\n" - "\n" - "float2 webgl_unpackUnorm2x16_emu(in uint u) {\n" - " uint y = (u >> 16);\n" - " uint x = u & 0xffffu;\n" - " return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n" - "}\n"); - emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1, - "float2 webgl_unpackHalf2x16_emu(in uint u) {\n" - " uint y = (u >> 16);\n" - " uint x = u & 0xffffu;\n" - " return float2(f16tof32(x), f16tof32(y));\n" - "}\n"); - - // The matrix resulting from outer product needs to be transposed - // (matrices are stored as transposed to simplify element access in HLSL). - // So the function should return transpose(c * r) where c is a column vector - // and r is a row vector. This can be simplified by using the following - // formula: - // transpose(c * r) = transpose(r) * transpose(c) - // transpose(r) and transpose(c) are in a sense free, since to get the - // transpose of r, we simply can build a column matrix out of the original - // vector instead of a row matrix. - emu->addEmulatedFunction(EOpOuterProduct, float2, float2, - "float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n" - " return mul(float2x1(r), float1x2(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float3, float3, - "float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n" - " return mul(float3x1(r), float1x3(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float4, float4, - "float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n" - " return mul(float4x1(r), float1x4(c));\n" - "}\n"); - - emu->addEmulatedFunction(EOpOuterProduct, float3, float2, - "float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n" - " return mul(float2x1(r), float1x3(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float2, float3, - "float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n" - " return mul(float3x1(r), float1x2(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float4, float2, - "float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n" - " return mul(float2x1(r), float1x4(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float2, float4, - "float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n" - " return mul(float4x1(r), float1x2(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float4, float3, - "float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n" - " return mul(float3x1(r), float1x4(c));\n" - "}\n"); - emu->addEmulatedFunction(EOpOuterProduct, float3, float4, - "float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n" - " return mul(float4x1(r), float1x3(c));\n" - "}\n"); - - TType *mat2 = 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 - // should also be the transpose of the inverse. - - // When accessing the parameter matrix with m[a][b] it can be thought of so - // that a is the column and b is the row of the matrix that we're inverting. - - // We calculate the inverse as the adjugate matrix divided by the - // determinant of the matrix being inverted. However, as the result needs - // to be transposed, we actually use of the transpose of the adjugate matrix - // which happens to be the cofactor matrix. That's stored in "cof". - - // We don't need to care about divide-by-zero since results are undefined - // for singular or poorly-conditioned matrices. - - emu->addEmulatedFunction(EOpInverse, mat2, - "float2x2 webgl_inverse_emu(in float2x2 m) {\n" - " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n" - " return cof / determinant(transpose(m));\n" - "}\n"); - - // cofAB is the cofactor for column A and row B. - - emu->addEmulatedFunction(EOpInverse, mat3, - "float3x3 webgl_inverse_emu(in float3x3 m) {\n" - " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n" - " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n" - " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n" - " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n" - " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n" - " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n" - " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n" - " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n" - " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n" - " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n" - " return cof / determinant(transpose(m));\n" - "}\n"); - - emu->addEmulatedFunction(EOpInverse, mat4, - "float4x4 webgl_inverse_emu(in float4x4 m) {\n" - " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3]" - " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * m[1][3];\n" - " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * m[1][2] * m[2][3]" - " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * m[1][3]);\n" - " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3]" - " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * m[1][3];\n" - " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * m[1][1] * m[2][2]" - " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * m[1][2]);\n" - " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[2][3]" - " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * m[0][3]);\n" - " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[2][3]" - " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * m[0][3];\n" - " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[2][3]" - " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * m[0][3]);\n" - " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[2][2]" - " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * m[0][2];\n" - " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[1][3]" - " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * m[0][3];\n" - " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[1][3]" - " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * m[0][3]);\n" - " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[1][3]" - " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * m[0][3];\n" - " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[1][2]" - " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * m[0][2]);\n" - " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * m[0][2] * m[1][3]" - " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * m[0][3]);\n" - " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * m[0][2] * m[1][3]" - " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * m[0][3];\n" - " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * m[0][1] * m[1][3]" - " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * m[0][3]);\n" - " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2]" - " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * m[0][2];\n" - " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31," - " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n" - " return cof / determinant(transpose(m));\n" - "}\n"); - - 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" +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) +{ + TType *int1 = new TType(EbtInt); + TType *int2 = new TType(EbtInt, 2); + TType *int3 = new TType(EbtInt, 3); + TType *int4 = new TType(EbtInt, 4); + TType *uint1 = new TType(EbtUInt); + TType *uint2 = new TType(EbtUInt, 2); + TType *uint3 = new TType(EbtUInt, 3); + TType *uint4 = new TType(EbtUInt, 4); + + emu->addFunctionMap(FindHLSLFunction); + + // (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32 + // Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because: + // a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000 + FunctionId umulExtendedUint1 = emu->addEmulatedFunction( + EOpUmulExtended, uint1, uint1, uint1, uint1, + "void umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n" + "{\n" + " lsb = x * y;\n" + " uint a = (x & 0xffffu);\n" + " uint b = (x >> 16);\n" + " uint c = (y & 0xffffu);\n" + " uint d = (y >> 16);\n" + " uint ad = a * d + ((a * c) >> 16);\n" + " uint bc = b * c;\n" + " uint carry = uint(ad > (0xffffffffu - bc));\n" + " msb = ((ad + bc) >> 16) + (carry << 16) + b * d;\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + umulExtendedUint1, EOpUmulExtended, uint2, uint2, uint2, uint2, + "void umulExtended_emu(uint2 x, uint2 y, out uint2 msb, out uint2 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + umulExtendedUint1, EOpUmulExtended, uint3, uint3, uint3, uint3, + "void umulExtended_emu(uint3 x, uint3 y, out uint3 msb, out uint3 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + umulExtendedUint1, EOpUmulExtended, uint4, uint4, uint4, uint4, + "void umulExtended_emu(uint4 x, uint4 y, out uint4 msb, out uint4 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + " umulExtended_emu(x.w, y.w, msb.w, lsb.w);\n" + "}\n"); + + // The imul emulation does two's complement negation on the lsb and msb manually in case the + // result needs to be negative. + // TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is + // -2^31. abs(-2^31) is undefined. + FunctionId imulExtendedInt1 = emu->addEmulatedFunctionWithDependency( + umulExtendedUint1, EOpImulExtended, int1, int1, int1, int1, + "void imulExtended_emu(int x, int y, out int msb, out int lsb)\n" + "{\n" + " uint unsignedMsb;\n" + " uint unsignedLsb;\n" + " bool negative = (x < 0) != (y < 0);\n" + " umulExtended_emu(uint(abs(x)), uint(abs(y)), unsignedMsb, unsignedLsb);\n" + " lsb = asint(unsignedLsb);\n" + " msb = asint(unsignedMsb);\n" + " if (negative)\n" + " {\n" + " lsb = ~lsb;\n" + " msb = ~msb;\n" + " if (lsb == 0xffffffff)\n" + " {\n" + " lsb = 0;\n" + " msb += 1;\n" + " }\n" + " else\n" + " {\n" + " lsb += 1;\n" + " }\n" + " }\n" "}\n"); - emu->addEmulatedFunction(EOpMix, float2, float2, bool2, - "float2 webgl_mix_emu(float2 x, float2 y, bool2 a)\n" + emu->addEmulatedFunctionWithDependency( + imulExtendedInt1, EOpImulExtended, int2, int2, int2, int2, + "void imulExtended_emu(int2 x, int2 y, out int2 msb, out int2 lsb)\n" "{\n" - " return a ? y : x;\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" "}\n"); - emu->addEmulatedFunction(EOpMix, float3, float3, bool3, - "float3 webgl_mix_emu(float3 x, float3 y, bool3 a)\n" + emu->addEmulatedFunctionWithDependency( + imulExtendedInt1, EOpImulExtended, int3, int3, int3, int3, + "void imulExtended_emu(int3 x, int3 y, out int3 msb, out int3 lsb)\n" "{\n" - " return a ? y : x;\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" "}\n"); - emu->addEmulatedFunction(EOpMix, float4, float4, bool4, - "float4 webgl_mix_emu(float4 x, float4 y, bool4 a)\n" + emu->addEmulatedFunctionWithDependency( + imulExtendedInt1, EOpImulExtended, int4, int4, int4, int4, + "void imulExtended_emu(int4 x, int4 y, out int4 msb, out int4 lsb)\n" "{\n" - " return a ? y : x;\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + " imulExtended_emu(x.w, y.w, msb.w, lsb.w);\n" "}\n"); - } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h index 4c45a93dc4..48da73f58e 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h @@ -9,8 +9,19 @@ #include "GLSLANG/ShaderLang.h" +namespace sh +{ + class BuiltInFunctionEmulator; void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu); +// +// This works around isnan() bug on some Intel drivers. +// +void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); + +} // namespace sh + #endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Cache.cpp b/src/3rdparty/angle/src/compiler/translator/Cache.cpp index 57a43700ca..417e82403a 100644 --- a/src/3rdparty/angle/src/compiler/translator/Cache.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Cache.cpp @@ -12,21 +12,20 @@ #include "common/debug.h" #include "compiler/translator/Cache.h" +namespace sh +{ + namespace { class TScopedAllocator : angle::NonCopyable { public: - TScopedAllocator(TPoolAllocator *allocator) - : mPreviousAllocator(GetGlobalPoolAllocator()) + TScopedAllocator(TPoolAllocator *allocator) : mPreviousAllocator(GetGlobalPoolAllocator()) { SetGlobalPoolAllocator(allocator); } - ~TScopedAllocator() - { - SetGlobalPoolAllocator(mPreviousAllocator); - } + ~TScopedAllocator() { SetGlobalPoolAllocator(mPreviousAllocator); } private: TPoolAllocator *mPreviousAllocator; @@ -40,28 +39,28 @@ TCache::TypeKey::TypeKey(TBasicType basicType, unsigned char primarySize, unsigned char secondarySize) { - static_assert(sizeof(components) <= sizeof(value), - "TypeKey::value is too small"); + 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 && + 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; + 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; +TCache::TCache() +{ +} + void TCache::initialize() { if (sCache == nullptr) @@ -81,8 +80,7 @@ const TType *TCache::getType(TBasicType basicType, unsigned char primarySize, unsigned char secondarySize) { - TypeKey key(basicType, precision, qualifier, - primarySize, secondarySize); + TypeKey key(basicType, precision, qualifier, primarySize, secondarySize); auto it = sCache->mTypes.find(key); if (it != sCache->mTypes.end()) { @@ -91,10 +89,11 @@ const TType *TCache::getType(TBasicType basicType, TScopedAllocator scopedAllocator(&sCache->mAllocator); - TType *type = new TType(basicType, precision, qualifier, - primarySize, secondarySize); + TType *type = new TType(basicType, precision, qualifier, primarySize, secondarySize); type->realize(); sCache->mTypes.insert(std::make_pair(key, type)); return type; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/Cache.h b/src/3rdparty/angle/src/compiler/translator/Cache.h index 1d2abb77e1..a182b07f51 100644 --- a/src/3rdparty/angle/src/compiler/translator/Cache.h +++ b/src/3rdparty/angle/src/compiler/translator/Cache.h @@ -16,33 +16,31 @@ #include "compiler/translator/Types.h" #include "compiler/translator/PoolAlloc.h" +namespace sh +{ + class TCache { public: - static void initialize(); static void destroy(); - static const TType *getType(TBasicType basicType, - TPrecision precision) + static const TType *getType(TBasicType basicType, TPrecision precision) { - return getType(basicType, precision, EvqTemporary, - 1, 1); + return getType(basicType, precision, EvqTemporary, 1, 1); } static const TType *getType(TBasicType basicType, - unsigned char primarySize = 1, + unsigned char primarySize = 1, unsigned char secondarySize = 1) { - return getType(basicType, EbpUndefined, EvqGlobal, - primarySize, secondarySize); + return getType(basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize); } static const TType *getType(TBasicType basicType, TQualifier qualifier, - unsigned char primarySize = 1, + unsigned char primarySize = 1, unsigned char secondarySize = 1) { - return getType(basicType, EbpUndefined, qualifier, - primarySize, secondarySize); + return getType(basicType, EbpUndefined, qualifier, primarySize, secondarySize); } static const TType *getType(TBasicType basicType, TPrecision precision, @@ -51,12 +49,9 @@ class TCache unsigned char secondarySize); private: - TCache() - { - } + TCache(); - union TypeKey - { + union TypeKey { TypeKey(TBasicType basicType, TPrecision precision, TQualifier qualifier, @@ -74,12 +69,9 @@ class TCache } components; uint64_t value; - bool operator < (const TypeKey &other) const - { - return value < other.value; - } + bool operator<(const TypeKey &other) const { return value < other.value; } }; - typedef std::map TypeMap; + typedef std::map TypeMap; TypeMap mTypes; TPoolAllocator mAllocator; @@ -87,4 +79,6 @@ class TCache static TCache *sCache; }; +} // namespace sh + #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 index 10f0eb937c..5f54e80898 100644 --- a/src/3rdparty/angle/src/compiler/translator/CallDAG.cpp +++ b/src/3rdparty/angle/src/compiler/translator/CallDAG.cpp @@ -9,16 +9,22 @@ // order. #include "compiler/translator/CallDAG.h" -#include "compiler/translator/InfoSink.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ // 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) + CallDAGCreator(TDiagnostics *diagnostics) : TIntermTraverser(true, false, true), - mCreationInfo(info), + mDiagnostics(diagnostics), mCurrentFunction(nullptr), mCurrentIndex(0) { @@ -35,7 +41,6 @@ class CallDAG::CallDAGCreator : public TIntermTraverser InitResult result = assignIndicesInternal(&it.second); if (result != INITDAG_SUCCESS) { - *mCreationInfo << "\n"; return result; } } @@ -44,6 +49,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser skipped++; } } + ASSERT(mFunctions.size() == mCurrentIndex + skipped); return INITDAG_SUCCESS; } @@ -75,147 +81,196 @@ class CallDAG::CallDAGCreator : public TIntermTraverser record.callees.push_back(static_cast(callee->index)); } - (*idToIndex)[data.node->getFunctionId()] = static_cast(data.index); + (*idToIndex)[data.node->getFunctionSymbolInfo()->getId().get()] = + static_cast(data.index); } } private: - struct CreatorFunctionData { - CreatorFunctionData() - : node(nullptr), - index(0), - indexAssigned(false), - visiting(false) - { - } + CreatorFunctionData() : node(nullptr), index(0), indexAssigned(false), visiting(false) {} - std::set callees; - TIntermAggregate *node; + std::set callees; + TIntermFunctionDefinition *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 + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override { - switch (node->getOp()) + // Create the record if need be and remember the node. + if (visit == PreVisit) { - case EOpPrototype: - if (visit == PreVisit) + auto it = mFunctions.find(node->getFunctionSymbolInfo()->getId().get()); + + if (it == mFunctions.end()) { - // Function declaration, create an empty record. - auto& record = mFunctions[node->getName()]; - record.name = node->getName(); + mCurrentFunction = &mFunctions[node->getFunctionSymbolInfo()->getId().get()]; + mCurrentFunction->name = node->getFunctionSymbolInfo()->getName(); } - break; - case EOpFunction: + else { - // Function definition, create the record if need be and remember the node. - if (visit == PreVisit) - { - auto it = mFunctions.find(node->getName()); + mCurrentFunction = &it->second; + ASSERT(mCurrentFunction->name == node->getFunctionSymbolInfo()->getName()); + } - if (it == mFunctions.end()) - { - mCurrentFunction = &mFunctions[node->getName()]; - } - else - { - mCurrentFunction = &it->second; - } + mCurrentFunction->node = node; + } + else if (visit == PostVisit) + { + mCurrentFunction = nullptr; + } + return true; + } - mCurrentFunction->node = node; - mCurrentFunction->name = node->getName(); + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override + { + ASSERT(visit == PreVisit); + if (mCurrentFunction != nullptr) + { + return false; + } - } - else if (visit == PostVisit) - { - mCurrentFunction = nullptr; - } - break; - } - case EOpFunctionCall: + // Function declaration, create an empty record. + auto &record = mFunctions[node->getFunctionSymbolInfo()->getId().get()]; + record.name = node->getFunctionSymbolInfo()->getName(); + + // No need to traverse the parameters. + return false; + } + + // 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 + { + if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST) + { + // Function call, add the callees + auto it = mFunctions.find(node->getFunctionSymbolInfo()->getId().get()); + ASSERT(it != mFunctions.end()); + + // We might be traversing the initializer of a global variable. Even though function + // calls in global scope are forbidden by the parser, some subsequent AST + // transformations can add them to emulate particular features. + if (mCurrentFunction) { - // 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; + mCurrentFunction->callees.insert(&it->second); } - default: - break; } return true; } // Recursively assigns indices to a sub DAG - InitResult assignIndicesInternal(CreatorFunctionData *function) + InitResult assignIndicesInternal(CreatorFunctionData *root) { - ASSERT(function); + // Iterative implementation of the index assignment algorithm. A recursive version + // would be prettier but since the CallDAG creation runs before the limiting of the + // call depth, we might get stack overflows (computation of the call depth uses the + // CallDAG). - if (!function->node) - { - *mCreationInfo << "Undefined function '" << function->name - << ")' used in the following call chain:"; - return INITDAG_UNDEFINED; - } + ASSERT(root); - if (function->indexAssigned) + if (root->indexAssigned) { return INITDAG_SUCCESS; } - if (function->visiting) + // If we didn't have to detect recursion, functionsToProcess could be a simple queue + // in which we add the function being processed's callees. However in order to detect + // recursion we need to know which functions we are currently visiting. For that reason + // functionsToProcess will look like a concatenation of segments of the form + // [F visiting = true, subset of F callees with visiting = false] and the following + // segment (if any) will be start with a callee of F. + // This way we can remember when we started visiting a function, to put visiting back + // to false. + TVector functionsToProcess; + functionsToProcess.push_back(root); + + InitResult result = INITDAG_SUCCESS; + + std::stringstream errorStream; + + while (!functionsToProcess.empty()) { - if (mCreationInfo) + CreatorFunctionData *function = functionsToProcess.back(); + + if (function->visiting) + { + function->visiting = false; + function->index = mCurrentIndex++; + function->indexAssigned = true; + + functionsToProcess.pop_back(); + continue; + } + + if (!function->node) + { + errorStream << "Undefined function '" << function->name + << ")' used in the following call chain:"; + result = INITDAG_UNDEFINED; + break; + } + + if (function->indexAssigned) + { + functionsToProcess.pop_back(); + continue; + } + + function->visiting = true; + + for (auto callee : function->callees) + { + functionsToProcess.push_back(callee); + + // Check if the callee is already being visited after pushing it so that it appears + // in the chain printed in the info log. + if (callee->visiting) + { + errorStream << "Recursive function call in the following call chain:"; + result = INITDAG_RECURSION; + break; + } + } + + if (result != INITDAG_SUCCESS) { - *mCreationInfo << "Recursive function call in the following call chain:" << function->name; + break; } - return INITDAG_RECURSION; } - function->visiting = true; - for (auto &callee : function->callees) + // The call chain is made of the function we were visiting when the error was detected. + if (result != INITDAG_SUCCESS) { - InitResult result = assignIndicesInternal(callee); - if (result != INITDAG_SUCCESS) + bool first = true; + for (auto function : functionsToProcess) { - // 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) + if (function->visiting) { - *mCreationInfo << " <- " << function->name << ")"; + if (!first) + { + errorStream << " -> "; + } + errorStream << function->name << ")"; + first = false; } - return result; + } + if (mDiagnostics) + { + std::string errorStr = errorStream.str(); + mDiagnostics->globalError(errorStr.c_str()); } } - function->index = mCurrentIndex++; - function->indexAssigned = true; - - function->visiting = false; - return INITDAG_SUCCESS; + return result; } - TInfoSinkBase *mCreationInfo; + TDiagnostics *mDiagnostics; - std::map mFunctions; + std::map mFunctions; CreatorFunctionData *mCurrentFunction; size_t mCurrentIndex; }; @@ -232,13 +287,9 @@ CallDAG::~CallDAG() const size_t CallDAG::InvalidIndex = std::numeric_limits::max(); -size_t CallDAG::findIndex(const TIntermAggregate *function) const +size_t CallDAG::findIndex(const TFunctionSymbolInfo *functionInfo) const { - TOperator op = function->getOp(); - ASSERT(op == EOpPrototype || op == EOpFunction || op == EOpFunctionCall); - UNUSED_ASSERTION_VARIABLE(op); - - auto it = mFunctionIdToIndex.find(function->getFunctionId()); + auto it = mFunctionIdToIndex.find(functionInfo->getId().get()); if (it == mFunctionIdToIndex.end()) { @@ -258,7 +309,7 @@ const CallDAG::Record &CallDAG::getRecordFromIndex(size_t index) const const CallDAG::Record &CallDAG::getRecord(const TIntermAggregate *function) const { - size_t index = findIndex(function); + size_t index = findIndex(function->getFunctionSymbolInfo()); ASSERT(index != InvalidIndex && index < mRecords.size()); return mRecords[index]; } @@ -274,9 +325,9 @@ void CallDAG::clear() mFunctionIdToIndex.clear(); } -CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info) +CallDAG::InitResult CallDAG::init(TIntermNode *root, TDiagnostics *diagnostics) { - CallDAGCreator creator(info); + CallDAGCreator creator(diagnostics); // Creates the mapping of functions to callees root->traverse(&creator); @@ -291,3 +342,5 @@ CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info) creator.fillDataStructures(&mRecords, &mFunctionIdToIndex); return INITDAG_SUCCESS; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/CallDAG.h b/src/3rdparty/angle/src/compiler/translator/CallDAG.h index 06c377db00..155081c9a2 100644 --- a/src/3rdparty/angle/src/compiler/translator/CallDAG.h +++ b/src/3rdparty/angle/src/compiler/translator/CallDAG.h @@ -14,8 +14,9 @@ #include #include "compiler/translator/IntermNode.h" -#include "compiler/translator/VariableInfo.h" +namespace sh +{ // The translator needs to analyze the the graph of the function calls // to run checks and analyses; since in GLSL recursion is not allowed @@ -24,7 +25,7 @@ // 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 +// Records are accessed by index but a function symbol id 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. // @@ -41,7 +42,7 @@ class CallDAG : angle::NonCopyable struct Record { std::string name; - TIntermAggregate *node; + TIntermFunctionDefinition *node; std::vector callees; }; @@ -53,11 +54,11 @@ class CallDAG : angle::NonCopyable }; // 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); + // the initialization error in diagnostics, if present. + InitResult init(TIntermNode *root, TDiagnostics *diagnostics); // Returns InvalidIndex if the function wasn't found - size_t findIndex(const TIntermAggregate *function) const; + size_t findIndex(const TFunctionSymbolInfo *functionInfo) const; const Record &getRecordFromIndex(size_t index) const; const Record &getRecord(const TIntermAggregate *function) const; @@ -65,6 +66,7 @@ class CallDAG : angle::NonCopyable void clear(); const static size_t InvalidIndex; + private: std::vector mRecords; std::map mFunctionIdToIndex; @@ -72,4 +74,6 @@ class CallDAG : angle::NonCopyable class CallDAGCreator; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_CALLDAG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ClampPointSize.cpp b/src/3rdparty/angle/src/compiler/translator/ClampPointSize.cpp new file mode 100644 index 0000000000..8598a137f5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ClampPointSize.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ClampPointSize.cpp: Limit the value that is written to gl_PointSize. +// + +#include "compiler/translator/ClampPointSize.h" + +#include "compiler/translator/FindSymbolNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/RunAtTheEndOfShader.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable) +{ + // Only clamp gl_PointSize if it's used in the shader. + if (!FindSymbolNode(root, TString("gl_PointSize"), EbtFloat)) + { + return; + } + + TIntermSymbol *pointSizeNode = ReferenceBuiltInVariable("gl_PointSize", *symbolTable, 100); + + TConstantUnion *maxPointSizeConstant = new TConstantUnion(); + maxPointSizeConstant->setFConst(maxPointSize); + TIntermConstantUnion *maxPointSizeNode = + new TIntermConstantUnion(maxPointSizeConstant, TType(EbtFloat, EbpHigh, EvqConst)); + + // min(gl_PointSize, maxPointSize) + TIntermSequence *minArguments = new TIntermSequence(); + minArguments->push_back(pointSizeNode->deepCopy()); + minArguments->push_back(maxPointSizeNode); + TIntermTyped *clampedPointSize = + CreateBuiltInFunctionCallNode("min", minArguments, *symbolTable, 100); + + // gl_PointSize = min(gl_PointSize, maxPointSize) + TIntermBinary *assignPointSize = new TIntermBinary(EOpAssign, pointSizeNode, clampedPointSize); + + RunAtTheEndOfShader(root, assignPointSize, symbolTable); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ClampPointSize.h b/src/3rdparty/angle/src/compiler/translator/ClampPointSize.h new file mode 100644 index 0000000000..0c71ae6b0d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ClampPointSize.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ClampPointSize.h: Limit the value that is written to gl_PointSize. +// + +#ifndef COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_ +#define COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp index f099bccf15..3e25cc2339 100644 --- a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp +++ b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp @@ -6,71 +6,70 @@ #ifdef ANGLE_ENABLE_ESSL #include "compiler/translator/TranslatorESSL.h" -#endif +#endif // ANGLE_ENABLE_ESSL #ifdef ANGLE_ENABLE_GLSL #include "compiler/translator/TranslatorGLSL.h" -#endif +#endif // ANGLE_ENABLE_GLSL #ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" -#endif // ANGLE_ENABLE_HLSL +#endif // ANGLE_ENABLE_HLSL + +#ifdef ANGLE_ENABLE_VULKAN +#include "compiler/translator/TranslatorVulkan.h" +#endif // ANGLE_ENABLE_VULKAN + +#include "compiler/translator/util.h" + +namespace sh +{ // // This function must be provided to create the actual // compile object used by higher level code. It returns // a subclass of TCompiler. // -TCompiler* ConstructCompiler( - sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) +TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) { - switch (output) { - case SH_ESSL_OUTPUT: #ifdef ANGLE_ENABLE_ESSL + if (IsOutputESSL(output)) + { return new TranslatorESSL(type, spec); -#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: + } +#endif // ANGLE_ENABLE_ESSL + #ifdef ANGLE_ENABLE_GLSL + if (IsOutputGLSL(output)) + { return new TranslatorGLSL(type, spec, 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: + } +#endif // ANGLE_ENABLE_GLSL + #ifdef ANGLE_ENABLE_HLSL + if (IsOutputHLSL(output)) + { return new TranslatorHLSL(type, spec, output); -#else - // This compiler is not supported in this - // configuration. Return NULL per the ShConstructCompiler API. - return nullptr; -#endif // ANGLE_ENABLE_HLSL - default: - // Unknown format. Return NULL per the ShConstructCompiler API. - return nullptr; } +#endif // ANGLE_ENABLE_HLSL + +#ifdef ANGLE_ENABLE_VULKAN + if (IsOutputVulkan(output)) + { + return new TranslatorVulkan(type, spec); + } +#endif // ANGLE_ENABLE_VULKAN + + // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API. + return nullptr; } // // Delete the compiler made by ConstructCompiler // -void DeleteCompiler(TCompiler* compiler) +void DeleteCompiler(TCompiler *compiler) { - delete compiler; + SafeDelete(compiler); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp b/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp new file mode 100644 index 0000000000..bd8cbc971a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp @@ -0,0 +1,869 @@ +// +// 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. +// +// CollectVariables.cpp: Collect lists of shader interface variables based on the AST. + +#include "compiler/translator/CollectVariables.h" + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) +{ + switch (blockStorage) + { + case EbsPacked: + return BLOCKLAYOUT_PACKED; + case EbsShared: + return BLOCKLAYOUT_SHARED; + case EbsStd140: + return BLOCKLAYOUT_STD140; + case EbsStd430: + return BLOCKLAYOUT_STD430; + default: + UNREACHABLE(); + return BLOCKLAYOUT_SHARED; + } +} + +// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks. +BlockType GetBlockType(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqUniform: + return BlockType::BLOCK_UNIFORM; + case EvqBuffer: + return BlockType::BLOCK_BUFFER; + case EvqPerVertexIn: + return BlockType::BLOCK_IN; + default: + UNREACHABLE(); + return BlockType::BLOCK_UNIFORM; + } +} + +template +VarT *FindVariable(const TString &name, std::vector *infoList) +{ + // TODO(zmo): optimize this function. + for (size_t ii = 0; ii < infoList->size(); ++ii) + { + if ((*infoList)[ii].name.c_str() == name) + return &((*infoList)[ii]); + } + + return nullptr; +} + +// Note that this shouldn't be called for interface blocks - static use information is collected for +// individual fields in case of interface blocks. +void MarkStaticallyUsed(ShaderVariable *variable) +{ + if (!variable->staticUse) + { + if (variable->isStruct()) + { + // Conservatively assume all fields are statically used as well. + for (auto &field : variable->fields) + { + MarkStaticallyUsed(&field); + } + } + variable->staticUse = true; + } +} + +ShaderVariable *FindVariableInInterfaceBlock(const TString &name, + const TInterfaceBlock *interfaceBlock, + std::vector *infoList) +{ + ASSERT(interfaceBlock); + InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList); + ASSERT(namedBlock); + + // Set static use on the parent interface block here + namedBlock->staticUse = true; + return FindVariable(name, &namedBlock->fields); +} + +// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs, +// and interface blocks. +class CollectVariablesTraverser : public TIntermTraverser +{ + public: + CollectVariablesTraverser(std::vector *attribs, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *inputVaryings, + std::vector *outputVaryings, + std::vector *uniformBlocks, + std::vector *shaderStorageBlocks, + std::vector *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + int shaderVersion, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior); + + void visitSymbol(TIntermSymbol *symbol) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBinary(Visit visit, TIntermBinary *binaryNode) override; + + private: + std::string getMappedName(const TName &name) const; + + void setCommonVariableProperties(const TType &type, + const TName &name, + ShaderVariable *variableOut) const; + + Attribute recordAttribute(const TIntermSymbol &variable) const; + OutputVariable recordOutputVariable(const TIntermSymbol &variable) const; + Varying recordVarying(const TIntermSymbol &variable) const; + void recordInterfaceBlock(const TType &interfaceBlockType, + InterfaceBlock *interfaceBlock) const; + Uniform recordUniform(const TIntermSymbol &variable) const; + + void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info); + + void recordBuiltInVaryingUsed(const char *name, + bool *addedFlag, + std::vector *varyings); + void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag); + void recordBuiltInAttributeUsed(const char *name, bool *addedFlag); + InterfaceBlock *recordGLInUsed(const TType &glInType); + InterfaceBlock *findNamedInterfaceBlock(const TString &name) const; + + std::vector *mAttribs; + std::vector *mOutputVariables; + std::vector *mUniforms; + std::vector *mInputVaryings; + std::vector *mOutputVaryings; + std::vector *mUniformBlocks; + std::vector *mShaderStorageBlocks; + std::vector *mInBlocks; + + std::map mInterfaceBlockFields; + + // Shader uniforms + bool mDepthRangeAdded; + + // Vertex Shader builtins + bool mInstanceIDAdded; + bool mVertexIDAdded; + bool mPointSizeAdded; + + // Vertex Shader and Geometry Shader builtins + bool mPositionAdded; + + // Fragment Shader builtins + bool mPointCoordAdded; + bool mFrontFacingAdded; + bool mFragCoordAdded; + bool mLastFragDataAdded; + bool mFragColorAdded; + bool mFragDataAdded; + bool mFragDepthEXTAdded; + bool mFragDepthAdded; + bool mSecondaryFragColorEXTAdded; + bool mSecondaryFragDataEXTAdded; + + // Geometry Shader builtins + bool mPerVertexInAdded; + bool mPrimitiveIDInAdded; + bool mInvocationIDAdded; + + // Geometry Shader and Fragment Shader builtins + bool mPrimitiveIDAdded; + bool mLayerAdded; + + ShHashFunction64 mHashFunction; + + int mShaderVersion; + GLenum mShaderType; + const TExtensionBehavior &mExtensionBehavior; +}; + +CollectVariablesTraverser::CollectVariablesTraverser( + std::vector *attribs, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *inputVaryings, + std::vector *outputVaryings, + std::vector *uniformBlocks, + std::vector *shaderStorageBlocks, + std::vector *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + int shaderVersion, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior) + : TIntermTraverser(true, false, false, symbolTable), + mAttribs(attribs), + mOutputVariables(outputVariables), + mUniforms(uniforms), + mInputVaryings(inputVaryings), + mOutputVaryings(outputVaryings), + mUniformBlocks(uniformBlocks), + mShaderStorageBlocks(shaderStorageBlocks), + mInBlocks(inBlocks), + mDepthRangeAdded(false), + mInstanceIDAdded(false), + mVertexIDAdded(false), + mPointSizeAdded(false), + mPositionAdded(false), + mPointCoordAdded(false), + mFrontFacingAdded(false), + mFragCoordAdded(false), + mLastFragDataAdded(false), + mFragColorAdded(false), + mFragDataAdded(false), + mFragDepthEXTAdded(false), + mFragDepthAdded(false), + mSecondaryFragColorEXTAdded(false), + mSecondaryFragDataEXTAdded(false), + mPerVertexInAdded(false), + mPrimitiveIDInAdded(false), + mInvocationIDAdded(false), + mPrimitiveIDAdded(false), + mLayerAdded(false), + mHashFunction(hashFunction), + mShaderVersion(shaderVersion), + mShaderType(shaderType), + mExtensionBehavior(extensionBehavior) +{ +} + +std::string CollectVariablesTraverser::getMappedName(const TName &name) const +{ + return HashName(name, mHashFunction, nullptr).c_str(); +} + +void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name, + ShaderVariable *info) +{ + TVariable *symbolTableVar = + reinterpret_cast(mSymbolTable->findBuiltIn(name, mShaderVersion)); + ASSERT(symbolTableVar); + const TType &type = symbolTableVar->getType(); + + info->name = name; + info->mappedName = name; + info->type = GLVariableType(type); + info->precision = GLVariablePrecision(type); + if (auto *arraySizes = type.getArraySizes()) + { + info->arraySizes.assign(arraySizes->begin(), arraySizes->end()); + } +} + +void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name, + bool *addedFlag, + std::vector *varyings) +{ + ASSERT(varyings); + if (!(*addedFlag)) + { + Varying info; + setBuiltInInfoFromSymbolTable(name, &info); + info.staticUse = true; + info.isInvariant = mSymbolTable->isVaryingInvariant(name); + varyings->push_back(info); + (*addedFlag) = true; + } +} + +void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag) +{ + if (!(*addedFlag)) + { + OutputVariable info; + setBuiltInInfoFromSymbolTable(name, &info); + info.staticUse = true; + mOutputVariables->push_back(info); + (*addedFlag) = true; + } +} + +void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag) +{ + if (!(*addedFlag)) + { + Attribute info; + setBuiltInInfoFromSymbolTable(name, &info); + info.staticUse = true; + info.location = -1; + mAttribs->push_back(info); + (*addedFlag) = true; + } +} + +InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType) +{ + if (!mPerVertexInAdded) + { + ASSERT(glInType.getQualifier() == EvqPerVertexIn); + InterfaceBlock info; + recordInterfaceBlock(glInType, &info); + info.staticUse = true; + + mPerVertexInAdded = true; + mInBlocks->push_back(info); + return &mInBlocks->back(); + } + else + { + return FindVariable("gl_PerVertex", mInBlocks); + } +} + +// We want to check whether a uniform/varying is statically used +// because we only count the used ones in packing computing. +// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count +// toward varying counting if they are statically used in a fragment +// shader. +void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) +{ + ASSERT(symbol != nullptr); + + if (symbol->getName().isInternal()) + { + // Internal variables are not collected. + return; + } + + ShaderVariable *var = nullptr; + const TString &symbolName = symbol->getName().getString(); + + if (IsVaryingIn(symbol->getQualifier())) + { + var = FindVariable(symbolName, mInputVaryings); + } + else if (IsVaryingOut(symbol->getQualifier())) + { + var = FindVariable(symbolName, mOutputVaryings); + } + else if (symbol->getType().getBasicType() == EbtInterfaceBlock) + { + 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_NONE; + info.precision = GL_NONE; + info.staticUse = true; + + ShaderVariable nearInfo(GL_FLOAT); + const char kNearName[] = "near"; + nearInfo.name = kNearName; + nearInfo.mappedName = kNearName; + nearInfo.precision = GL_HIGH_FLOAT; + nearInfo.staticUse = true; + + ShaderVariable farInfo(GL_FLOAT); + const char kFarName[] = "far"; + farInfo.name = kFarName; + farInfo.mappedName = kFarName; + farInfo.precision = GL_HIGH_FLOAT; + farInfo.staticUse = true; + + ShaderVariable diffInfo(GL_FLOAT); + const char kDiffName[] = "diff"; + diffInfo.name = kDiffName; + diffInfo.mappedName = kDiffName; + 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()) + { + case EvqAttribute: + case EvqVertexIn: + var = FindVariable(symbolName, mAttribs); + break; + case EvqFragmentOut: + var = FindVariable(symbolName, mOutputVariables); + break; + case EvqUniform: + { + const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); + if (interfaceBlock) + { + var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks); + } + else + { + var = FindVariable(symbolName, mUniforms); + } + + // It's an internal error to reference an undefined user uniform + ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var); + } + break; + case EvqBuffer: + { + const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); + var = + FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks); + } + break; + case EvqFragCoord: + recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings); + return; + case EvqFrontFacing: + recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings); + return; + case EvqPointCoord: + recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings); + return; + case EvqInstanceID: + // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set, + // gl_InstanceID is added inside expressions to initialize ViewID_OVR and + // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders + // which makes it necessary to populate the type information explicitly instead of + // extracting it from the symbol table. + if (!mInstanceIDAdded) + { + Attribute info; + const char kName[] = "gl_InstanceID"; + info.name = kName; + info.mappedName = kName; + info.type = GL_INT; + info.precision = GL_HIGH_INT; // Defined by spec. + info.staticUse = true; + info.location = -1; + mAttribs->push_back(info); + mInstanceIDAdded = true; + } + return; + case EvqVertexID: + recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded); + return; + case EvqPosition: + recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings); + return; + case EvqPointSize: + recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings); + return; + case EvqLastFragData: + recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings); + return; + case EvqFragColor: + recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded); + return; + case EvqFragData: + if (!mFragDataAdded) + { + OutputVariable info; + setBuiltInInfoFromSymbolTable("gl_FragData", &info); + if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers)) + { + ASSERT(info.arraySizes.size() == 1u); + info.arraySizes.back() = 1u; + } + info.staticUse = true; + mOutputVariables->push_back(info); + mFragDataAdded = true; + } + return; + case EvqFragDepthEXT: + recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded); + return; + case EvqFragDepth: + recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded); + return; + case EvqSecondaryFragColorEXT: + recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT", + &mSecondaryFragColorEXTAdded); + return; + case EvqSecondaryFragDataEXT: + recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT", + &mSecondaryFragDataEXTAdded); + return; + case EvqInvocationID: + recordBuiltInVaryingUsed("gl_InvocationID", &mInvocationIDAdded, mInputVaryings); + break; + case EvqPrimitiveIDIn: + recordBuiltInVaryingUsed("gl_PrimitiveIDIn", &mPrimitiveIDInAdded, mInputVaryings); + break; + case EvqPrimitiveID: + if (mShaderType == GL_GEOMETRY_SHADER_OES) + { + recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mOutputVaryings); + } + else + { + ASSERT(mShaderType == GL_FRAGMENT_SHADER); + recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mInputVaryings); + } + break; + case EvqLayer: + if (mShaderType == GL_GEOMETRY_SHADER_OES) + { + recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mOutputVaryings); + } + else if (mShaderType == GL_FRAGMENT_SHADER) + { + recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mInputVaryings); + } + else + { + ASSERT(mShaderType == GL_VERTEX_SHADER && + IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)); + } + break; + default: + break; + } + } + if (var) + { + MarkStaticallyUsed(var); + } +} + +void CollectVariablesTraverser::setCommonVariableProperties(const TType &type, + const TName &name, + ShaderVariable *variableOut) const +{ + ASSERT(variableOut); + + const TStructure *structure = type.getStruct(); + + if (!structure) + { + variableOut->type = GLVariableType(type); + variableOut->precision = GLVariablePrecision(type); + } + else + { + // Structures use a NONE type that isn't exposed outside ANGLE. + variableOut->type = GL_NONE; + variableOut->structName = structure->name().c_str(); + + const TFieldList &fields = structure->fields(); + + for (TField *field : fields) + { + // Regardless of the variable type (uniform, in/out etc.) its fields are always plain + // ShaderVariable objects. + ShaderVariable fieldVariable; + setCommonVariableProperties(*field->type(), TName(field->name()), &fieldVariable); + variableOut->fields.push_back(fieldVariable); + } + } + variableOut->name = name.getString().c_str(); + variableOut->mappedName = getMappedName(name); + + if (auto *arraySizes = type.getArraySizes()) + { + variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end()); + } +} + +Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + ASSERT(!type.getStruct()); + + Attribute attribute; + setCommonVariableProperties(type, variable.getName(), &attribute); + + attribute.location = type.getLayoutQualifier().location; + return attribute; +} + +OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + ASSERT(!type.getStruct()); + + OutputVariable outputVariable; + setCommonVariableProperties(type, variable.getName(), &outputVariable); + + outputVariable.location = type.getLayoutQualifier().location; + return outputVariable; +} + +Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + + Varying varying; + setCommonVariableProperties(type, variable.getName(), &varying); + varying.location = type.getLayoutQualifier().location; + + switch (type.getQualifier()) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqVertexOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqGeometryOut: + if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) || + type.isInvariant()) + { + varying.isInvariant = true; + } + break; + default: + break; + } + + varying.interpolation = GetInterpolationType(type.getQualifier()); + return varying; +} + +// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks. +void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlockType, + InterfaceBlock *interfaceBlock) const +{ + ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock); + ASSERT(interfaceBlock); + + const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock(); + ASSERT(blockType); + + interfaceBlock->name = blockType->name().c_str(); + interfaceBlock->mappedName = getMappedName(TName(blockType->name())); + interfaceBlock->instanceName = + (blockType->hasInstanceName() ? blockType->instanceName().c_str() : ""); + ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9 + interfaceBlock->arraySize = interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0; + + interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier()); + if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM || + interfaceBlock->blockType == BlockType::BLOCK_BUFFER) + { + interfaceBlock->isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor); + interfaceBlock->binding = blockType->blockBinding(); + interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage()); + } + + // Gather field information + for (const TField *field : blockType->fields()) + { + const TType &fieldType = *field->type(); + + InterfaceBlockField fieldVariable; + setCommonVariableProperties(fieldType, TName(field->name()), &fieldVariable); + fieldVariable.isRowMajorLayout = + (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); + interfaceBlock->fields.push_back(fieldVariable); + } +} + +Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const +{ + Uniform uniform; + setCommonVariableProperties(variable.getType(), variable.getName(), &uniform); + uniform.binding = variable.getType().getLayoutQualifier().binding; + uniform.location = variable.getType().getLayoutQualifier().location; + uniform.offset = variable.getType().getLayoutQualifier().offset; + return uniform; +} + +bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + ASSERT(!sequence.empty()); + + const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); + TQualifier qualifier = typedNode.getQualifier(); + + bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn || + qualifier == EvqFragmentOut || qualifier == EvqUniform || + IsVarying(qualifier); + + if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable) + { + return true; + } + + for (TIntermNode *variableNode : sequence) + { + // The only case in which the sequence will not contain a TIntermSymbol node is + // initialization. It will contain a TInterBinary node in that case. Since attributes, + // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we + // must have only TIntermSymbol nodes in the sequence in the cases we are interested in. + const TIntermSymbol &variable = *variableNode->getAsSymbolNode(); + if (variable.getName().isInternal()) + { + // Internal variables are not collected. + continue; + } + + // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks. + if (typedNode.getBasicType() == EbtInterfaceBlock) + { + InterfaceBlock interfaceBlock; + recordInterfaceBlock(variable.getType(), &interfaceBlock); + + switch (qualifier) + { + case EvqUniform: + mUniformBlocks->push_back(interfaceBlock); + break; + case EvqBuffer: + mShaderStorageBlocks->push_back(interfaceBlock); + break; + default: + UNREACHABLE(); + } + } + else + { + switch (qualifier) + { + case EvqAttribute: + case EvqVertexIn: + mAttribs->push_back(recordAttribute(variable)); + break; + case EvqFragmentOut: + mOutputVariables->push_back(recordOutputVariable(variable)); + break; + case EvqUniform: + mUniforms->push_back(recordUniform(variable)); + break; + default: + if (IsVaryingIn(qualifier)) + { + mInputVaryings->push_back(recordVarying(variable)); + } + else + { + ASSERT(IsVaryingOut(qualifier)); + mOutputVaryings->push_back(recordVarying(variable)); + } + break; + } + } + } + + // None of the recorded variables can have initializers, so we don't need to traverse the + // declarators. + return false; +} + +// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing +// GL_OES_shader_io_blocks. +InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(const TString &blockName) const +{ + InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks); + if (!namedBlock) + { + namedBlock = FindVariable(blockName, mShaderStorageBlocks); + } + return namedBlock; +} + +bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode) +{ + if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) + { + // NOTE: we do not determine static use for individual blocks of an array + TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); + ASSERT(blockNode); + + TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); + ASSERT(constantUnion); + + InterfaceBlock *namedBlock = nullptr; + + bool traverseIndexExpression = false; + TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode(); + if (interfaceIndexingNode) + { + TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped(); + ASSERT(interfaceNode); + + const TType &interfaceType = interfaceNode->getType(); + if (interfaceType.getQualifier() == EvqPerVertexIn) + { + namedBlock = recordGLInUsed(interfaceType); + ASSERT(namedBlock); + + // We need to continue traversing to collect useful variables in the index + // expression of gl_in. + traverseIndexExpression = true; + } + } + + const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock(); + if (!namedBlock) + { + namedBlock = findNamedInterfaceBlock(interfaceBlock->name()); + } + ASSERT(namedBlock); + namedBlock->staticUse = true; + unsigned int fieldIndex = static_cast(constantUnion->getIConst(0)); + ASSERT(fieldIndex < namedBlock->fields.size()); + namedBlock->fields[fieldIndex].staticUse = true; + + if (traverseIndexExpression) + { + ASSERT(interfaceIndexingNode); + interfaceIndexingNode->getRight()->traverse(this); + } + return false; + } + + return true; +} + +} // anonymous namespace + +void CollectVariables(TIntermBlock *root, + std::vector *attributes, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *inputVaryings, + std::vector *outputVaryings, + std::vector *uniformBlocks, + std::vector *shaderStorageBlocks, + std::vector *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + int shaderVersion, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior) +{ + CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings, + outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks, + hashFunction, symbolTable, shaderVersion, shaderType, + extensionBehavior); + root->traverse(&collect); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/CollectVariables.h b/src/3rdparty/angle/src/compiler/translator/CollectVariables.h new file mode 100644 index 0000000000..4d0d1192e0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/CollectVariables.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// CollectVariables.h: Collect lists of shader interface variables based on the AST. + +#ifndef COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ +#define COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ + +#include + +#include "compiler/translator/ExtensionBehavior.h" + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void CollectVariables(TIntermBlock *root, + std::vector *attributes, + std::vector *outputVariables, + std::vector *uniforms, + std::vector *inputVaryings, + std::vector *outputVaryings, + std::vector *uniformBlocks, + std::vector *shaderStorageBlocks, + std::vector *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + int shaderVersion, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior); +} + +#endif // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Common.h b/src/3rdparty/angle/src/compiler/translator/Common.h index 60223232af..cb3a680d85 100644 --- a/src/3rdparty/angle/src/compiler/translator/Common.h +++ b/src/3rdparty/angle/src/compiler/translator/Common.h @@ -10,15 +10,21 @@ #include #include #include +#include #include #include #include #include "common/angleutils.h" #include "common/debug.h" +#include "common/third_party/smhasher/src/PMurHash.h" #include "compiler/translator/PoolAlloc.h" -struct TSourceLoc { +namespace sh +{ + +struct TSourceLoc +{ int first_file; int first_line; int last_file; @@ -29,25 +35,25 @@ struct TSourceLoc { // Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. // #define POOL_ALLOCATOR_NEW_DELETE() \ - void* operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ - void* operator new(size_t, void *_Where) { return (_Where); } \ - void operator delete(void*) { } \ - void operator delete(void *, void *) { } \ - void* operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ - void* operator new[](size_t, void *_Where) { return (_Where); } \ - void operator delete[](void*) { } \ - void operator delete[](void *, void *) { } + void *operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void *operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void *) {} \ + void operator delete(void *, void *) {} \ + void *operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void *operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void *) {} \ + void operator delete[](void *, void *) {} // // Pool version of string. // typedef pool_allocator TStringAllocator; -typedef std::basic_string , TStringAllocator> TString; +typedef std::basic_string, TStringAllocator> TString; typedef std::basic_ostringstream, TStringAllocator> TStringStream; -inline TString* NewPoolTString(const char* s) +inline TString *NewPoolTString(const char *s) { - void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TString)); - return new(memory) TString(s); + void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TString)); + return new (memory) TString(s); } // @@ -64,21 +70,44 @@ template class TVector : public std::vector> { public: + POOL_ALLOCATOR_NEW_DELETE(); + 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 CMP = std::equal_to> +class TUnorderedMap : public std::unordered_map>> +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + typedef pool_allocator> tAllocator; + + TUnorderedMap() : std::unordered_map() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TUnorderedMap(const tAllocator &a) + : std::unordered_map( + std::unordered_map::key_compare(), + a) + { + } +}; + template > class TMap : public std::map>> { public: + POOL_ALLOCATOR_NEW_DELETE(); typedef pool_allocator> tAllocator; TMap() : std::map() {} // use correct two-stage name lookup supported in gcc 3.4 and above - TMap(const tAllocator& a) : std::map(std::map::key_compare(), a) {} + TMap(const tAllocator &a) + : std::map(std::map::key_compare(), a) + { + } }; // Integer to TString conversion @@ -92,4 +121,18 @@ inline TString str(T i) return buffer; } -#endif // COMPILER_TRANSLATOR_COMMON_H_ +} // namespace sh + +namespace std +{ +template <> +struct hash +{ + size_t operator()(const sh::TString &s) const + { + return angle::PMurHash32(0, s.data(), static_cast(s.length())); + } +}; +} // namespace std + +#endif // COMPILER_TRANSLATOR_COMMON_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index 18524ce569..2f411cb58c 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -4,91 +4,193 @@ // found in the LICENSE file. // -#include "compiler/translator/Cache.h" #include "compiler/translator/Compiler.h" + +#include + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/AddAndTrueToLoopCondition.h" +#include "compiler/translator/Cache.h" #include "compiler/translator/CallDAG.h" -#include "compiler/translator/ForLoopUnroll.h" +#include "compiler/translator/ClampPointSize.h" +#include "compiler/translator/CollectVariables.h" +#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h" +#include "compiler/translator/DeferGlobalInitializers.h" +#include "compiler/translator/EmulateGLFragColorBroadcast.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/Initialize.h" -#include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IsASTDepthBelowLimit.h" +#include "compiler/translator/OutputTree.h" #include "compiler/translator/ParseContext.h" -#include "compiler/translator/PruneEmptyDeclarations.h" +#include "compiler/translator/PruneNoOps.h" #include "compiler/translator/RegenerateStructNames.h" +#include "compiler/translator/RemoveArrayLengthMethod.h" +#include "compiler/translator/RemoveEmptySwitchStatements.h" +#include "compiler/translator/RemoveInvariantDeclaration.h" +#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h" #include "compiler/translator/RemovePow.h" -#include "compiler/translator/RenameFunction.h" +#include "compiler/translator/RemoveUnreferencedVariables.h" #include "compiler/translator/RewriteDoWhile.h" #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" +#include "compiler/translator/SeparateDeclarations.h" +#include "compiler/translator/SimplifyLoopConditions.h" +#include "compiler/translator/SplitSequenceOperator.h" #include "compiler/translator/UnfoldShortCircuitAST.h" +#include "compiler/translator/UseInterfaceBlockFields.h" #include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/ValidateMaxParameters.h" #include "compiler/translator/ValidateOutputs.h" +#include "compiler/translator/ValidateVaryingLocations.h" #include "compiler/translator/VariablePacker.h" -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/depgraph/DependencyGraphOutput.h" -#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" -#include "compiler/translator/timing/RestrictVertexShaderTiming.h" +#include "compiler/translator/VectorizeVectorScalarArithmetic.h" +#include "compiler/translator/util.h" #include "third_party/compiler/ArrayBoundsClamper.h" -#include "angle_gl.h" -#include "common/utilities.h" + +namespace sh +{ + +namespace +{ + +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +void DumpFuzzerCase(char const *const *shaderStrings, + size_t numStrings, + uint32_t type, + uint32_t spec, + uint32_t output, + uint64_t options) +{ + static int fileIndex = 0; + + std::ostringstream o; + o << "corpus/" << fileIndex++ << ".sample"; + std::string s = o.str(); + + // Must match the input format of the fuzzer + FILE *f = fopen(s.c_str(), "w"); + fwrite(&type, sizeof(type), 1, f); + fwrite(&spec, sizeof(spec), 1, f); + fwrite(&output, sizeof(output), 1, f); + fwrite(&options, sizeof(options), 1, f); + + char zero[128 - 20] = {0}; + fwrite(&zero, 128 - 20, 1, f); + + for (size_t i = 0; i < numStrings; i++) + { + fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f); + } + fwrite(&zero, 1, 1, f); + + fclose(f); +} +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +} // anonymous namespace bool IsWebGLBasedSpec(ShShaderSpec spec) { - return (spec == SH_WEBGL_SPEC || - spec == SH_CSS_SHADERS_SPEC || - spec == SH_WEBGL2_SPEC); + return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_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); + 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); +} + +bool IsGLSL420OrNewer(ShShaderOutput output) +{ + return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT || + output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT); +} + +bool IsGLSL410OrOlder(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); +} + +bool RemoveInvariant(sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput outputType, + ShCompileOptions compileOptions) +{ + if ((compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) == 0 && + shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType)) + return true; + + if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 && + shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER) + return true; + + return false; } size_t GetGlobalMaxTokenSize(ShShaderSpec spec) { - // WebGL defines a max token legnth of 256, while ES2 leaves max token + // WebGL defines a max token length of 256, while ES2 leaves max token // size undefined. ES3 defines a max size of 1024 characters. switch (spec) { - case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: - return 256; - default: - return 1024; + case SH_WEBGL_SPEC: + return 256; + default: + return 1024; } } -namespace { +int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResources &resources) +{ + switch (shaderType) + { + case GL_VERTEX_SHADER: + return resources.MaxVertexUniformVectors; + case GL_FRAGMENT_SHADER: + return resources.MaxFragmentUniformVectors; + + // TODO (jiawei.shao@intel.com): check if we need finer-grained component counting + case GL_COMPUTE_SHADER: + return resources.MaxComputeUniformComponents / 4; + case GL_GEOMETRY_SHADER_OES: + return resources.MaxGeometryUniformComponents / 4; + default: + UNREACHABLE(); + return -1; + } +} + +namespace +{ class TScopedPoolAllocator { public: - TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) + TScopedPoolAllocator(TPoolAllocator *allocator) : mAllocator(allocator) { mAllocator->push(); SetGlobalPoolAllocator(mAllocator); } ~TScopedPoolAllocator() { - SetGlobalPoolAllocator(NULL); + SetGlobalPoolAllocator(nullptr); mAllocator->pop(); } private: - TPoolAllocator* mAllocator; + TPoolAllocator *mAllocator; }; class TScopedSymbolTableLevel { public: - TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) + TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table) { ASSERT(mTable->atBuiltInLevel()); mTable->push(); @@ -100,23 +202,25 @@ class TScopedSymbolTableLevel } private: - TSymbolTable* mTable; + TSymbolTable *mTable; }; int MapSpecToShaderVersion(ShShaderSpec spec) { switch (spec) { - case SH_GLES2_SPEC: - case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: - return 100; - case SH_GLES3_SPEC: - case SH_WEBGL2_SPEC: - return 300; - default: - UNREACHABLE(); - return 0; + case SH_GLES2_SPEC: + case SH_WEBGL_SPEC: + return 100; + case SH_GLES3_SPEC: + case SH_WEBGL2_SPEC: + return 300; + case SH_GLES3_1_SPEC: + case SH_WEBGL3_SPEC: + return 310; + default: + UNREACHABLE(); + return 0; } } @@ -130,22 +234,31 @@ TShHandleBase::TShHandleBase() TShHandleBase::~TShHandleBase() { - SetGlobalPoolAllocator(NULL); + SetGlobalPoolAllocator(nullptr); allocator.popAll(); } TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) - : shaderType(type), + : variablesCollected(false), + mGLPositionInitialized(false), + shaderType(type), shaderSpec(spec), outputType(output), maxUniformVectors(0), maxExpressionComplexity(0), maxCallStackDepth(0), + maxFunctionParameters(0), fragmentPrecisionHigh(false), clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), builtInFunctionEmulator(), - mSourcePath(NULL), - mTemporaryIndex(0) + mDiagnostics(infoSink.info), + mSourcePath(nullptr), + mComputeShaderLocalSizeDeclared(false), + mComputeShaderLocalSize(1), + mGeometryShaderMaxVertices(-1), + mGeometryShaderInvocations(0), + mGeometryShaderInputPrimitiveType(EptUndefined), + mGeometryShaderOutputPrimitiveType(EptUndefined) { } @@ -153,7 +266,7 @@ TCompiler::~TCompiler() { } -bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const +bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions 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 @@ -162,14 +275,15 @@ bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const (compileOptions & SH_VALIDATE_LOOP_INDEXING); } -bool TCompiler::Init(const ShBuiltInResources& resources) +bool TCompiler::Init(const ShBuiltInResources &resources) { shaderVersion = 100; - maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ? - resources.MaxVertexUniformVectors : - resources.MaxFragmentUniformVectors; + + maxUniformVectors = GetMaxUniformVectorsForShaderType(shaderType, resources); + maxExpressionComplexity = resources.MaxExpressionComplexity; - maxCallStackDepth = resources.MaxCallStackDepth; + maxCallStackDepth = resources.MaxCallStackDepth; + maxFunctionParameters = resources.MaxFunctionParameters; SetGlobalPoolAllocator(&allocator); @@ -187,15 +301,16 @@ bool TCompiler::Init(const ShBuiltInResources& resources) return true; } -TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) { return compileTreeImpl(shaderStrings, numStrings, compileOptions); } -TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], - size_t numStrings, - const int compileOptions) +TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], + size_t numStrings, + const ShCompileOptions compileOptions) { clearResults(); @@ -213,191 +328,347 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], ++firstSource; } - TIntermediate intermediate(infoSink); - TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, - compileOptions, true, infoSink, getResources()); + TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec, + compileOptions, true, &mDiagnostics, getResources()); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); - SetGlobalParseContext(&parseContext); // We preserve symbols at the built-in level from compile-to-compile. // Start pushing the user-defined symbols at global level. TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); // Parse shader. - bool success = - (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) && - (parseContext.getTreeRoot() != nullptr); + if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, + &parseContext) != 0) + { + return nullptr; + } + + if (parseContext.getTreeRoot() == nullptr) + { + return nullptr; + } + + setASTMetadata(parseContext); + + if (MapSpecToShaderVersion(shaderSpec) < shaderVersion) + { + mDiagnostics.globalError("unsupported shader version"); + return nullptr; + } + TIntermBlock *root = parseContext.getTreeRoot(); + if (!checkAndSimplifyAST(root, parseContext, compileOptions)) + { + return nullptr; + } + + return root; +} + +void TCompiler::setASTMetadata(const TParseContext &parseContext) +{ shaderVersion = parseContext.getShaderVersion(); - if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion) + + mPragma = parseContext.pragma(); + symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll); + + mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); + mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); + + mNumViews = parseContext.getNumViews(); + + // Highp might have been auto-enabled based on shader version + fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); + + if (shaderType == GL_GEOMETRY_SHADER_OES) { - infoSink.info.prefix(EPrefixError); - infoSink.info << "unsupported shader version"; - success = false; + mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType(); + mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType(); + mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices(); + mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations(); } +} - TIntermNode *root = nullptr; +bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, + const TParseContext &parseContext, + ShCompileOptions compileOptions) +{ + // Disallow expressions deemed too complex. + if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root)) + { + return false; + } - if (success) + // We prune no-ops to work around driver bugs and to keep AST processing and output simple. + // The following kinds of no-ops are pruned: + // 1. Empty declarations "int;". + // 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision + // for float, so float literal statements would end up with no precision which is + // invalid ESSL. + // After this empty declarations are not allowed in the AST. + PruneNoOps(root); + + // In case the last case inside a switch statement is a certain type of no-op, GLSL + // compilers in drivers may not accept it. In this case we clean up the dead code from the + // end of switch statements. This is also required because PruneNoOps may have left switch + // statements that only contained an empty declaration inside the final case in an invalid + // state. Relies on that PruneNoOps has already been run. + RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable); + + // Remove empty switch statements - this makes output simpler. + RemoveEmptySwitchStatements(root); + + // Create the function DAG and check there is no recursion + if (!initCallDag(root)) { - mPragma = parseContext.pragma(); - if (mPragma.stdgl.invariantAll) - { - symbolTable.setGlobalInvariant(); - } + return false; + } - root = parseContext.getTreeRoot(); - root = intermediate.postProcess(root); + if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth()) + { + return false; + } - // Highp might have been auto-enabled based on shader version - fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); + // Checks which functions are used and if "main" exists + functionMetadata.clear(); + functionMetadata.resize(mCallDag.size()); + if (!tagUsedFunctions()) + { + return false; + } - // Disallow expressions deemed too complex. - if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) - success = limitExpressionComplexity(root); + if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) + { + pruneUnusedFunctions(root); + } - // Create the function DAG and check there is no recursion - if (success) - success = initCallDag(root); + if (shaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, shaderType)) + { + return false; + } - if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH)) - success = checkCallDepth(); + if (shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER && + !ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers, + &mDiagnostics)) + { + return false; + } - // Checks which functions are used and if "main" exists - if (success) - { - functionMetadata.clear(); - functionMetadata.resize(mCallDag.size()); - success = tagUsedFunctions(); - } + if (shouldRunLoopAndIndexingValidation(compileOptions) && + !ValidateLimitations(root, shaderType, &symbolTable, shaderVersion, &mDiagnostics)) + { + return false; + } - if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) - success = pruneUnusedFunctions(root); + // Fail compilation if precision emulation not supported. + if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision && + !EmulatePrecision::SupportedInLanguage(outputType)) + { + mDiagnostics.globalError("Precision emulation not supported for this output type."); + return false; + } - // Prune empty declarations to work around driver bugs and to keep declaration output simple. - if (success) - PruneEmptyDeclarations(root); + // Clamping uniform array bounds needs to happen after validateLimitations pass. + if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS) + { + arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + } - if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER) - success = validateOutputs(root); + if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) && + parseContext.isExtensionEnabled(TExtension::OVR_multiview) && + getShaderType() != GL_COMPUTE_SHADER) + { + DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, shaderType, compileOptions, + outputType, &symbolTable); + } - if (success && shouldRunLoopAndIndexingValidation(compileOptions)) - success = validateLimitations(root); + // This pass might emit short circuits so keep it before the short circuit unfolding + if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS) + RewriteDoWhile(root, &symbolTable); - if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) - success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); + if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) + sh::AddAndTrueToLoopCondition(root); - if (success && shaderSpec == SH_CSS_SHADERS_SPEC) - rewriteCSSShader(root); + if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT) + { + UnfoldShortCircuitAST unfoldShortCircuit; + root->traverse(&unfoldShortCircuit); + unfoldShortCircuit.updateTree(); + } - // Unroll for-loop markup needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) - { - ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex, - shouldRunLoopAndIndexingValidation(compileOptions)); - root->traverse(&marker); - } - if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) - { - ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex, - shouldRunLoopAndIndexingValidation(compileOptions)); - root->traverse(&marker); - if (marker.samplerArrayIndexIsFloatLoopIndex()) - { - infoSink.info.prefix(EPrefixError); - infoSink.info << "sampler array index is float loop index"; - success = false; - } - } + if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT) + { + RemovePow(root); + } - // Built-in function emulation needs to happen after validateLimitations pass. - if (success) - { - initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); - builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); - } + if (compileOptions & SH_REGENERATE_STRUCT_NAMES) + { + RegenerateStructNames gen(&symbolTable, shaderVersion); + root->traverse(&gen); + } - // Clamping uniform array bounds needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) - arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + if (shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 && + compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 && + IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers)) + { + EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables, + &symbolTable, shaderVersion); + } - // 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); + // Split multi declarations and remove calls to array length(). + // Note that SimplifyLoopConditions needs to be run before any other AST transformations + // that may need to generate new statements from loop conditions or loop expressions. + SimplifyLoopConditions( + root, + IntermNodePatternMatcher::kMultiDeclaration | IntermNodePatternMatcher::kArrayLengthMethod, + &getSymbolTable(), getShaderVersion()); - // 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()); + // Note that separate declarations need to be run before other AST transformations that + // generate new statements from expressions. + SeparateDeclarations(root); - if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) - { - UnfoldShortCircuitAST unfoldShortCircuit; - root->traverse(&unfoldShortCircuit); - unfoldShortCircuit.updateTree(); - } + SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable(), + getShaderVersion()); + + RemoveArrayLengthMethod(root); + + RemoveUnreferencedVariables(root, &symbolTable); - if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)) + // Built-in function emulation needs to happen after validateLimitations pass. + // TODO(jmadill): Remove global pool allocator. + GetGlobalPoolAllocator()->lock(); + initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); + GetGlobalPoolAllocator()->unlock(); + builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root); + + if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS) + { + ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, &symbolTable); + } + + if (shouldCollectVariables(compileOptions)) + { + ASSERT(!variablesCollected); + CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings, + &outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks, + hashFunction, &symbolTable, shaderVersion, shaderType, extensionBehavior); + collectInterfaceBlocks(); + variablesCollected = true; + if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) { - RemovePow(root); + useAllMembersInUnusedStandardAndSharedBlocks(root); } - - if (success && shouldCollectVariables(compileOptions)) + if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { - collectVariables(root); - if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) + // Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec + // Appendix A, section 7, the shader does not use too many uniforms. + if (!CheckVariablesInPackingLimits(maxUniformVectors, uniforms)) { - success = enforcePackingRestrictions(); - if (!success) - { - infoSink.info.prefix(EPrefixError); - infoSink.info << "too many uniforms"; - } + mDiagnostics.globalError("too many uniforms"); + return false; } - if (success && shaderType == GL_VERTEX_SHADER && - (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) - initializeVaryingsWithoutStaticUse(root); } - - if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) + if (compileOptions & SH_INIT_OUTPUT_VARIABLES) { - ScalarizeVecAndMatConstructorArgs scalarizer( - shaderType, fragmentPrecisionHigh); - root->traverse(&scalarizer); + initializeOutputVariables(root); } + } + + // Removing invariant declarations must be done after collecting variables. + // Otherwise, built-in invariant declarations don't apply. + if (RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions)) + { + RemoveInvariantDeclaration(root); + } + + // gl_Position is always written in compatibility output mode. + // It may have been already initialized among other output variables, in that case we don't + // need to initialize it twice. + if (shaderType == GL_VERTEX_SHADER && !mGLPositionInitialized && + ((compileOptions & SH_INIT_GL_POSITION) || (outputType == SH_GLSL_COMPATIBILITY_OUTPUT))) + { + initializeGLPosition(root); + mGLPositionInitialized = true; + } + + // DeferGlobalInitializers needs to be run before other AST transformations that generate new + // statements from expressions. But it's fine to run DeferGlobalInitializers after the above + // SplitSequenceOperator and RemoveArrayLengthMethod since they only have an effect on the AST + // on ESSL >= 3.00, and the initializers that need to be deferred can only exist in ESSL < 3.00. + bool initializeLocalsAndGlobals = + (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType()); + bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES); + DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize, &symbolTable); - if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES)) + if (initializeLocalsAndGlobals) + { + // Initialize uninitialized local variables. + // In some cases initializing can generate extra statements in the parent block, such as + // when initializing nameless structs or initializing arrays in ESSL 1.00. In that case + // we need to first simplify loop conditions. We've already separated declarations + // earlier, which is also required. If we don't follow the Appendix A limitations, loop + // init statements can declare arrays or nameless structs and have multiple + // declarations. + + if (!shouldRunLoopAndIndexingValidation(compileOptions)) { - RegenerateStructNames gen(symbolTable, shaderVersion); - root->traverse(&gen); + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kArrayDeclaration | + IntermNodePatternMatcher::kNamelessStructDeclaration, + &getSymbolTable(), getShaderVersion()); } + + InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize, + &getSymbolTable()); } - SetGlobalParseContext(NULL); - if (success) - return root; + if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE)) + { + ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable()); + } - return NULL; + if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC) + { + VectorizeVectorScalarArithmetic(root, &getSymbolTable()); + } + + return true; } -bool TCompiler::compile(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +bool TCompiler::compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptionsIn) { +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn); +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + if (numStrings == 0) return true; + ShCompileOptions compileOptions = compileOptionsIn; + + // Apply key workarounds. + if (shouldFlattenPragmaStdglInvariantAll()) + { + // This should be harmless to do in all cases, but for the moment, do it only conditionally. + compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL; + } + TScopedPoolAllocator scopedAlloc(&allocator); - TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); + TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); if (root) { if (compileOptions & SH_INTERMEDIATE_TREE) - TIntermediate::outputTree(root, infoSink.info); + OutputTree(root, infoSink.info); if (compileOptions & SH_OBJECT_CODE) - translate(root, compileOptions); + { + PerformanceDiagnostics perfDiagnostics(&mDiagnostics); + translate(root, compileOptions, &perfDiagnostics); + } // The IntermNode tree doesn't need to be deleted here, since the // memory will be freed in a big chunk by the PoolAllocator. @@ -408,37 +679,38 @@ bool TCompiler::compile(const char* const shaderStrings[], bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) { + if (resources.MaxDrawBuffers < 1) + { + return false; + } + if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1) + { + return false; + } + compileResources = resources; setResourceString(); - assert(symbolTable.isEmpty()); - symbolTable.push(); // COMMON_BUILTINS - symbolTable.push(); // ESSL1_BUILTINS - symbolTable.push(); // ESSL3_BUILTINS - - TPublicType integer; - integer.type = EbtInt; - integer.primarySize = 1; - integer.secondarySize = 1; - integer.array = false; - - TPublicType floatingPoint; - floatingPoint.type = EbtFloat; - floatingPoint.primarySize = 1; - floatingPoint.secondarySize = 1; - floatingPoint.array = false; - - switch(shaderType) - { - case GL_FRAGMENT_SHADER: - symbolTable.setDefaultPrecision(integer, EbpMedium); - break; - case GL_VERTEX_SHADER: - symbolTable.setDefaultPrecision(integer, EbpHigh); - symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); - break; - default: - assert(false && "Language not supported"); + ASSERT(symbolTable.isEmpty()); + symbolTable.push(); // COMMON_BUILTINS + symbolTable.push(); // ESSL1_BUILTINS + symbolTable.push(); // ESSL3_BUILTINS + symbolTable.push(); // ESSL3_1_BUILTINS + symbolTable.push(); // GLSL_BUILTINS + + switch (shaderType) + { + case GL_FRAGMENT_SHADER: + symbolTable.setDefaultPrecision(EbtInt, EbpMedium); + break; + case GL_VERTEX_SHADER: + case GL_COMPUTE_SHADER: + case GL_GEOMETRY_SHADER_OES: + symbolTable.setDefaultPrecision(EbtInt, EbpHigh); + symbolTable.setDefaultPrecision(EbtFloat, EbpHigh); + break; + default: + UNREACHABLE(); } // Set defaults for sampler types that have default precision, even those that are // only available if an extension exists. @@ -447,9 +719,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) initSamplerDefaultPrecision(EbtSamplerCube); // SamplerExternalOES is specified in the extension to have default precision. initSamplerDefaultPrecision(EbtSamplerExternalOES); + // SamplerExternal2DY2YEXT is specified in the extension to have default precision. + initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT); // It isn't specified whether Sampler2DRect has default precision. initSamplerDefaultPrecision(EbtSampler2DRect); + symbolTable.setDefaultPrecision(EbtAtomicCounter, EbpHigh); + InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable); IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable); @@ -460,87 +736,149 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 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); + symbolTable.setDefaultPrecision(samplerType, EbpLow); } void TCompiler::setResourceString() { std::ostringstream strstream; + + // clang-format off strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs - << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors - << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors - << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits - << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits - << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits - << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors - << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers - << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives - << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external - << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle - << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers - << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh - << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity - << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth - << ":EXT_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 - << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch - << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch - << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors - << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors - << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset - << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset - << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers - << ":NV_draw_buffers:" << compileResources.NV_draw_buffers - << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; + << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors + << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors + << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits + << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits + << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits + << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors + << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers + << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives + << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external + << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3 + << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external + << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle + << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers + << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh + << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity + << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth + << ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters + << ":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 + << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch + << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch + << ":OVR_multiview:" << compileResources.OVR_multiview + << ":EXT_YUV_target:" << compileResources.EXT_YUV_target + << ":OES_geometry_shader:" << compileResources.OES_geometry_shader + << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors + << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors + << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset + << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers + << ":MaxViewsOVR:" << compileResources.MaxViewsOVR + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers + << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision + << ":MinProgramTextureGatherOffset:" << compileResources.MinProgramTextureGatherOffset + << ":MaxProgramTextureGatherOffset:" << compileResources.MaxProgramTextureGatherOffset + << ":MaxImageUnits:" << compileResources.MaxImageUnits + << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms + << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms + << ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms + << ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms + << ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources + << ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0] + << ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1] + << ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2] + << ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0] + << ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1] + << ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2] + << ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents + << ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits + << ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters + << ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers + << ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters + << ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters + << ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters + << ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings + << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers + << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers + << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers + << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize + << ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents + << ":MaxGeometryUniformBlocks:" << compileResources.MaxGeometryUniformBlocks + << ":MaxGeometryInputComponents:" << compileResources.MaxGeometryInputComponents + << ":MaxGeometryOutputComponents:" << compileResources.MaxGeometryOutputComponents + << ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices + << ":MaxGeometryTotalOutputComponents:" << compileResources.MaxGeometryTotalOutputComponents + << ":MaxGeometryTextureImageUnits:" << compileResources.MaxGeometryTextureImageUnits + << ":MaxGeometryAtomicCounterBuffers:" << compileResources.MaxGeometryAtomicCounterBuffers + << ":MaxGeometryAtomicCounters:" << compileResources.MaxGeometryAtomicCounters + << ":MaxGeometryShaderStorageBlocks:" << compileResources.MaxGeometryShaderStorageBlocks + << ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations + << ":MaxGeometryImageUniforms:" << compileResources.MaxGeometryImageUniforms; + // clang-format on builtInResourcesString = strstream.str(); } +void TCompiler::collectInterfaceBlocks() +{ + ASSERT(interfaceBlocks.empty()); + interfaceBlocks.reserve(uniformBlocks.size() + shaderStorageBlocks.size() + inBlocks.size()); + interfaceBlocks.insert(interfaceBlocks.end(), uniformBlocks.begin(), uniformBlocks.end()); + interfaceBlocks.insert(interfaceBlocks.end(), shaderStorageBlocks.begin(), + shaderStorageBlocks.end()); + interfaceBlocks.insert(interfaceBlocks.end(), inBlocks.begin(), inBlocks.end()); +} + void TCompiler::clearResults() { arrayBoundsClamper.Cleanup(); infoSink.info.erase(); infoSink.obj.erase(); infoSink.debug.erase(); + mDiagnostics.resetErrorCount(); attributes.clear(); outputVariables.clear(); uniforms.clear(); - expandedUniforms.clear(); - varyings.clear(); + inputVaryings.clear(); + outputVaryings.clear(); interfaceBlocks.clear(); + uniformBlocks.clear(); + shaderStorageBlocks.clear(); + inBlocks.clear(); + variablesCollected = false; + mGLPositionInitialized = false; + + mNumViews = -1; - builtInFunctionEmulator.Cleanup(); + mGeometryShaderInputPrimitiveType = EptUndefined; + mGeometryShaderOutputPrimitiveType = EptUndefined; + mGeometryShaderInvocations = 0; + mGeometryShaderMaxVertices = -1; + + builtInFunctionEmulator.cleanup(); nameMap.clear(); - mSourcePath = NULL; - mTemporaryIndex = 0; + mSourcePath = nullptr; } bool TCompiler::initCallDag(TIntermNode *root) { mCallDag.clear(); - switch (mCallDag.init(root, &infoSink.info)) + switch (mCallDag.init(root, &mDiagnostics)) { - case CallDAG::INITDAG_SUCCESS: - return true; - case CallDAG::INITDAG_RECURSION: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function recursion detected"; - return false; - case CallDAG::INITDAG_UNDEFINED: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Unimplemented function detected"; - return false; + case CallDAG::INITDAG_SUCCESS: + return true; + case CallDAG::INITDAG_RECURSION: + case CallDAG::INITDAG_UNDEFINED: + // Error message has already been written out. + ASSERT(mDiagnostics.numErrors() > 0); + return false; } UNREACHABLE(); @@ -553,7 +891,7 @@ bool TCompiler::checkCallDepth() for (size_t i = 0; i < mCallDag.size(); i++) { - int depth = 0; + int depth = 0; auto &record = mCallDag.getRecordFromIndex(i); for (auto &calleeIndex : record.callees) @@ -566,19 +904,19 @@ bool TCompiler::checkCallDepth() 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; + std::stringstream errorStream; + errorStream << "Call stack too deep (larger than " << maxCallStackDepth + << ") with the following call chain: " << record.name; int currentFunction = static_cast(i); - int currentDepth = depth; + int currentDepth = depth; while (currentFunction != -1) { - infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name; + errorStream << " -> " << mCallDag.getRecordFromIndex(currentFunction).name; int nextFunction = -1; - for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) + for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) { if (depths[calleeIndex] == currentDepth - 1) { @@ -590,6 +928,9 @@ bool TCompiler::checkCallDepth() currentFunction = nextFunction; } + std::string errorStr = errorStream.str(); + mDiagnostics.globalError(errorStr.c_str()); + return false; } } @@ -602,15 +943,14 @@ 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(") + if (mCallDag.getRecordFromIndex(i).name == "main") { internalTagUsedFunction(i); return true; } } - infoSink.info.prefix(EPrefixError); - infoSink.info << "Missing main()\n"; + mDiagnostics.globalError("Missing main()"); return false; } @@ -634,30 +974,35 @@ class TCompiler::UnusedPredicate { public: UnusedPredicate(const CallDAG *callDag, const std::vector *metadatas) - : mCallDag(callDag), - mMetadatas(metadatas) + : mCallDag(callDag), mMetadatas(metadatas) { } - bool operator ()(TIntermNode *node) + bool operator()(TIntermNode *node) { - const TIntermAggregate *asAggregate = node->getAsAggregate(); + const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode(); + const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition(); + + const TFunctionSymbolInfo *functionInfo = nullptr; - if (asAggregate == nullptr) + if (asFunctionDefinition) { - return false; + functionInfo = asFunctionDefinition->getFunctionSymbolInfo(); } - - if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype)) + else if (asFunctionPrototype) + { + functionInfo = asFunctionPrototype->getFunctionSymbolInfo(); + } + if (functionInfo == nullptr) { return false; } - size_t callDagIndex = mCallDag->findIndex(asAggregate); + size_t callDagIndex = mCallDag->findIndex(functionInfo); if (callDagIndex == CallDAG::InvalidIndex) { // This happens only for unimplemented prototypes which are thus unused - ASSERT(asAggregate->getOp() == EOpPrototype); + ASSERT(asFunctionPrototype); return true; } @@ -670,157 +1015,97 @@ class TCompiler::UnusedPredicate const std::vector *mMetadatas; }; -bool TCompiler::pruneUnusedFunctions(TIntermNode *root) +void TCompiler::pruneUnusedFunctions(TIntermBlock *root) { - TIntermAggregate *rootNode = root->getAsAggregate(); - ASSERT(rootNode != nullptr); - UnusedPredicate isUnused(&mCallDag, &functionMetadata); - TIntermSequence *sequence = rootNode->getSequence(); + TIntermSequence *sequence = root->getSequence(); if (!sequence->empty()) { - sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end()); + sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), + sequence->end()); } - - return true; -} - -bool TCompiler::validateOutputs(TIntermNode* root) -{ - ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers); - root->traverse(&validateOutputs); - return (validateOutputs.validateAndCountErrors(infoSink.info) == 0); -} - -void TCompiler::rewriteCSSShader(TIntermNode* root) -{ - RenameFunction renamer("main(", "css_main("); - root->traverse(&renamer); } -bool TCompiler::validateLimitations(TIntermNode* root) +bool TCompiler::limitExpressionComplexity(TIntermBlock *root) { - ValidateLimitations validate(shaderType, &infoSink.info); - root->traverse(&validate); - return validate.numErrors() == 0; -} - -bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) -{ - if (shaderSpec != SH_WEBGL_SPEC) + if (!IsASTDepthBelowLimit(root, maxExpressionComplexity)) { - infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; + mDiagnostics.globalError("Expression too complex."); return false; } - if (shaderType == GL_FRAGMENT_SHADER) - { - TDependencyGraph graph(root); - - // Output any errors first. - bool success = enforceFragmentShaderTimingRestrictions(graph); - - // Then, output the dependency graph. - if (outputGraph) - { - TDependencyGraphOutput output(infoSink.info); - output.outputAllSpanningTrees(graph); - } - - return success; - } - else - { - return enforceVertexShaderTimingRestrictions(root); - } -} - -bool TCompiler::limitExpressionComplexity(TIntermNode* root) -{ - TMaxDepthTraverser traverser(maxExpressionComplexity+1); - root->traverse(&traverser); - - if (traverser.getMaxDepth() > maxExpressionComplexity) + if (!ValidateMaxParameters(root, maxFunctionParameters)) { - infoSink.info << "Expression too complex."; + mDiagnostics.globalError("Function has too many parameters."); return false; } return true; } -bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) +bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions) { - RestrictFragmentShaderTiming restrictor(infoSink.info); - restrictor.enforceRestrictions(graph); - return restrictor.numErrors() == 0; + return (compileOptions & SH_VARIABLES) != 0; } -bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) +bool TCompiler::wereVariablesCollected() const { - RestrictVertexShaderTiming restrictor(infoSink.info); - restrictor.enforceRestrictions(root); - return restrictor.numErrors() == 0; + return variablesCollected; } -void TCompiler::collectVariables(TIntermNode* root) +void TCompiler::initializeGLPosition(TIntermBlock *root) { - sh::CollectVariables collect(&attributes, - &outputVariables, - &uniforms, - &varyings, - &interfaceBlocks, - hashFunction, - symbolTable); - root->traverse(&collect); - - // This is for enforcePackingRestriction(). - sh::ExpandUniforms(uniforms, &expandedUniforms); + InitVariableList list; + sh::ShaderVariable var(GL_FLOAT_VEC4); + var.name = "gl_Position"; + list.push_back(var); + InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false); } -bool TCompiler::enforcePackingRestrictions() +void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root) { - VariablePacker packer; - return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms); -} + sh::InterfaceBlockList list; -void TCompiler::initializeGLPosition(TIntermNode* root) -{ - InitializeVariables::InitVariableInfoList variables; - InitializeVariables::InitVariableInfo var( - "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); - variables.push_back(var); - InitializeVariables initializer(variables); - root->traverse(&initializer); + for (auto block : uniformBlocks) + { + if (!block.staticUse && + (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED)) + { + list.push_back(block); + } + } + + sh::UseInterfaceBlockFields(root, list, symbolTable); } -void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) +void TCompiler::initializeOutputVariables(TIntermBlock *root) { - InitializeVariables::InitVariableInfoList variables; - for (size_t ii = 0; ii < varyings.size(); ++ii) + InitVariableList list; + if (shaderType == GL_VERTEX_SHADER || shaderType == GL_GEOMETRY_SHADER_OES) { - const sh::Varying& varying = varyings[ii]; - if (varying.staticUse) - continue; - unsigned char primarySize = static_cast(gl::VariableColumnCount(varying.type)); - unsigned char secondarySize = static_cast(gl::VariableRowCount(varying.type)); - TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray()); - TString name = varying.name.c_str(); - if (varying.isArray()) + for (auto var : outputVaryings) { - type.setArraySize(varying.arraySize); - name = name.substr(0, name.find_first_of('[')); + list.push_back(var); + if (var.name == "gl_Position") + { + ASSERT(!mGLPositionInitialized); + mGLPositionInitialized = true; + } } - - InitializeVariables::InitVariableInfo var(name, type); - variables.push_back(var); } - InitializeVariables initializer(variables); - root->traverse(&initializer); + else + { + ASSERT(shaderType == GL_FRAGMENT_SHADER); + for (auto var : outputVariables) + { + list.push_back(var); + } + } + InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false); } -const TExtensionBehavior& TCompiler::getExtensionBehavior() const +const TExtensionBehavior &TCompiler::getExtensionBehavior() const { return extensionBehavior; } @@ -830,12 +1115,12 @@ const char *TCompiler::getSourcePath() const return mSourcePath; } -const ShBuiltInResources& TCompiler::getResources() const +const ShBuiltInResources &TCompiler::getResources() const { return compileResources; } -const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const +const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const { return arrayBoundsClamper; } @@ -845,14 +1130,40 @@ ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const return clampingStrategy; } -const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const +const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const { return builtInFunctionEmulator; } -void TCompiler::writePragma() +void TCompiler::writePragma(ShCompileOptions compileOptions) +{ + if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL)) + { + TInfoSinkBase &sink = infoSink.obj; + if (mPragma.stdgl.invariantAll) + sink << "#pragma STDGL invariant(all)\n"; + } +} + +bool TCompiler::isVaryingDefined(const char *varyingName) { - TInfoSinkBase &sink = infoSink.obj; - if (mPragma.stdgl.invariantAll) - sink << "#pragma STDGL invariant(all)\n"; + ASSERT(variablesCollected); + for (size_t ii = 0; ii < inputVaryings.size(); ++ii) + { + if (inputVaryings[ii].name == varyingName) + { + return true; + } + } + for (size_t ii = 0; ii < outputVaryings.size(); ++ii) + { + if (outputVaryings[ii].name == varyingName) + { + return true; + } + } + + return false; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h index c00a8f97aa..753cfb8e7b 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.h +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h @@ -14,25 +14,29 @@ // This should not be included by driver code. // +#include + #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/CallDAG.h" +#include "compiler/translator/Diagnostics.h" #include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/HashNames.h" #include "compiler/translator/InfoSink.h" #include "compiler/translator/Pragma.h" #include "compiler/translator/SymbolTable.h" -#include "compiler/translator/VariableInfo.h" #include "third_party/compiler/ArrayBoundsClamper.h" +namespace sh +{ + class TCompiler; -class TDependencyGraph; +class TParseContext; #ifdef ANGLE_ENABLE_HLSL class TranslatorHLSL; -#endif // ANGLE_ENABLE_HLSL +#endif // ANGLE_ENABLE_HLSL // -// Helper function to identify specs that are based on the WebGL spec, -// like the CSS Shaders spec. +// Helper function to identify specs that are based on the WebGL spec. // bool IsWebGLBasedSpec(ShShaderSpec spec); @@ -40,20 +44,31 @@ bool IsWebGLBasedSpec(ShShaderSpec spec); // Helper function to check if the shader type is GLSL. // bool IsGLSL130OrNewer(ShShaderOutput output); +bool IsGLSL420OrNewer(ShShaderOutput output); +bool IsGLSL410OrOlder(ShShaderOutput output); + +// +// Helper function to check if the invariant qualifier can be removed. +// +bool RemoveInvariant(sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput outputType, + ShCompileOptions compileOptions); // // The base class used to back handles returned to the driver. // -class TShHandleBase { -public: +class TShHandleBase +{ + public: TShHandleBase(); virtual ~TShHandleBase(); - virtual TCompiler* getAsCompiler() { return 0; } + virtual TCompiler *getAsCompiler() { return 0; } #ifdef ANGLE_ENABLE_HLSL - virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } -#endif // ANGLE_ENABLE_HLSL + virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; } +#endif // ANGLE_ENABLE_HLSL -protected: + protected: // Memory allocator. Allocates and tracks memory required by the compiler. // Deallocates all memory when compiler is destructed. TPoolAllocator allocator; @@ -70,20 +85,26 @@ class TCompiler : public TShHandleBase ~TCompiler() override; TCompiler *getAsCompiler() override { return this; } - bool Init(const ShBuiltInResources& resources); + bool Init(const ShBuiltInResources &resources); // compileTreeForTesting should be used only when tests require access to // the AST. Users of this function need to manually manage the global pool - // allocator. Returns NULL whenever there are compilation errors. - TIntermNode *compileTreeForTesting(const char* const shaderStrings[], - size_t numStrings, int compileOptions); + // allocator. Returns nullptr whenever there are compilation errors. + TIntermBlock *compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); - bool compile(const char* const shaderStrings[], - size_t numStrings, int compileOptions); + bool compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); // Get results of the last compilation. int getShaderVersion() const { return shaderVersion; } - TInfoSink& getInfoSink() { return infoSink; } + TInfoSink &getInfoSink() { return infoSink; } + + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } + int getNumViews() const { return mNumViews; } // Clears the results from the previous compilation. void clearResults(); @@ -91,86 +112,94 @@ class TCompiler : public TShHandleBase const std::vector &getAttributes() const { return attributes; } const std::vector &getOutputVariables() const { return outputVariables; } const std::vector &getUniforms() const { return uniforms; } - const std::vector &getVaryings() const { return varyings; } + const std::vector &getInputVaryings() const { return inputVaryings; } + const std::vector &getOutputVaryings() const { return outputVaryings; } const std::vector &getInterfaceBlocks() const { return interfaceBlocks; } + const std::vector &getUniformBlocks() const { return uniformBlocks; } + const std::vector &getShaderStorageBlocks() const + { + return shaderStorageBlocks; + } + const std::vector &getInBlocks() const { return inBlocks; } ShHashFunction64 getHashFunction() const { return hashFunction; } - NameMap& getNameMap() { return nameMap; } - TSymbolTable& getSymbolTable() { return symbolTable; } + NameMap &getNameMap() { return nameMap; } + TSymbolTable &getSymbolTable() { return symbolTable; } ShShaderSpec getShaderSpec() const { return shaderSpec; } ShShaderOutput getOutputType() const { return outputType; } const std::string &getBuiltInResourcesString() const { return builtInResourcesString; } - bool shouldRunLoopAndIndexingValidation(int compileOptions) const; + bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const; // Get the resources set by InitBuiltInSymbolTable - const ShBuiltInResources& getResources() const; + const ShBuiltInResources &getResources() const; + + int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; } + int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; } + TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const + { + return mGeometryShaderInputPrimitiveType; + } + TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const + { + return mGeometryShaderOutputPrimitiveType; + } - protected: sh::GLenum getShaderType() const { return shaderType; } + + protected: // Initialize symbol-table with built-in symbols. - bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); + bool InitBuiltInSymbolTable(const ShBuiltInResources &resources); // Compute the string representation of the built-in resources void setResourceString(); // 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. - void rewriteCSSShader(TIntermNode* root); - // Returns true if the given shader does not exceed the minimum - // functionality mandated in GLSL 1.0 spec Appendix A. - bool validateLimitations(TIntermNode* root); - // Collect info for all attribs, uniforms, varyings. - void collectVariables(TIntermNode* root); // Add emulated functions to the built-in function emulator. - virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {}; - // Translate to object code. - virtual void translate(TIntermNode *root, int compileOptions) = 0; - // Returns true if, after applying the packing rules in the GLSL 1.017 spec - // Appendix A, section 7, the shader does not use too many uniforms. - bool enforcePackingRestrictions(); - // Insert statements to initialize varyings without static use in the beginning - // of main(). It is to work around a Mac driver where such varyings in a vertex - // shader may be optimized out incorrectly at compile time, causing a link failure. - // This function should only be applied to vertex shaders. - void initializeVaryingsWithoutStaticUse(TIntermNode* root); + virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions){}; + // Translate to object code. May generate performance warnings through the diagnostics. + virtual void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) = 0; + // Insert statements to reference all members in unused uniform blocks with standard and shared + // layout. This is to work around a Mac driver that treats unused standard/shared + // uniform blocks as inactive. + void useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root); + // Insert statements to initialize output variables in the beginning of main(). + // This is to avoid undefined behaviors. + void initializeOutputVariables(TIntermBlock *root); // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). // It is to work around a Linux driver bug where missing this causes compile failure // while spec says it is allowed. // This function should only be applied to vertex shaders. - void initializeGLPosition(TIntermNode* root); - // Returns true if the shader passes the restrictions that aim to prevent timing attacks. - bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); - // Returns true if the shader does not use samplers. - bool enforceVertexShaderTimingRestrictions(TIntermNode* root); - // Returns true if the shader does not use sampler dependent values to affect control - // flow or in operations whose time can depend on the input values. - bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); + void initializeGLPosition(TIntermBlock *root); // Return true if the maximum expression complexity is below the limit. - bool limitExpressionComplexity(TIntermNode* root); + bool limitExpressionComplexity(TIntermBlock *root); // Get built-in extensions with default behavior. - const TExtensionBehavior& getExtensionBehavior() const; + const TExtensionBehavior &getExtensionBehavior() const; const char *getSourcePath() const; - const TPragma& getPragma() const { return mPragma; } - void writePragma(); - unsigned int *getTemporaryIndex() { return &mTemporaryIndex; } + const TPragma &getPragma() const { return mPragma; } + void writePragma(ShCompileOptions compileOptions); + // Relies on collectVariables having been called. + bool isVaryingDefined(const char *varyingName); - const ArrayBoundsClamper& getArrayBoundsClamper() const; + const ArrayBoundsClamper &getArrayBoundsClamper() const; ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; - const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; + const BuiltInFunctionEmulator &getBuiltInFunctionEmulator() const; + virtual bool shouldFlattenPragmaStdglInvariantAll() = 0; + virtual bool shouldCollectVariables(ShCompileOptions compileOptions); + + bool wereVariablesCollected() const; std::vector attributes; std::vector outputVariables; std::vector uniforms; - std::vector expandedUniforms; - std::vector varyings; + std::vector inputVaryings; + std::vector outputVaryings; std::vector interfaceBlocks; - - virtual bool shouldCollectVariables(int compileOptions) - { - return (compileOptions & SH_VARIABLES) != 0; - } + std::vector uniformBlocks; + std::vector shaderStorageBlocks; + std::vector inBlocks; private: // Creates the function call DAG for further analysis, returning false if there is a recursion @@ -181,13 +210,28 @@ class TCompiler : public TShHandleBase void initSamplerDefaultPrecision(TBasicType samplerType); + void collectInterfaceBlocks(); + + bool variablesCollected; + + bool mGLPositionInitialized; + // Removes unused function declarations and prototypes from the AST class UnusedPredicate; - bool pruneUnusedFunctions(TIntermNode *root); + void pruneUnusedFunctions(TIntermBlock *root); + + TIntermBlock *compileTreeImpl(const char *const shaderStrings[], + size_t numStrings, + const ShCompileOptions compileOptions); - TIntermNode *compileTreeImpl(const char *const shaderStrings[], - size_t numStrings, - const int compileOptions); + // Fetches and stores shader metadata that is not stored within the AST itself, such as shader + // version. + void setASTMetadata(const TParseContext &parseContext); + + // Does checks that need to be run after parsing is complete and returns true if they pass. + bool checkAndSimplifyAST(TIntermBlock *root, + const TParseContext &parseContext, + ShCompileOptions compileOptions); sh::GLenum shaderType; ShShaderSpec shaderSpec; @@ -195,10 +239,7 @@ class TCompiler : public TShHandleBase struct FunctionMetadata { - FunctionMetadata() - : used(false) - { - } + FunctionMetadata() : used(false) {} bool used; }; @@ -208,6 +249,7 @@ class TCompiler : public TShHandleBase int maxUniformVectors; int maxExpressionComplexity; int maxCallStackDepth; + int maxFunctionParameters; ShBuiltInResources compileResources; std::string builtInResourcesString; @@ -225,16 +267,28 @@ class TCompiler : public TShHandleBase // Results of compilation. int shaderVersion; - TInfoSink infoSink; // Output sink. - const char *mSourcePath; // Path of source file or NULL + TInfoSink infoSink; // Output sink. + TDiagnostics mDiagnostics; + const char *mSourcePath; // Path of source file or NULL + + // compute shader local group size + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + + // GL_OVR_multiview num_views. + int mNumViews; + + // geometry shader parameters. + int mGeometryShaderMaxVertices; + int mGeometryShaderInvocations; + TLayoutPrimitiveType mGeometryShaderInputPrimitiveType; + TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType; // name hashing. ShHashFunction64 hashFunction; NameMap nameMap; TPragma mPragma; - - unsigned int mTemporaryIndex; }; // @@ -246,8 +300,9 @@ class TCompiler : public TShHandleBase // destroy the machine dependent objects, which contain the // above machine independent information. // -TCompiler* ConstructCompiler( - sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); -void DeleteCompiler(TCompiler*); +TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); +void DeleteCompiler(TCompiler *); + +} // namespace sh -#endif // COMPILER_TRANSLATOR_COMPILER_H_ +#endif // COMPILER_TRANSLATOR_COMPILER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.cpp b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.cpp new file mode 100644 index 0000000000..7004aedee3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.cpp @@ -0,0 +1,681 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ConstantUnion: Constant folding helper class. + +#include "compiler/translator/ConstantUnion.h" + +#include "common/mathutil.h" +#include "compiler/translator/Diagnostics.h" + +namespace sh +{ + +namespace +{ + +float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs + rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined addition generated NaN", "+"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded addition overflowed to infinity", "+"); + } + return result; +} + +float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs - rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined subtraction generated NaN", "-"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded subtraction overflowed to infinity", "-"); + } + return result; +} + +float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs * rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined multiplication generated NaN", "*"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded multiplication overflowed to infinity", "*"); + } + return result; +} + +bool IsValidShiftOffset(const TConstantUnion &rhs) +{ + return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) || + (rhs.getType() == EbtUInt && rhs.getUConst() <= 31u); +} + +} // anonymous namespace + +TConstantUnion::TConstantUnion() +{ + iConst = 0; + type = EbtVoid; +} + +int TConstantUnion::getIConst() const +{ + ASSERT(type == EbtInt); + return iConst; +} + +unsigned int TConstantUnion::getUConst() const +{ + ASSERT(type == EbtUInt); + return uConst; +} + +float TConstantUnion::getFConst() const +{ + ASSERT(type == EbtFloat); + return fConst; +} + +bool TConstantUnion::getBConst() const +{ + ASSERT(type == EbtBool); + return bConst; +} + +TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const +{ + ASSERT(type == EbtYuvCscStandardEXT); + return yuvCscStandardEXTConst; +} + +bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant) +{ + switch (newType) + { + case EbtFloat: + switch (constant.type) + { + case EbtInt: + setFConst(static_cast(constant.getIConst())); + break; + case EbtUInt: + setFConst(static_cast(constant.getUConst())); + break; + case EbtBool: + setFConst(static_cast(constant.getBConst())); + break; + case EbtFloat: + setFConst(static_cast(constant.getFConst())); + break; + default: + return false; + } + break; + case EbtInt: + switch (constant.type) + { + case EbtInt: + setIConst(static_cast(constant.getIConst())); + break; + case EbtUInt: + setIConst(static_cast(constant.getUConst())); + break; + case EbtBool: + setIConst(static_cast(constant.getBConst())); + break; + case EbtFloat: + setIConst(static_cast(constant.getFConst())); + break; + default: + return false; + } + break; + case EbtUInt: + switch (constant.type) + { + case EbtInt: + setUConst(static_cast(constant.getIConst())); + break; + case EbtUInt: + setUConst(static_cast(constant.getUConst())); + break; + case EbtBool: + setUConst(static_cast(constant.getBConst())); + break; + case EbtFloat: + setUConst(static_cast(constant.getFConst())); + break; + default: + return false; + } + break; + case EbtBool: + switch (constant.type) + { + case EbtInt: + setBConst(constant.getIConst() != 0); + break; + case EbtUInt: + setBConst(constant.getUConst() != 0); + break; + case EbtBool: + setBConst(constant.getBConst()); + break; + case EbtFloat: + setBConst(constant.getFConst() != 0.0f); + break; + default: + return false; + } + break; + case EbtStruct: // Struct fields don't get cast + switch (constant.type) + { + case EbtInt: + setIConst(constant.getIConst()); + break; + case EbtUInt: + setUConst(constant.getUConst()); + break; + case EbtBool: + setBConst(constant.getBConst()); + break; + case EbtFloat: + setFConst(constant.getFConst()); + break; + default: + return false; + } + break; + default: + return false; + } + + return true; +} + +bool TConstantUnion::operator==(const int i) const +{ + return i == iConst; +} + +bool TConstantUnion::operator==(const unsigned int u) const +{ + return u == uConst; +} + +bool TConstantUnion::operator==(const float f) const +{ + return f == fConst; +} + +bool TConstantUnion::operator==(const bool b) const +{ + return b == bConst; +} + +bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const +{ + return s == yuvCscStandardEXTConst; +} + +bool TConstantUnion::operator==(const TConstantUnion &constant) const +{ + if (constant.type != type) + return false; + + switch (type) + { + case EbtInt: + return constant.iConst == iConst; + case EbtUInt: + return constant.uConst == uConst; + case EbtFloat: + return constant.fConst == fConst; + case EbtBool: + return constant.bConst == bConst; + case EbtYuvCscStandardEXT: + return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst; + default: + return false; + } +} + +bool TConstantUnion::operator!=(const int i) const +{ + return !operator==(i); +} + +bool TConstantUnion::operator!=(const unsigned int u) const +{ + return !operator==(u); +} + +bool TConstantUnion::operator!=(const float f) const +{ + return !operator==(f); +} + +bool TConstantUnion::operator!=(const bool b) const +{ + return !operator==(b); +} + +bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const +{ + return !operator==(s); +} + +bool TConstantUnion::operator!=(const TConstantUnion &constant) const +{ + return !operator==(constant); +} + +bool TConstantUnion::operator>(const TConstantUnion &constant) const +{ + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + return iConst > constant.iConst; + case EbtUInt: + return uConst > constant.uConst; + case EbtFloat: + return fConst > constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } +} + +bool TConstantUnion::operator<(const TConstantUnion &constant) const +{ + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + return iConst < constant.iConst; + case EbtUInt: + return uConst < constant.uConst; + case EbtFloat: + return fConst < constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } +} + +// static +TConstantUnion TConstantUnion::add(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == rhs.type); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingSum(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + returnValue.setUConst(gl::WrappingSum(lhs.uConst, rhs.uConst)); + break; + case EbtFloat: + returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == rhs.type); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingDiff(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + returnValue.setUConst(gl::WrappingDiff(lhs.uConst, rhs.uConst)); + break; + case EbtFloat: + returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == rhs.type); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that + // to implement wrapping multiplication. + returnValue.setUConst(lhs.uConst * rhs.uConst); + break; + case EbtFloat: + returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst % constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst % constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); + ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); + if (!IsValidShiftOffset(rhs)) + { + diag->warning(line, "Undefined shift (operand out of range)", ">>"); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(0); + break; + case EbtUInt: + returnValue.setUConst(0u); + break; + default: + UNREACHABLE(); + } + return returnValue; + } + + switch (lhs.type) + { + case EbtInt: + { + unsigned int shiftOffset = 0; + switch (rhs.type) + { + case EbtInt: + shiftOffset = static_cast(rhs.iConst); + break; + case EbtUInt: + shiftOffset = rhs.uConst; + break; + default: + UNREACHABLE(); + } + if (shiftOffset > 0) + { + // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend + // the sign bit." In C++ shifting negative integers is undefined, so we implement + // extending the sign bit manually. + int lhsSafe = lhs.iConst; + if (lhsSafe == std::numeric_limits::min()) + { + // The min integer needs special treatment because only bit it has set is the + // sign bit, which we clear later to implement safe right shift of negative + // numbers. + lhsSafe = -0x40000000; + --shiftOffset; + } + if (shiftOffset > 0) + { + bool extendSignBit = false; + if (lhsSafe < 0) + { + extendSignBit = true; + // Clear the sign bit so that bitshift right is defined in C++. + lhsSafe &= 0x7fffffff; + ASSERT(lhsSafe > 0); + } + returnValue.setIConst(lhsSafe >> shiftOffset); + + // Manually fill in the extended sign bit if necessary. + if (extendSignBit) + { + int extendedSignBit = static_cast(0xffffffffu << (31 - shiftOffset)); + returnValue.setIConst(returnValue.getIConst() | extendedSignBit); + } + } + else + { + returnValue.setIConst(lhsSafe); + } + } + else + { + returnValue.setIConst(lhs.iConst); + } + break; + } + case EbtUInt: + switch (rhs.type) + { + case EbtInt: + returnValue.setUConst(lhs.uConst >> rhs.iConst); + break; + case EbtUInt: + returnValue.setUConst(lhs.uConst >> rhs.uConst); + break; + default: + UNREACHABLE(); + } + break; + + default: + UNREACHABLE(); + } + return returnValue; +} + +// static +TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); + ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); + if (!IsValidShiftOffset(rhs)) + { + diag->warning(line, "Undefined shift (operand out of range)", "<<"); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(0); + break; + case EbtUInt: + returnValue.setUConst(0u); + break; + default: + UNREACHABLE(); + } + return returnValue; + } + + switch (lhs.type) + { + case EbtInt: + switch (rhs.type) + { + // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that + // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed + // integer overflow or undefined shift of a negative integer. + case EbtInt: + returnValue.setIConst( + static_cast(static_cast(lhs.iConst) << rhs.iConst)); + break; + case EbtUInt: + returnValue.setIConst( + static_cast(static_cast(lhs.iConst) << rhs.uConst)); + break; + default: + UNREACHABLE(); + } + break; + + case EbtUInt: + switch (rhs.type) + { + case EbtInt: + returnValue.setUConst(lhs.uConst << rhs.iConst); + break; + case EbtUInt: + returnValue.setUConst(lhs.uConst << rhs.uConst); + break; + default: + UNREACHABLE(); + } + break; + + default: + UNREACHABLE(); + } + return returnValue; +} + +TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(constant.type == EbtInt || constant.type == EbtUInt); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst & constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst & constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst | constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst | constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst ^ constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst ^ constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtBool: + returnValue.setBConst(bConst && constant.bConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtBool: + returnValue.setBConst(bConst || constant.bConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h index a86d27f3ff..c1b3db9070 100644 --- a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h +++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h @@ -9,340 +9,109 @@ #include +#include "compiler/translator/Common.h" #include "compiler/translator/BaseTypes.h" -class TConstantUnion { -public: - POOL_ALLOCATOR_NEW_DELETE(); - TConstantUnion() - { - iConst = 0; - type = EbtVoid; - } - - bool cast(TBasicType newType, const TConstantUnion &constant) - { - switch (newType) - { - case EbtFloat: - switch (constant.type) - { - case EbtInt: setFConst(static_cast(constant.getIConst())); break; - case EbtUInt: setFConst(static_cast(constant.getUConst())); break; - case EbtBool: setFConst(static_cast(constant.getBConst())); break; - case EbtFloat: setFConst(static_cast(constant.getFConst())); break; - default: return false; - } - break; - case EbtInt: - switch (constant.type) - { - case EbtInt: setIConst(static_cast(constant.getIConst())); break; - case EbtUInt: setIConst(static_cast(constant.getUConst())); break; - case EbtBool: setIConst(static_cast(constant.getBConst())); break; - case EbtFloat: setIConst(static_cast(constant.getFConst())); break; - default: return false; - } - break; - case EbtUInt: - switch (constant.type) - { - case EbtInt: setUConst(static_cast(constant.getIConst())); break; - case EbtUInt: setUConst(static_cast(constant.getUConst())); break; - case EbtBool: setUConst(static_cast(constant.getBConst())); break; - case EbtFloat: setUConst(static_cast(constant.getFConst())); break; - default: return false; - } - break; - case EbtBool: - switch (constant.type) - { - case EbtInt: setBConst(constant.getIConst() != 0); break; - case EbtUInt: setBConst(constant.getUConst() != 0); break; - case EbtBool: setBConst(constant.getBConst()); break; - case EbtFloat: setBConst(constant.getFConst() != 0.0f); break; - default: return false; - } - break; - case EbtStruct: // Struct fields don't get cast - switch (constant.type) - { - case EbtInt: setIConst(constant.getIConst()); break; - case EbtUInt: setUConst(constant.getUConst()); break; - case EbtBool: setBConst(constant.getBConst()); break; - case EbtFloat: setFConst(constant.getFConst()); break; - default: return false; - } - break; - default: - return false; - } - - return true; - } - - void setIConst(int i) {iConst = i; type = EbtInt; } - void setUConst(unsigned int u) { uConst = u; type = EbtUInt; } - void setFConst(float f) {fConst = f; type = EbtFloat; } - void setBConst(bool b) {bConst = b; type = EbtBool; } - - int getIConst() const { return iConst; } - unsigned int getUConst() const { return uConst; } - float getFConst() const { return fConst; } - bool getBConst() const { return bConst; } +namespace sh +{ - bool operator==(const int i) const - { - return i == iConst; - } - - bool operator==(const unsigned int u) const - { - return u == uConst; - } - - bool operator==(const float f) const - { - return f == fConst; - } +class TDiagnostics; - bool operator==(const bool b) const - { - return b == bConst; - } - - bool operator==(const TConstantUnion& constant) const - { - if (constant.type != type) - return false; +class TConstantUnion +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TConstantUnion(); - switch (type) { - case EbtInt: - return constant.iConst == iConst; - case EbtUInt: - return constant.uConst == uConst; - case EbtFloat: - return constant.fConst == fConst; - case EbtBool: - return constant.bConst == bConst; - default: - return false; - } - } + bool cast(TBasicType newType, const TConstantUnion &constant); - bool operator!=(const int i) const + void setIConst(int i) { - return !operator==(i); + iConst = i; + type = EbtInt; } - - bool operator!=(const unsigned int u) const + void setUConst(unsigned int u) { - return !operator==(u); + uConst = u; + type = EbtUInt; } - - bool operator!=(const float f) const + void setFConst(float f) { - return !operator==(f); + fConst = f; + type = EbtFloat; } - - bool operator!=(const bool b) const + void setBConst(bool b) { - return !operator==(b); + bConst = b; + type = EbtBool; } - bool operator!=(const TConstantUnion& constant) const + void setYuvCscStandardEXTConst(TYuvCscStandardEXT s) { - return !operator==(constant); - } - - bool operator>(const TConstantUnion& constant) const - { - assert(type == constant.type); - switch (type) { - case EbtInt: - return iConst > constant.iConst; - case EbtUInt: - return uConst > constant.uConst; - case EbtFloat: - return fConst > constant.fConst; - default: - return false; // Invalid operation, handled at semantic analysis - } - } - - bool operator<(const TConstantUnion& constant) const - { - assert(type == constant.type); - switch (type) { - case EbtInt: - return iConst < constant.iConst; - case EbtUInt: - return uConst < constant.uConst; - case EbtFloat: - return fConst < constant.fConst; - default: - return false; // Invalid operation, handled at semantic analysis - } - } - - TConstantUnion operator+(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator-(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator*(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator%(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator>>(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator<<(const TConstantUnion& constant) const - { - 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. - assert(constant.type == EbtInt || constant.type == EbtUInt); - switch (type) { - case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator&(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(constant.type == EbtInt || constant.type == EbtUInt); - switch (type) { - case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator|(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator^(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator&&(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator||(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } + yuvCscStandardEXTConst = s; + type = EbtYuvCscStandardEXT; + } + + int getIConst() const; + unsigned int getUConst() const; + float getFConst() const; + bool getBConst() const; + TYuvCscStandardEXT getYuvCscStandardEXTConst() const; + + bool operator==(const int i) const; + bool operator==(const unsigned int u) const; + bool operator==(const float f) const; + bool operator==(const bool b) const; + bool operator==(const TYuvCscStandardEXT s) const; + bool operator==(const TConstantUnion &constant) const; + bool operator!=(const int i) const; + bool operator!=(const unsigned int u) const; + bool operator!=(const float f) const; + bool operator!=(const bool b) const; + bool operator!=(const TYuvCscStandardEXT s) const; + bool operator!=(const TConstantUnion &constant) const; + bool operator>(const TConstantUnion &constant) const; + bool operator<(const TConstantUnion &constant) const; + static TConstantUnion add(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion sub(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion mul(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + TConstantUnion operator%(const TConstantUnion &constant) const; + static TConstantUnion rshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion lshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + TConstantUnion operator&(const TConstantUnion &constant) const; + TConstantUnion operator|(const TConstantUnion &constant) const; + TConstantUnion operator^(const TConstantUnion &constant) const; + TConstantUnion operator&&(const TConstantUnion &constant) const; + TConstantUnion operator||(const TConstantUnion &constant) const; TBasicType getType() const { return type; } -private: - - union { - int iConst; // used for ivec, scalar ints - unsigned int uConst; // used for uvec, scalar uints - bool bConst; // used for bvec, scalar bools - float fConst; // used for vec, mat, scalar floats - } ; + private: + union { + int iConst; // used for ivec, scalar ints + unsigned int uConst; // used for uvec, scalar uints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + TYuvCscStandardEXT yuvCscStandardEXTConst; + }; TBasicType type; }; -#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp new file mode 100644 index 0000000000..ce9828f1f9 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp @@ -0,0 +1,221 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Applies the necessary AST transformations to support multiview rendering through instancing. +// Check the header file For more information. +// + +#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h" + +#include "compiler/translator/FindMain.h" +#include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +class ReplaceVariableTraverser : public TIntermTraverser +{ + public: + ReplaceVariableTraverser(const TString &symbolName, TIntermSymbol *newSymbol) + : TIntermTraverser(true, false, false), mSymbolName(symbolName), mNewSymbol(newSymbol) + { + } + + void visitSymbol(TIntermSymbol *node) override + { + TName &name = node->getName(); + if (name.getString() == mSymbolName) + { + queueReplacement(mNewSymbol->deepCopy(), OriginalNode::IS_DROPPED); + } + } + + private: + TString mSymbolName; + TIntermSymbol *mNewSymbol; +}; + +TIntermSymbol *CreateGLInstanceIDSymbol(const TSymbolTable &symbolTable) +{ + return ReferenceBuiltInVariable("gl_InstanceID", symbolTable, 300); +} + +// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence. +void InitializeViewIDAndInstanceID(TIntermTyped *viewIDSymbol, + TIntermTyped *instanceIDSymbol, + unsigned numberOfViews, + const TSymbolTable &symbolTable, + TIntermSequence *initializers) +{ + // Create an unsigned numberOfViews node. + TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion(); + numberOfViewsUnsignedConstant->setUConst(numberOfViews); + TIntermConstantUnion *numberOfViewsUint = + new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst)); + + // Create a uint(gl_InstanceID) node. + TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence(); + glInstanceIDSymbolCastArguments->push_back(CreateGLInstanceIDSymbol(symbolTable)); + TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor( + TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments); + + // Create a uint(gl_InstanceID) / numberOfViews node. + TIntermBinary *normalizedInstanceID = + new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint); + + // Create an int(uint(gl_InstanceID) / numberOfViews) node. + TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence(); + normalizedInstanceIDCastArguments->push_back(normalizedInstanceID); + TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments); + + // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node. + TIntermBinary *instanceIDInitializer = + new TIntermBinary(EOpAssign, instanceIDSymbol->deepCopy(), normalizedInstanceIDAsInt); + initializers->push_back(instanceIDInitializer); + + // Create a uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *normalizedViewID = + new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy()); + + // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *viewIDInitializer = + new TIntermBinary(EOpAssign, viewIDSymbol->deepCopy(), normalizedViewID); + initializers->push_back(viewIDInitializer); +} + +// Replaces every occurrence of a symbol with the name specified in symbolName with newSymbolNode. +void ReplaceSymbol(TIntermBlock *root, const TString &symbolName, TIntermSymbol *newSymbolNode) +{ + ReplaceVariableTraverser traverser(symbolName, newSymbolNode); + root->traverse(&traverser); + traverser.updateTree(); +} + +void DeclareGlobalVariable(TIntermBlock *root, TIntermTyped *typedNode) +{ + TIntermSequence *globalSequence = root->getSequence(); + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(typedNode->deepCopy()); + globalSequence->insert(globalSequence->begin(), declaration); +} + +// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is +// added to the end of the initializers' sequence. +void SelectViewIndexInVertexShader(TIntermTyped *viewIDSymbol, + TIntermTyped *multiviewBaseViewLayerIndexSymbol, + TIntermSequence *initializers, + const TSymbolTable &symbolTable) +{ + // Create an int(ViewID_OVR) node. + TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence(); + viewIDSymbolCastArguments->push_back(viewIDSymbol); + TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments); + + // Create a gl_ViewportIndex node. + TIntermSymbol *viewportIndexSymbol = + ReferenceBuiltInVariable("gl_ViewportIndex", symbolTable, 0); + + // Create a { gl_ViewportIndex = int(ViewID_OVR) } node. + TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock(); + viewportIndexInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt)); + + // Create a gl_Layer node. + TIntermSymbol *layerSymbol = ReferenceBuiltInVariable("gl_Layer", symbolTable, 0); + + // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node + TIntermBinary *sumOfViewIDAndBaseViewIndex = + new TIntermBinary(EOpAdd, viewIDAsInt->deepCopy(), multiviewBaseViewLayerIndexSymbol); + + // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node. + TIntermBlock *layerInitializerInBlock = new TIntermBlock(); + layerInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex)); + + // Create a node to compare whether the base view index uniform is less than zero. + TIntermBinary *multiviewBaseViewLayerIndexZeroComparison = + new TIntermBinary(EOpLessThan, multiviewBaseViewLayerIndexSymbol->deepCopy(), + CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst))); + + // Create an if-else statement to select the code path. + TIntermIfElse *multiviewBranch = + new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison, + viewportIndexInitializerInBlock, layerInitializerInBlock); + + initializers->push_back(multiviewBranch); +} + +} // namespace + +void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, + unsigned numberOfViews, + GLenum shaderType, + ShCompileOptions compileOptions, + ShShaderOutput shaderOutput, + TSymbolTable *symbolTable) +{ + ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER); + + TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn; + TIntermSymbol *viewIDSymbol = new TIntermSymbol(symbolTable->nextUniqueId(), "ViewID_OVR", + TType(EbtUInt, EbpHigh, viewIDQualifier)); + viewIDSymbol->setInternal(true); + + DeclareGlobalVariable(root, viewIDSymbol); + ReplaceSymbol(root, "gl_ViewID_OVR", viewIDSymbol); + if (shaderType == GL_VERTEX_SHADER) + { + // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of + // InstanceID and ViewID. + TIntermSymbol *instanceIDSymbol = new TIntermSymbol( + symbolTable->nextUniqueId(), "InstanceID", TType(EbtInt, EbpHigh, EvqGlobal)); + instanceIDSymbol->setInternal(true); + DeclareGlobalVariable(root, instanceIDSymbol); + ReplaceSymbol(root, "gl_InstanceID", instanceIDSymbol); + + TIntermSequence *initializers = new TIntermSequence(); + InitializeViewIDAndInstanceID(viewIDSymbol, instanceIDSymbol, numberOfViews, *symbolTable, + initializers); + + // The AST transformation which adds the expression to select the viewport index should + // be done only for the GLSL and ESSL output. + const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u; + // Assert that if the view is selected in the vertex shader, then the output is + // either GLSL or ESSL. + ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)); + if (selectView) + { + // Add a uniform to switch between side-by-side and layered rendering. + TIntermSymbol *multiviewBaseViewLayerIndexSymbol = + new TIntermSymbol(symbolTable->nextUniqueId(), "multiviewBaseViewLayerIndex", + TType(EbtInt, EbpHigh, EvqUniform)); + multiviewBaseViewLayerIndexSymbol->setInternal(true); + DeclareGlobalVariable(root, multiviewBaseViewLayerIndexSymbol); + + // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's + // initialization. + SelectViewIndexInVertexShader(viewIDSymbol->deepCopy(), + multiviewBaseViewLayerIndexSymbol->deepCopy(), + initializers, *symbolTable); + } + + // Insert initializers at the beginning of main(). + TIntermBlock *initializersBlock = new TIntermBlock(); + initializersBlock->getSequence()->swap(*initializers); + TIntermBlock *mainBody = FindMainBody(root); + mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock); + } +} + +} // namespace sh \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h new file mode 100644 index 0000000000..b4ab05fd0e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Regardless of the shader type, the following AST transformations are applied: +// - Add declaration of View_ID_OVR. +// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and +// declare it as a flat varying. +// +// If the shader type is a vertex shader, the following AST transformations are applied: +// - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set +// its qualifier to EvqTemporary. +// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass +// should be executed before any variables get collected so that usage of gl_InstanceID is recorded. +// - If the output is ESSL or GLSL and the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is +// enabled, the expression +// "if (multiviewBaseViewLayerIndex < 0) { +// gl_ViewportIndex = int(ViewID_OVR); +// } else { +// gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex; +// }" +// is added after ViewID and InstanceID are initialized. Also, MultiviewRenderPath is added as a +// uniform. +// + +#ifndef COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ +#define COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ + +#include "GLSLANG/ShaderLang.h" +#include "angle_gl.h" + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, + unsigned numberOfViews, + GLenum shaderType, + ShCompileOptions compileOptions, + ShShaderOutput shaderOutput, + TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.cpp b/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.cpp new file mode 100644 index 0000000000..67d51ea87b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.cpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate +// function that is called in the beginning of main(). This enables initialization of globals with +// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing +// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be +// done after DeferGlobalInitializers is run. Note that it's important that the function definition +// is at the end of the shader, as some globals may be declared after main(). +// +// It can also initialize all uninitialized globals. +// + +#include "compiler/translator/DeferGlobalInitializers.h" + +#include "compiler/translator/FindMain.h" +#include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +void GetDeferredInitializers(TIntermDeclaration *declaration, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + TIntermSequence *deferredInitializersOut, + TSymbolTable *symbolTable) +{ + // SeparateDeclarations should have already been run. + ASSERT(declaration->getSequence()->size() == 1); + + TIntermNode *declarator = declaration->getSequence()->back(); + TIntermBinary *init = declarator->getAsBinaryNode(); + if (init) + { + TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); + TIntermTyped *expression = init->getRight(); + + if ((expression->getQualifier() != EvqConst || + (expression->getAsConstantUnion() == nullptr && + !expression->isConstructorWithOnlyConstantUnionParameters()))) + { + // For variables which are not constant, defer their real initialization until + // after we initialize uniforms. + // Deferral is done also in any cases where the variable has not been constant + // folded, since otherwise there's a chance that HLSL output will generate extra + // statements from the initializer expression. + + // Change const global to a regular global if its initialization is deferred. + // This can happen if ANGLE has not been able to fold the constant expression used + // as an initializer. + ASSERT(symbolNode->getQualifier() == EvqConst || + symbolNode->getQualifier() == EvqGlobal); + if (symbolNode->getQualifier() == EvqConst) + { + symbolNode->getTypePointer()->setQualifier(EvqGlobal); + } + + TIntermBinary *deferredInit = + new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight()); + deferredInitializersOut->push_back(deferredInit); + + // Remove the initializer from the global scope and just declare the global instead. + declaration->replaceChildNode(init, symbolNode); + } + } + else if (initializeUninitializedGlobals) + { + TIntermSymbol *symbolNode = declarator->getAsSymbolNode(); + ASSERT(symbolNode); + + // Ignore ANGLE internal variables. + if (symbolNode->getName().isInternal()) + return; + + if (symbolNode->getQualifier() == EvqGlobal && symbolNode->getSymbol() != "") + { + TIntermSequence *initCode = + CreateInitCode(symbolNode, canUseLoopsToInitialize, symbolTable); + deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(), + initCode->end()); + } + } +} + +void InsertInitCallToMain(TIntermBlock *root, + TIntermSequence *deferredInitializers, + TSymbolTable *symbolTable) +{ + TIntermBlock *initGlobalsBlock = new TIntermBlock(); + initGlobalsBlock->getSequence()->swap(*deferredInitializers); + + TSymbolUniqueId initGlobalsFunctionId(symbolTable); + + const char *kInitGlobalsFunctionName = "initGlobals"; + + TIntermFunctionPrototype *initGlobalsFunctionPrototype = + CreateInternalFunctionPrototypeNode(TType(), kInitGlobalsFunctionName, initGlobalsFunctionId); + root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype); + TIntermFunctionDefinition *initGlobalsFunctionDefinition = CreateInternalFunctionDefinitionNode( + TType(), kInitGlobalsFunctionName, initGlobalsBlock, initGlobalsFunctionId); + root->appendStatement(initGlobalsFunctionDefinition); + + TIntermAggregate *initGlobalsCall = CreateInternalFunctionCallNode( + TType(), kInitGlobalsFunctionName, initGlobalsFunctionId, new TIntermSequence()); + + TIntermBlock *mainBody = FindMainBody(root); + mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall); +} + +} // namespace + +void DeferGlobalInitializers(TIntermBlock *root, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable) +{ + TIntermSequence *deferredInitializers = new TIntermSequence(); + + // Loop over all global statements and process the declarations. This is simpler than using a + // traverser. + for (TIntermNode *statement : *root->getSequence()) + { + TIntermDeclaration *declaration = statement->getAsDeclarationNode(); + if (declaration) + { + GetDeferredInitializers(declaration, initializeUninitializedGlobals, + canUseLoopsToInitialize, deferredInitializers, symbolTable); + } + } + + // Add the function with initialization and the call to that. + if (!deferredInitializers->empty()) + { + InsertInitCallToMain(root, deferredInitializers, symbolTable); + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.h b/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.h new file mode 100644 index 0000000000..86930a585f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/DeferGlobalInitializers.h @@ -0,0 +1,32 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate +// function that is called in the beginning of main(). This enables initialization of globals with +// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing +// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be +// done after DeferGlobalInitializers is run. Note that it's important that the function definition +// is at the end of the shader, as some globals may be declared after main(). +// +// It can also initialize all uninitialized globals. +// + +#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ +#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void DeferGlobalInitializers(TIntermBlock *root, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp deleted file mode 100644 index 0dc5d22709..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/DetectCallDepth.h" -#include "compiler/translator/InfoSink.h" - -DetectCallDepth::FunctionNode::FunctionNode(const TString& fname) - : name(fname), - visit(PreVisit) -{ -} - -const TString& DetectCallDepth::FunctionNode::getName() const -{ - return name; -} - -void DetectCallDepth::FunctionNode::addCallee( - DetectCallDepth::FunctionNode* callee) -{ - for (size_t i = 0; i < callees.size(); ++i) { - if (callees[i] == callee) - return; - } - callees.push_back(callee); -} - -int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth) -{ - ASSERT(visit == PreVisit); - ASSERT(detectCallDepth); - - int retMaxDepth = depth; - visit = InVisit; - for (size_t i = 0; i < callees.size(); ++i) { - switch (callees[i]->visit) { - case InVisit: - // cycle detected, i.e., recursion detected. - return kInfiniteCallDepth; - case PostVisit: - break; - case PreVisit: { - // Check before we recurse so we don't go too depth - if (detectCallDepth->checkExceedsMaxDepth(depth)) - return depth; - int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1); - // Check after we recurse so we can exit immediately and provide info. - if (detectCallDepth->checkExceedsMaxDepth(callDepth)) { - detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName(); - return callDepth; - } - retMaxDepth = std::max(callDepth, retMaxDepth); - break; - } - default: - UNREACHABLE(); - break; - } - } - visit = PostVisit; - return retMaxDepth; -} - -void DetectCallDepth::FunctionNode::reset() -{ - visit = PreVisit; -} - -DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth) - : TIntermTraverser(true, false, true, false), - currentFunction(NULL), - infoSink(infoSink), - maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth) -{ -} - -DetectCallDepth::~DetectCallDepth() -{ - for (size_t i = 0; i < functions.size(); ++i) - delete functions[i]; -} - -bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node) -{ - switch (node->getOp()) - { - case EOpPrototype: - // Function declaration. - // Don't add FunctionNode here because node->getName() is the - // unmangled function name. - break; - case EOpFunction: { - // Function definition. - if (visit == PreVisit) { - currentFunction = findFunctionByName(node->getName()); - if (currentFunction == NULL) { - currentFunction = new FunctionNode(node->getName()); - functions.push_back(currentFunction); - } - } else if (visit == PostVisit) { - currentFunction = NULL; - } - break; - } - case EOpFunctionCall: { - // Function call. - if (visit == PreVisit) { - FunctionNode* func = findFunctionByName(node->getName()); - if (func == NULL) { - func = new FunctionNode(node->getName()); - functions.push_back(func); - } - if (currentFunction) - currentFunction->addCallee(func); - } - break; - } - default: - break; - } - return true; -} - -bool DetectCallDepth::checkExceedsMaxDepth(int depth) -{ - return depth >= maxDepth; -} - -void DetectCallDepth::resetFunctionNodes() -{ - for (size_t i = 0; i < functions.size(); ++i) { - functions[i]->reset(); - } -} - -DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func) -{ - currentFunction = NULL; - resetFunctionNodes(); - - int maxCallDepth = func->detectCallDepth(this, 1); - - if (maxCallDepth == FunctionNode::kInfiniteCallDepth) - return kErrorRecursion; - - if (maxCallDepth >= maxDepth) - return kErrorMaxDepthExceeded; - - return kErrorNone; -} - -DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth() -{ - if (maxDepth != FunctionNode::kInfiniteCallDepth) { - // Check all functions because the driver may fail on them - // TODO: Before detectingRecursion, strip unused functions. - for (size_t i = 0; i < functions.size(); ++i) { - ErrorCode error = detectCallDepthForFunction(functions[i]); - if (error != kErrorNone) - return error; - } - } else { - FunctionNode* main = findFunctionByName("main("); - if (main == NULL) - return kErrorMissingMain; - - return detectCallDepthForFunction(main); - } - - return kErrorNone; -} - -DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName( - const TString& name) -{ - for (size_t i = 0; i < functions.size(); ++i) { - if (functions[i]->getName() == name) - return functions[i]; - } - return NULL; -} - diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h deleted file mode 100644 index 8dd1391e67..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ -#define COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ - -#include -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/VariableInfo.h" - -class TInfoSink; - -// Traverses intermediate tree to detect function recursion. -class DetectCallDepth : public TIntermTraverser { -public: - enum ErrorCode { - kErrorMissingMain, - kErrorRecursion, - kErrorMaxDepthExceeded, - kErrorNone - }; - - DetectCallDepth(TInfoSink& infoSync, bool limitCallStackDepth, int maxCallStackDepth); - ~DetectCallDepth(); - - virtual bool visitAggregate(Visit, TIntermAggregate*); - - bool checkExceedsMaxDepth(int depth); - - ErrorCode detectCallDepth(); - -private: - class FunctionNode { - public: - static const int kInfiniteCallDepth = INT_MAX; - - FunctionNode(const TString& fname); - - const TString& getName() const; - - // If a function is already in the callee list, this becomes a no-op. - void addCallee(FunctionNode* callee); - - // Returns kInifinityCallDepth if recursive function calls are detected. - int detectCallDepth(DetectCallDepth* detectCallDepth, int depth); - - // Reset state. - void reset(); - - private: - // mangled function name is unique. - TString name; - - // functions that are directly called by this function. - TVector callees; - - Visit visit; - }; - - ErrorCode detectCallDepthForFunction(FunctionNode* func); - FunctionNode* findFunctionByName(const TString& name); - void resetFunctionNodes(); - - TInfoSink& getInfoSink() { return infoSink; } - - TVector functions; - FunctionNode* currentFunction; - TInfoSink& infoSink; - int maxDepth; - - DetectCallDepth(const DetectCallDepth&); - void operator=(const DetectCallDepth&); -}; - -#endif // COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp deleted file mode 100644 index f98d32b2b7..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp +++ /dev/null @@ -1,191 +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. -// -// Contains analysis utilities for dealing with HLSL's lack of support for -// the use of intrinsic functions which (implicitly or explicitly) compute -// gradients of functions with discontinuities. -// - -#include "compiler/translator/DetectDiscontinuity.h" - -#include "compiler/translator/ParseContext.h" - -namespace sh -{ - -// Detect Loop Discontinuity - -bool DetectLoopDiscontinuity::traverse(TIntermNode *node) -{ - mLoopDepth = 0; - mLoopDiscontinuity = false; - node->traverse(this); - return mLoopDiscontinuity; -} - -bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop) -{ - if (visit == PreVisit) - { - ++mLoopDepth; - } - else if (visit == PostVisit) - { - --mLoopDepth; - } - - return true; -} - -bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node) -{ - if (mLoopDiscontinuity) - { - return false; - } - - if (!mLoopDepth) - { - return true; - } - - switch (node->getFlowOp()) - { - case EOpKill: - break; - case EOpBreak: - case EOpContinue: - case EOpReturn: - mLoopDiscontinuity = true; - break; - default: UNREACHABLE(); - } - - return !mLoopDiscontinuity; -} - -bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node) -{ - return !mLoopDiscontinuity; -} - -bool containsLoopDiscontinuity(TIntermNode *node) -{ - DetectLoopDiscontinuity detectLoopDiscontinuity; - return detectLoopDiscontinuity.traverse(node); -} - -// Detect Any Loop - -bool DetectAnyLoop::traverse(TIntermNode *node) -{ - mHasLoop = false; - node->traverse(this); - return mHasLoop; -} - -bool DetectAnyLoop::visitLoop(Visit visit, TIntermLoop *loop) -{ - mHasLoop = true; - return false; -} - -// The following definitions stop all traversal when we have found a loop -bool DetectAnyLoop::visitBinary(Visit, TIntermBinary *) -{ - return !mHasLoop; -} - -bool DetectAnyLoop::visitUnary(Visit, TIntermUnary *) -{ - return !mHasLoop; -} - -bool DetectAnyLoop::visitSelection(Visit, TIntermSelection *) -{ - return !mHasLoop; -} - -bool DetectAnyLoop::visitAggregate(Visit, TIntermAggregate *) -{ - return !mHasLoop; -} - -bool DetectAnyLoop::visitBranch(Visit, TIntermBranch *) -{ - return !mHasLoop; -} - -bool containsAnyLoop(TIntermNode *node) -{ - DetectAnyLoop detectAnyLoop; - return detectAnyLoop.traverse(node); -} - -// Detect Gradient Operation - -bool DetectGradientOperation::traverse(TIntermNode *node) -{ - mGradientOperation = false; - node->traverse(this); - return mGradientOperation; -} - -bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node) -{ - if (mGradientOperation) - { - return false; - } - - switch (node->getOp()) - { - case EOpDFdx: - case EOpDFdy: - mGradientOperation = true; - default: - break; - } - - return !mGradientOperation; -} - -bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node) -{ - if (mGradientOperation) - { - return false; - } - - if (node->getOp() == EOpFunctionCall) - { - if (!node->isUserDefined()) - { - TString name = TFunction::unmangleName(node->getName()); - - if (name == "texture2D" || - name == "texture2DProj" || - name == "textureCube") - { - mGradientOperation = true; - } - } - else - { - // When a user defined function is called, we have to - // conservatively assume it to contain gradient operations - mGradientOperation = true; - } - } - - return !mGradientOperation; -} - -bool containsGradientOperation(TIntermNode *node) -{ - DetectGradientOperation detectGradientOperation; - return detectGradientOperation.traverse(node); -} -} diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h deleted file mode 100644 index 623be13533..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h +++ /dev/null @@ -1,71 +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. -// -// Contains analysis utilities for dealing with HLSL's lack of support for -// the use of intrinsic functions which (implicitly or explicitly) compute -// gradients of functions with discontinuities. -// - -#ifndef COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ -#define COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ - -#include "compiler/translator/IntermNode.h" - -namespace sh -{ -// Checks whether a loop can run for a variable number of iterations -class DetectLoopDiscontinuity : public TIntermTraverser -{ - public: - bool traverse(TIntermNode *node); - - protected: - bool visitBranch(Visit visit, TIntermBranch *node); - bool visitLoop(Visit visit, TIntermLoop *loop); - bool visitAggregate(Visit visit, TIntermAggregate *node); - - int mLoopDepth; - bool mLoopDiscontinuity; -}; - -bool containsLoopDiscontinuity(TIntermNode *node); - -// Checks for the existence of any loop -class DetectAnyLoop : public TIntermTraverser -{ -public: - bool traverse(TIntermNode *node); - -protected: - bool visitBinary(Visit, TIntermBinary *); - bool visitUnary(Visit, TIntermUnary *); - bool visitSelection(Visit, TIntermSelection *); - bool visitAggregate(Visit, TIntermAggregate *); - bool visitLoop(Visit, TIntermLoop *); - bool visitBranch(Visit, TIntermBranch *); - - bool mHasLoop; -}; - -bool containsAnyLoop(TIntermNode *node); - -// Checks for intrinsic functions which compute gradients -class DetectGradientOperation : public TIntermTraverser -{ - public: - bool traverse(TIntermNode *node); - - protected: - bool visitUnary(Visit visit, TIntermUnary *node); - bool visitAggregate(Visit visit, TIntermAggregate *node); - - bool mGradientOperation; -}; - -bool containsGradientOperation(TIntermNode *node); - -} - -#endif // COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp index 593137fb0a..1744e5ab3e 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.cpp @@ -7,13 +7,15 @@ #include "compiler/translator/Diagnostics.h" #include "common/debug.h" -#include "compiler/translator/InfoSink.h" #include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" + +namespace sh +{ -TDiagnostics::TDiagnostics(TInfoSink& infoSink) : - mInfoSink(infoSink), - mNumErrors(0), - mNumWarnings(0) +TDiagnostics::TDiagnostics(TInfoSinkBase &infoSink) + : mInfoSink(infoSink), mNumErrors(0), mNumWarnings(0) { } @@ -22,37 +24,82 @@ TDiagnostics::~TDiagnostics() } void TDiagnostics::writeInfo(Severity severity, - const pp::SourceLocation& loc, - const std::string& reason, - const std::string& token, - const std::string& extra) + const pp::SourceLocation &loc, + const char *reason, + const char *token) { - TPrefixType prefix = EPrefixNone; switch (severity) { - case PP_ERROR: - ++mNumErrors; - prefix = EPrefixError; - break; - case PP_WARNING: - ++mNumWarnings; - prefix = EPrefixWarning; - break; - default: - UNREACHABLE(); - break; + case SH_ERROR: + ++mNumErrors; + break; + case SH_WARNING: + ++mNumWarnings; + break; + default: + UNREACHABLE(); + break; } - TInfoSinkBase& sink = mInfoSink.info; /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ - sink.prefix(prefix); - sink.location(loc.file, loc.line); - sink << "'" << token << "' : " << reason << " " << extra << "\n"; + mInfoSink.prefix(severity); + mInfoSink.location(loc.file, loc.line); + mInfoSink << "'" << token << "' : " << reason << "\n"; } -void TDiagnostics::print(ID id, - const pp::SourceLocation& loc, - const std::string& text) +void TDiagnostics::globalError(const char *message) { - writeInfo(severity(id), loc, message(id), text, ""); + ++mNumErrors; + mInfoSink.prefix(SH_ERROR); + mInfoSink << message << "\n"; } + +void TDiagnostics::error(const pp::SourceLocation &loc, const char *reason, const char *token) +{ + writeInfo(SH_ERROR, loc, reason, token); +} + +void TDiagnostics::warning(const pp::SourceLocation &loc, const char *reason, const char *token) +{ + writeInfo(SH_WARNING, loc, reason, token); +} + +void TDiagnostics::error(const TSourceLoc &loc, const char *reason, const char *token) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + error(srcLoc, reason, token); +} + +void TDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + warning(srcLoc, reason, token); +} + +void TDiagnostics::print(ID id, const pp::SourceLocation &loc, const std::string &text) +{ + writeInfo(isError(id) ? SH_ERROR : SH_WARNING, loc, message(id), text.c_str()); +} + +void TDiagnostics::resetErrorCount() +{ + mNumErrors = 0; + mNumWarnings = 0; +} + +PerformanceDiagnostics::PerformanceDiagnostics(TDiagnostics *diagnostics) + : mDiagnostics(diagnostics) +{ + ASSERT(diagnostics); +} + +void PerformanceDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token) +{ + mDiagnostics->warning(loc, reason, token); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h index bc26e4584f..55b88991df 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h @@ -9,33 +9,59 @@ #include "common/angleutils.h" #include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/translator/Severity.h" -class TInfoSink; +namespace sh +{ + +class TInfoSinkBase; +struct TSourceLoc; class TDiagnostics : public pp::Diagnostics, angle::NonCopyable { public: - TDiagnostics(TInfoSink& infoSink); + TDiagnostics(TInfoSinkBase &infoSink); ~TDiagnostics() override; - TInfoSink& infoSink() { return mInfoSink; } - int numErrors() const { return mNumErrors; } int numWarnings() const { return mNumWarnings; } - void writeInfo(Severity severity, - const pp::SourceLocation& loc, - const std::string& reason, - const std::string& token, - const std::string& extra); + void error(const pp::SourceLocation &loc, const char *reason, const char *token); + void warning(const pp::SourceLocation &loc, const char *reason, const char *token); + + void error(const TSourceLoc &loc, const char *reason, const char *token); + void warning(const TSourceLoc &loc, const char *reason, const char *token); + + void globalError(const char *message); + + void resetErrorCount(); protected: + void writeInfo(Severity severity, + const pp::SourceLocation &loc, + const char *reason, + const char *token); + void print(ID id, const pp::SourceLocation &loc, const std::string &text) override; private: - TInfoSink& mInfoSink; + TInfoSinkBase &mInfoSink; int mNumErrors; int mNumWarnings; }; +// Diagnostics wrapper to use when the code is only allowed to generate warnings. +class PerformanceDiagnostics : public angle::NonCopyable +{ + public: + PerformanceDiagnostics(TDiagnostics *diagnostics); + + void warning(const TSourceLoc &loc, const char *reason, const char *token); + + private: + TDiagnostics *mDiagnostics; +}; + +} // namespace sh + #endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp index ff8a69efa5..485e66670c 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp @@ -12,17 +12,24 @@ #include "common/debug.h" #include "compiler/translator/Diagnostics.h" -static TBehavior getBehavior(const std::string& str) +namespace sh +{ + +static TBehavior getBehavior(const std::string &str) { const char kRequire[] = "require"; - const char kEnable[] = "enable"; + const char kEnable[] = "enable"; const char kDisable[] = "disable"; - const char kWarn[] = "warn"; - - if (str == kRequire) return EBhRequire; - else if (str == kEnable) return EBhEnable; - else if (str == kDisable) return EBhDisable; - else if (str == kWarn) return EBhWarn; + const char kWarn[] = "warn"; + + if (str == kRequire) + return EBhRequire; + else if (str == kEnable) + return EBhEnable; + else if (str == kDisable) + return EBhDisable; + else if (str == kWarn) + return EBhWarn; return EBhUndefined; } @@ -43,30 +50,29 @@ TDirectiveHandler::~TDirectiveHandler() { } -void TDirectiveHandler::handleError(const pp::SourceLocation& loc, - const std::string& msg) +void TDirectiveHandler::handleError(const pp::SourceLocation &loc, const std::string &msg) { - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", ""); + mDiagnostics.error(loc, msg.c_str(), ""); } -void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, - const std::string& name, - const std::string& value, +void TDirectiveHandler::handlePragma(const pp::SourceLocation &loc, + const std::string &name, + const std::string &value, bool stdgl) { if (stdgl) { const char kInvariant[] = "invariant"; - const char kAll[] = "all"; + 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); + mDiagnostics.error( + loc, "#pragma STDGL invariant(all) can not be used in fragment shader", + name.c_str()); } mPragma.stdgl.invariantAll = true; } @@ -77,30 +83,39 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, } else { - const char kOptimize[] = "optimize"; - const char kDebug[] = "debug"; + const char kOptimize[] = "optimize"; + const char kDebug[] = "debug"; const char kDebugShaderPrecision[] = "webgl_debug_shader_precision"; - const char kOn[] = "on"; - const char kOff[] = "off"; + const char kOn[] = "on"; + const char kOff[] = "off"; bool invalidValue = false; if (name == kOptimize) { - if (value == kOn) mPragma.optimize = true; - else if (value == kOff) mPragma.optimize = false; - else invalidValue = true; + if (value == kOn) + mPragma.optimize = true; + else if (value == kOff) + mPragma.optimize = false; + else + invalidValue = true; } else if (name == kDebug) { - if (value == kOn) mPragma.debug = true; - else if (value == kOff) mPragma.debug = false; - else invalidValue = true; + if (value == kOn) + mPragma.debug = true; + else if (value == kOff) + mPragma.debug = false; + else + invalidValue = true; } else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported) { - if (value == kOn) mPragma.debugShaderPrecision = true; - else if (value == kOff) mPragma.debugShaderPrecision = false; - else invalidValue = true; + if (value == kOn) + mPragma.debugShaderPrecision = true; + else if (value == kOff) + mPragma.debugShaderPrecision = false; + else + invalidValue = true; } else { @@ -110,24 +125,21 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, if (invalidValue) { - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "invalid pragma value", value, - "'on' or 'off' expected"); + mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str()); } } } -void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, - const std::string& name, - const std::string& behavior) +void TDirectiveHandler::handleExtension(const pp::SourceLocation &loc, + const std::string &name, + const std::string &behavior) { const char kExtAll[] = "all"; TBehavior behaviorVal = getBehavior(behavior); if (behaviorVal == EBhUndefined) { - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "behavior", name, "invalid"); + mDiagnostics.error(loc, "behavior invalid", name.c_str()); return; } @@ -135,15 +147,11 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, { if (behaviorVal == EBhRequire) { - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "extension", name, - "cannot have 'require' behavior"); + mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str()); } else if (behaviorVal == EBhEnable) { - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "extension", name, - "cannot have 'enable' behavior"); + mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str()); } else { @@ -154,36 +162,32 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, return; } - TExtensionBehavior::iterator iter = mExtensionBehavior.find(name); + TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str())); if (iter != mExtensionBehavior.end()) { iter->second = behaviorVal; return; } - pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR; - switch (behaviorVal) { - case EBhRequire: - severity = pp::Diagnostics::PP_ERROR; - break; - case EBhEnable: - case EBhWarn: - case EBhDisable: - severity = pp::Diagnostics::PP_WARNING; - break; - default: - UNREACHABLE(); - break; + switch (behaviorVal) + { + case EBhRequire: + mDiagnostics.error(loc, "extension is not supported", name.c_str()); + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + mDiagnostics.warning(loc, "extension is not supported", name.c_str()); + break; + default: + UNREACHABLE(); + break; } - mDiagnostics.writeInfo(severity, loc, - "extension", name, "is not supported"); } -void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, - int version) +void TDirectiveHandler::handleVersion(const pp::SourceLocation &loc, int version) { - if (version == 100 || - version == 300) + if (version == 100 || version == 300 || version == 310) { mShaderVersion = version; } @@ -192,7 +196,8 @@ void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, std::stringstream stream; stream << version; std::string str = stream.str(); - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "version number", str, "not supported"); + mDiagnostics.error(loc, "version number not supported", str.c_str()); } } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h index 00eb49114e..8e8cb9bbf6 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h @@ -13,6 +13,8 @@ #include "compiler/preprocessor/DirectiveHandlerBase.h" #include "GLSLANG/ShaderLang.h" +namespace sh +{ class TDiagnostics; class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable @@ -25,8 +27,8 @@ class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable bool debugShaderPrecisionSupported); ~TDirectiveHandler() override; - const TPragma& pragma() const { return mPragma; } - const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; } + const TPragma &pragma() const { return mPragma; } + const TExtensionBehavior &extensionBehavior() const { return mExtensionBehavior; } void handleError(const pp::SourceLocation &loc, const std::string &msg) override; @@ -43,11 +45,13 @@ class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable private: TPragma mPragma; - TExtensionBehavior& mExtensionBehavior; - TDiagnostics& mDiagnostics; - int& mShaderVersion; + TExtensionBehavior &mExtensionBehavior; + TDiagnostics &mDiagnostics; + int &mShaderVersion; sh::GLenum mShaderType; bool mDebugShaderPrecisionSupported; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp new file mode 100644 index 0000000000..189ea341eb --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp @@ -0,0 +1,129 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// gl_FragColor needs to broadcast to all color buffers in ES2 if +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// +// We emulate this by replacing all gl_FragColor with gl_FragData[0], and in the end +// of main() function, assigning gl_FragData[1], ..., gl_FragData[maxDrawBuffers-1] +// with gl_FragData[0]. +// + +#include "compiler/translator/EmulateGLFragColorBroadcast.h" + +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/RunAtTheEndOfShader.h" + +namespace sh +{ + +namespace +{ + +class GLFragColorBroadcastTraverser : public TIntermTraverser +{ + public: + GLFragColorBroadcastTraverser(int maxDrawBuffers, TSymbolTable *symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false, symbolTable), + mGLFragColorUsed(false), + mMaxDrawBuffers(maxDrawBuffers), + mShaderVersion(shaderVersion) + { + } + + void broadcastGLFragColor(TIntermBlock *root); + + bool isGLFragColorUsed() const { return mGLFragColorUsed; } + + protected: + void visitSymbol(TIntermSymbol *node) override; + + TIntermBinary *constructGLFragDataNode(int index) const; + TIntermBinary *constructGLFragDataAssignNode(int index) const; + + private: + bool mGLFragColorUsed; + int mMaxDrawBuffers; + const int mShaderVersion; +}; + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const +{ + TIntermSymbol *symbol = + ReferenceBuiltInVariable(TString("gl_FragData"), *mSymbolTable, mShaderVersion); + TIntermTyped *indexNode = CreateIndexNode(index); + + TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode); + return binary; +} + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const +{ + TIntermTyped *fragDataIndex = constructGLFragDataNode(index); + TIntermTyped *fragDataZero = constructGLFragDataNode(0); + + return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero); +} + +void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node) +{ + if (node->getSymbol() == "gl_FragColor") + { + queueReplacement(constructGLFragDataNode(0), OriginalNode::IS_DROPPED); + mGLFragColorUsed = true; + } +} + +void GLFragColorBroadcastTraverser::broadcastGLFragColor(TIntermBlock *root) +{ + ASSERT(mMaxDrawBuffers > 1); + if (!mGLFragColorUsed) + { + return; + } + + TIntermBlock *broadcastBlock = new TIntermBlock(); + // Now insert statements + // gl_FragData[1] = gl_FragData[0]; + // ... + // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0]; + for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex) + { + broadcastBlock->appendStatement(constructGLFragDataAssignNode(colorIndex)); + } + RunAtTheEndOfShader(root, broadcastBlock, mSymbolTable); +} + +} // namespace anonymous + +void EmulateGLFragColorBroadcast(TIntermBlock *root, + int maxDrawBuffers, + std::vector *outputVariables, + TSymbolTable *symbolTable, + int shaderVersion) +{ + ASSERT(maxDrawBuffers > 1); + GLFragColorBroadcastTraverser traverser(maxDrawBuffers, symbolTable, shaderVersion); + root->traverse(&traverser); + if (traverser.isGLFragColorUsed()) + { + traverser.updateTree(); + traverser.broadcastGLFragColor(root); + for (auto &var : *outputVariables) + { + if (var.name == "gl_FragColor") + { + // TODO(zmo): Find a way to keep the original variable information. + var.name = "gl_FragData"; + var.mappedName = "gl_FragData"; + var.arraySizes.push_back(maxDrawBuffers); + ASSERT(var.arraySizes.size() == 1u); + } + } + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h b/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h new file mode 100644 index 0000000000..e652b7e07e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Emulate gl_FragColor broadcast behaviors in ES2 where +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// + +#ifndef COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ +#define COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ + +#include + +namespace sh +{ +struct OutputVariable; +class TIntermBlock; +class TSymbolTable; + +// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function, +// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0]. +// If gl_FragColor is in outputVariables, it is replaced by gl_FragData. +void EmulateGLFragColorBroadcast(TIntermBlock *root, + int maxDrawBuffers, + std::vector *outputVariables, + TSymbolTable *symbolTable, + int shaderVersion); +} + +#endif // COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp index 4a7fa54155..ba09fd77df 100644 --- a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp @@ -6,88 +6,206 @@ #include "compiler/translator/EmulatePrecision.h" -namespace -{ +#include -static void writeVectorPrecisionEmulationHelpers( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size) +namespace sh { - std::stringstream vecTypeStrStr; - if (outputLanguage == SH_ESSL_OUTPUT) - vecTypeStrStr << "highp "; - vecTypeStrStr << "vec" << size; - std::string vecType = vecTypeStrStr.str(); - sink << - vecType << " angle_frm(in " << vecType << " v) {\n" - " v = clamp(v, -65504.0, 65504.0);\n" - " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" - " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" - " v = v * exp2(-exponent);\n" - " v = sign(v) * floor(abs(v));\n" - " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" - "}\n"; +namespace +{ - sink << - vecType << " angle_frl(in " << vecType << " v) {\n" - " v = clamp(v, -2.0, 2.0);\n" - " v = v * 256.0;\n" - " v = sign(v) * floor(abs(v));\n" - " return v * 0.00390625;\n" - "}\n"; -} +class RoundingHelperWriter : angle::NonCopyable +{ + public: + static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage); + + void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion); + void writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr); + + virtual ~RoundingHelperWriter() {} + + protected: + RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {} + RoundingHelperWriter() = delete; + + const ShShaderOutput mOutputLanguage; + + private: + virtual std::string getTypeString(const char *glslType) = 0; + virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0; + virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0; + virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) = 0; +}; + +class RoundingHelperWriterGLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) + { + } -static void writeMatrixPrecisionEmulationHelper( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size, const char *functionName) + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL { - std::stringstream matTypeStrStr; - if (outputLanguage == SH_ESSL_OUTPUT) - matTypeStrStr << "highp "; - matTypeStrStr << "mat" << size; - std::string matType = matTypeStrStr.str(); + public: + RoundingHelperWriterESSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriterGLSL(outputLanguage) + { + } - sink << matType << " " << functionName << "(in " << matType << " m) {\n" - " " << matType << " rounded;\n"; + private: + std::string getTypeString(const char *glslType) override; +}; - for (unsigned int i = 0; i < size; ++i) +class RoundingHelperWriterHLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) { - sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; } - sink << " return rounded;\n" - "}\n"; + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage) +{ + ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage)); + switch (outputLanguage) + { + case SH_HLSL_4_1_OUTPUT: + return new RoundingHelperWriterHLSL(outputLanguage); + case SH_ESSL_OUTPUT: + return new RoundingHelperWriterESSL(outputLanguage); + default: + return new RoundingHelperWriterGLSL(outputLanguage); + } } -static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion) { // Write the angle_frm functions that round floating point numbers to // half precision, and angle_frl functions that round them to minimum lowp // precision. + writeFloatRoundingHelpers(sink); + writeVectorRoundingHelpers(sink, 2); + writeVectorRoundingHelpers(sink, 3); + writeVectorRoundingHelpers(sink, 4); + if (shaderVersion > 100) + { + for (unsigned int columns = 2; columns <= 4; ++columns) + { + for (unsigned int rows = 2; rows <= 4; ++rows) + { + writeMatrixRoundingHelper(sink, columns, rows, "angle_frm"); + writeMatrixRoundingHelper(sink, columns, rows, "angle_frl"); + } + } + } + else + { + for (unsigned int size = 2; size <= 4; ++size) + { + writeMatrixRoundingHelper(sink, size, size, "angle_frm"); + writeMatrixRoundingHelper(sink, size, size, "angle_frl"); + } + } +} + +void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr) +{ + std::string lTypeStr = getTypeString(lType); + std::string rTypeStr = getTypeString(rType); + + // Note that y should be passed through angle_frm at the function call site, + // but x can't be passed through angle_frm there since it is an inout parameter. + // So only pass x and the result through angle_frm here. + // clang-format off + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frm(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frl(angle_frl(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + // clang-format on +} + +std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType) +{ + return glslType; +} + +std::string RoundingHelperWriterESSL::getTypeString(const char *glslType) +{ + std::stringstream typeStrStr; + typeStrStr << "highp " << glslType; + return typeStrStr.str(); +} + +void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ // Unoptimized version of angle_frm for single floats: // - // int webgl_maxNormalExponent(in int exponentBits) { + // int webgl_maxNormalExponent(in int exponentBits) + // { // int possibleExponents = int(exp2(float(exponentBits))); // int exponentBias = possibleExponents / 2 - 1; // int allExponentBitsOne = possibleExponents - 1; // return (allExponentBitsOne - 1) - exponentBias; // } // - // float angle_frm(in float x) { + // float angle_frm(in float x) + // { // int mantissaBits = 10; // int exponentBits = 5; // float possibleMantissas = exp2(float(mantissaBits)); // float mantissaMax = 2.0 - 1.0 / possibleMantissas; // int maxNE = webgl_maxNormalExponent(exponentBits); // float max = exp2(float(maxNE)) * mantissaMax; - // if (x > max) { + // if (x > max) + // { // return max; // } - // if (x < -max) { + // if (x < -max) + // { // return -max; // } // float exponent = floor(log2(abs(x))); - // if (abs(x) == 0.0 || exponent < -float(maxNE)) { + // if (abs(x) == 0.0 || exponent < -float(maxNE)) + // { // return 0.0 * sign(x) // } // x = x * exp2(-(exponent - float(mantissaBits))); @@ -109,140 +227,215 @@ static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOu // numbers will be flushed to zero either way (2^-15 is the smallest // normal positive number), this does not introduce any error. - std::string floatType = "float"; - if (outputLanguage == SH_ESSL_OUTPUT) - floatType = "highp float"; + std::string floatType = getTypeString("float"); + + // clang-format off + sink << + floatType << " angle_frm(in " << floatType << " x) {\n" + " x = clamp(x, -65504.0, 65504.0);\n" + " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" + " bool isNonZero = (exponent >= -25.0);\n" + " x = x * exp2(-exponent);\n" + " x = sign(x) * floor(abs(x));\n" + " return x * exp2(exponent) * float(isNonZero);\n" + "}\n"; + + sink << + floatType << " angle_frl(in " << floatType << " x) {\n" + " x = clamp(x, -2.0, 2.0);\n" + " x = x * 256.0;\n" + " x = sign(x) * floor(abs(x));\n" + " return x * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr; + vecTypeStrStr << "vec" << size; + std::string vecType = getTypeString(vecTypeStrStr.str().c_str()); + // clang-format off sink << - floatType << " angle_frm(in " << floatType << " x) {\n" - " x = clamp(x, -65504.0, 65504.0);\n" - " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" - " bool isNonZero = (exponent >= -25.0);\n" - " x = x * exp2(-exponent);\n" - " x = sign(x) * floor(abs(x));\n" - " return x * exp2(exponent) * float(isNonZero);\n" - "}\n"; + vecType << " angle_frm(in " << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" + "}\n"; sink << - floatType << " angle_frl(in " << floatType << " x) {\n" - " x = clamp(x, -2.0, 2.0);\n" - " x = x * 256.0;\n" - " x = sign(x) * floor(abs(x));\n" - " return x * 0.00390625;\n" - "}\n"; + vecType << " angle_frl(in " << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on +} - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 2); - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 3); - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 4); - for (unsigned int size = 2; size <= 4; ++size) +void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) +{ + std::stringstream matTypeStrStr; + matTypeStrStr << "mat" << columns; + if (rows != columns) { - writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frm"); - writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frl"); + matTypeStrStr << "x" << rows; + } + std::string matType = getTypeString(matTypeStrStr.str().c_str()); + + sink << matType << " " << functionName << "(in " << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; } + + sink << " return rounded;\n" + "}\n"; } -static void writeCompoundAssignmentPrecisionEmulation( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, - const char *lType, const char *rType, const char *opStr, const char *opNameStr) +static const char *GetHLSLTypeStr(const char *floatTypeStr) { - std::string lTypeStr = lType; - std::string rTypeStr = rType; - if (outputLanguage == SH_ESSL_OUTPUT) + if (strcmp(floatTypeStr, "float") == 0) + { + return "float"; + } + if (strcmp(floatTypeStr, "vec2") == 0) + { + return "float2"; + } + if (strcmp(floatTypeStr, "vec3") == 0) + { + return "float3"; + } + if (strcmp(floatTypeStr, "vec4") == 0) + { + return "float4"; + } + if (strcmp(floatTypeStr, "mat2") == 0) + { + return "float2x2"; + } + if (strcmp(floatTypeStr, "mat3") == 0) { - std::stringstream lTypeStrStr; - lTypeStrStr << "highp " << lType; - lTypeStr = lTypeStrStr.str(); - std::stringstream rTypeStrStr; - rTypeStrStr << "highp " << rType; - rTypeStr = rTypeStrStr.str(); + return "float3x3"; } + if (strcmp(floatTypeStr, "mat4") == 0) + { + return "float4x4"; + } + if (strcmp(floatTypeStr, "mat2x3") == 0) + { + return "float2x3"; + } + if (strcmp(floatTypeStr, "mat2x4") == 0) + { + return "float2x4"; + } + if (strcmp(floatTypeStr, "mat3x2") == 0) + { + return "float3x2"; + } + if (strcmp(floatTypeStr, "mat3x4") == 0) + { + return "float3x4"; + } + if (strcmp(floatTypeStr, "mat4x2") == 0) + { + return "float4x2"; + } + if (strcmp(floatTypeStr, "mat4x3") == 0) + { + return "float4x3"; + } + UNREACHABLE(); + return nullptr; +} - // Note that y should be passed through angle_frm at the function call site, - // but x can't be passed through angle_frm there since it is an inout parameter. - // So only pass x and the result through angle_frm here. +std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType) +{ + return GetHLSLTypeStr(glslType); +} + +void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ + // In HLSL scalars are the same as 1-vectors. + writeVectorRoundingHelpers(sink, 1); +} + +void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr; + vecTypeStrStr << "float" << size; + std::string vecType = vecTypeStrStr.str(); + + // clang-format off sink << - lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" - " x = angle_frm(angle_frm(x) " << opStr << " y);\n" - " return x;\n" - "}\n"; + vecType << " angle_frm(" << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bool" << size << " isNonZero = exponent < -25.0;\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * (float" << size << ")(isNonZero);\n" + "}\n"; + sink << - lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" - " x = angle_frl(angle_frm(x) " << opStr << " y);\n" - " return x;\n" - "}\n"; + vecType << " angle_frl(" << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on } -const char *getFloatTypeStr(const TType& type) +void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) { - switch (type.getNominalSize()) + std::stringstream matTypeStrStr; + matTypeStrStr << "float" << columns << "x" << rows; + std::string matType = matTypeStrStr.str(); + + sink << matType << " " << functionName << "(" << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) { - case 1: - return "float"; - case 2: - 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: - 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: - 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; + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; } + + sink << " return rounded;\n" + "}\n"; } bool canRoundFloat(const TType &type) { - return type.getBasicType() == EbtFloat && !type.isNonSquareMatrix() && !type.isArray() && - (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); + return type.getBasicType() == EbtFloat && !type.isArray() && + (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); } -TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child) +TIntermAggregate *createInternalFunctionCallNode(const TType &type, + TString name, + TIntermSequence *arguments) { - TIntermAggregate *callNode = new TIntermAggregate(); - callNode->setOp(EOpFunctionCall); - TName nameObj(TFunction::mangleName(name)); + TName nameObj(name); nameObj.setInternal(true); - callNode->setNameObj(nameObj); - callNode->getSequence()->push_back(child); + TIntermAggregate *callNode = + TIntermAggregate::Create(type, EOpCallInternalRawFunction, arguments); + callNode->getFunctionSymbolInfo()->setNameObj(nameObj); return callNode; } @@ -252,63 +445,92 @@ TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild) if (roundedChild->getPrecision() == EbpMedium) roundFunctionName = "angle_frm"; else - roundFunctionName = "angle_frl"; - return createInternalFunctionCallNode(roundFunctionName, roundedChild); + roundFunctionName = "angle_frl"; + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(roundedChild); + TIntermAggregate *callNode = + createInternalFunctionCallNode(roundedChild->getType(), roundFunctionName, arguments); + callNode->getFunctionSymbolInfo()->setKnownToNotHaveSideEffects(true); + return callNode; } -TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr) +TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, + TIntermTyped *right, + const char *opNameStr) { std::stringstream strstr; if (left->getPrecision() == EbpMedium) strstr << "angle_compound_" << opNameStr << "_frm"; else strstr << "angle_compound_" << opNameStr << "_frl"; - TString functionName = strstr.str().c_str(); - TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left); - callNode->getSequence()->push_back(right); - return callNode; + TString functionName = strstr.str().c_str(); + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(left); + arguments->push_back(right); + return createInternalFunctionCallNode(left->getType(), functionName, arguments); } -bool parentUsesResult(TIntermNode* parent, TIntermNode* node) +bool ParentUsesResult(TIntermNode *parent, TIntermTyped *node) { if (!parent) { return false; } - TIntermAggregate *aggParent = parent->getAsAggregate(); - // If the parent's op is EOpSequence, the result is not assigned anywhere, + TIntermBlock *blockParent = parent->getAsBlock(); + // If the parent is a block, the result is not assigned anywhere, // so rounding it is not needed. In particular, this can avoid a lot of // unnecessary rounding of unused return values of assignment. - if (aggParent && aggParent->getOp() == EOpSequence) + if (blockParent) { return false; } - if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node)) + TIntermBinary *binaryParent = parent->getAsBinaryNode(); + if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node)) { return false; } return true; } +bool ParentConstructorTakesCareOfRounding(TIntermNode *parent, TIntermTyped *node) +{ + if (!parent) + { + return false; + } + TIntermAggregate *parentConstructor = parent->getAsAggregate(); + if (!parentConstructor || parentConstructor->getOp() != EOpConstruct) + { + return false; + } + if (parentConstructor->getPrecision() != node->getPrecision()) + { + return false; + } + return canRoundFloat(parentConstructor->getType()); +} + } // namespace anonymous -EmulatePrecision::EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion) +EmulatePrecision::EmulatePrecision(TSymbolTable *symbolTable, int shaderVersion) : TLValueTrackingTraverser(true, true, true, symbolTable, shaderVersion), mDeclaringVariables(false) -{} +{ +} void EmulatePrecision::visitSymbol(TIntermSymbol *node) { - if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere()) + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && + !ParentConstructorTakesCareOfRounding(parent, node) && !mDeclaringVariables && + !isLValueRequiredHere()) { - TIntermNode *parent = getParentNode(); TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); } } - bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; @@ -319,189 +541,211 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) if (op == EOpInitialize && visit == InVisit) mDeclaringVariables = false; - if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && visit == InVisit) + if ((op == EOpIndexDirectStruct) && visit == InVisit) visitChildren = false; if (visit != PreVisit) return visitChildren; - const TType& type = node->getType(); - bool roundFloat = canRoundFloat(type); - - if (roundFloat) { - switch (op) { - // Math operators that can result in a float may need to apply rounding to the return - // value. Note that in the case of assignment, the rounding is applied to its return - // value here, not the value being assigned. - case EOpAssign: - case EOpAdd: - case EOpSub: - case EOpMul: - case EOpDiv: - case EOpVectorTimesScalar: - case EOpVectorTimesMatrix: - case EOpMatrixTimesVector: - case EOpMatrixTimesScalar: - case EOpMatrixTimesMatrix: - { - TIntermNode *parent = getParentNode(); - if (!parentUsesResult(parent, node)) + const TType &type = node->getType(); + bool roundFloat = canRoundFloat(type); + + if (roundFloat) + { + switch (op) + { + // Math operators that can result in a float may need to apply rounding to the return + // value. Note that in the case of assignment, the rounding is applied to its return + // value here, not the value being assigned. + case EOpAssign: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: { + TIntermNode *parent = getParentNode(); + if (!ParentUsesResult(parent, node) || + ParentConstructorTakesCareOfRounding(parent, node)) + { + break; + } + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); break; } - TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); - break; - } - // Compound assignment cases need to replace the operator with a function call. - case EOpAddAssign: - { - mEmulateCompoundAdd.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "add"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; - } - case EOpSubAssign: - { - mEmulateCompoundSub.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "sub"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; - } - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - { - mEmulateCompoundMul.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "mul"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; - } - case EOpDivAssign: - { - mEmulateCompoundDiv.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "div"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; - } - default: - // The rest of the binary operations should not need precision emulation. - break; + // Compound assignment cases need to replace the operator with a function call. + case EOpAddAssign: + { + mEmulateCompoundAdd.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "add"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpSubAssign: + { + mEmulateCompoundSub.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "sub"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + { + mEmulateCompoundMul.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "mul"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpDivAssign: + { + mEmulateCompoundDiv.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "div"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + default: + // The rest of the binary operations should not need precision emulation. + break; } } return visitChildren; } +bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + // Variable or interface block declaration. + if (visit == PreVisit) + { + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + return true; +} + +bool EmulatePrecision::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + return false; +} + +bool EmulatePrecision::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) +{ + return false; +} + bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) { - bool visitChildren = true; + if (visit != PreVisit) + return true; switch (node->getOp()) { - case EOpSequence: - case EOpConstructStruct: - case EOpFunction: - break; - case EOpPrototype: - visitChildren = false; - break; - case EOpParameters: - visitChildren = false; - break; - case EOpInvariantDeclaration: - visitChildren = false; - break; - case EOpDeclaration: - // Variable declaration. - if (visit == PreVisit) - { - mDeclaringVariables = true; - } - else if (visit == InVisit) - { - mDeclaringVariables = true; - } - else - { - mDeclaringVariables = false; - } - break; - case EOpFunctionCall: - { - // Function call. - if (visit == PreVisit) - { - // User-defined function return values are not rounded, this relies on that - // calculations producing the value were rounded. + case EOpCallInternalRawFunction: + case EOpCallFunctionInAST: + // User-defined function return values are not rounded. The calculations that produced + // the value inside the function definition should have been rounded. + break; + case EOpConstruct: + if (node->getBasicType() == EbtStruct) + { + break; + } + default: TIntermNode *parent = getParentNode(); - if (canRoundFloat(node->getType()) && !isInFunctionMap(node) && - parentUsesResult(parent, node)) + if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && + !ParentConstructorTakesCareOfRounding(parent, node)) { TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); } - } - break; - } - default: - TIntermNode *parent = getParentNode(); - if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node)) - { - TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); - } - break; + break; } - return visitChildren; + return true; } bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) { switch (node->getOp()) { - case EOpNegative: - case EOpVectorLogicalNot: - case EOpLogicalNot: - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - break; - default: - if (canRoundFloat(node->getType()) && visit == PreVisit) - { - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); - } - break; + case EOpNegative: + case EOpLogicalNot: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpLogicalNotComponentWise: + break; + default: + if (canRoundFloat(node->getType()) && visit == PreVisit) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); + } + break; } return true; } -void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage) { - // Other languages not yet supported - ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || - IsGLSL130OrNewer(outputLanguage) || - outputLanguage == SH_ESSL_OUTPUT); - writeCommonPrecisionEmulationHelpers(sink, outputLanguage); + std::unique_ptr roundingHelperWriter( + RoundingHelperWriter::createHelperWriter(outputLanguage)); + + roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion); EmulationSet::const_iterator it; for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "+", "add"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add"); for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "-", "sub"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub"); for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "/", "div"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div"); for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "*", "mul"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul"); +} + +// static +bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage) +{ + switch (outputLanguage) + { + case SH_HLSL_4_1_OUTPUT: + case SH_ESSL_OUTPUT: + return true; + default: + // Other languages not yet supported + return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || + sh::IsGLSL130OrNewer(outputLanguage)); + } } +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h index 08177b3414..8044465410 100644 --- a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h @@ -7,34 +7,43 @@ #ifndef COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ #define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ +#include "GLSLANG/ShaderLang.h" #include "common/angleutils.h" #include "compiler/translator/Compiler.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/IntermNode.h" -#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/IntermTraverse.h" // This class gathers all compound assignments from the AST and can then write // the functions required for their precision emulation. This way there is no // need to write a huge number of variations of the emulated compound assignment // to every translated shader with emulation enabled. +namespace sh +{ + class EmulatePrecision : public TLValueTrackingTraverser { public: - EmulatePrecision(const TSymbolTable &symbolTable, int shaderVersion); + EmulatePrecision(TSymbolTable *symbolTable, int shaderVersion); 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; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + + void writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage); - void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage); + static bool SupportedInLanguage(const ShShaderOutput outputLanguage); private: struct TypePair { - TypePair(const char *l, const char *r) - : lType(l), rType(r) { } + TypePair(const char *l, const char *r) : lType(l), rType(r) {} const char *lType; const char *rType; @@ -42,7 +51,7 @@ class EmulatePrecision : public TLValueTrackingTraverser struct TypePairComparator { - bool operator() (const TypePair& l, const TypePair& r) const + bool operator()(const TypePair &l, const TypePair &r) const { if (l.lType == r.lType) return l.rType < r.rType; @@ -59,4 +68,6 @@ class EmulatePrecision : public TLValueTrackingTraverser bool mDeclaringVariables; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp b/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp new file mode 100644 index 0000000000..f17dd73657 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp @@ -0,0 +1,153 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of the integer pow expressions HLSL bug workaround. +// See header for more info. + +#include "compiler/translator/ExpandIntegerPowExpressions.h" + +#include +#include + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, TSymbolTable *symbolTable); + + private: + Traverser(TSymbolTable *symbolTable); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root, TSymbolTable *symbolTable) +{ + Traverser traverser(symbolTable); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable) +{ +} + +void Traverser::nextIteration() +{ + mFound = false; + nextTemporaryId(); +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Test 0: skip non-pow operators. + if (node->getOp() != EOpPow) + { + return true; + } + + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 2u); + const TIntermConstantUnion *constantNode = sequence->at(1)->getAsConstantUnion(); + + // Test 1: check for a single constant. + if (!constantNode || constantNode->getNominalSize() != 1) + { + return true; + } + + const TConstantUnion *constant = constantNode->getUnionArrayPointer(); + + TConstantUnion asFloat; + asFloat.cast(EbtFloat, *constant); + + float value = asFloat.getFConst(); + + // Test 2: value is in the problematic range. + if (value < -5.0f || value > 9.0f) + { + return true; + } + + // Test 3: value is integer or pretty close to an integer. + float absval = std::abs(value); + float frac = absval - std::round(absval); + if (frac > 0.0001f) + { + return true; + } + + // Test 4: skip -1, 0, and 1 + int exponent = static_cast(value); + int n = std::abs(exponent); + if (n < 2) + { + return true; + } + + // Potential problem case detected, apply workaround. + nextTemporaryId(); + + TIntermTyped *lhs = sequence->at(0)->getAsTyped(); + ASSERT(lhs); + + TIntermDeclaration *init = createTempInitDeclaration(lhs); + TIntermTyped *current = createTempSymbol(lhs->getType()); + + insertStatementInParentBlock(init); + + // Create a chain of n-1 multiples. + for (int i = 1; i < n; ++i) + { + TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType())); + mul->setLine(node->getLine()); + current = mul; + } + + // For negative pow, compute the reciprocal of the positive pow. + if (exponent < 0) + { + TConstantUnion *oneVal = new TConstantUnion(); + oneVal->setFConst(1.0f); + TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType()); + TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current); + current = div; + } + + queueReplacement(current, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable) +{ + Traverser::Apply(root, symbolTable); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.h b/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.h new file mode 100644 index 0000000000..0074e5d663 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ExpandIntegerPowExpressions.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2016 The ANGLE Project 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 mutating tree traversal works around a bug in the HLSL compiler optimizer with "pow" that +// manifests under the following conditions: +// +// - If pow() has a literal exponent value +// - ... and this value is integer or within 10e-6 of an integer +// - ... and it is in {-4, -3, -2, 2, 3, 4, 5, 6, 7, 8} +// +// The workaround is to replace the pow with a series of multiplies. +// See http://anglebug.com/851 + +#ifndef COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ +#define COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.cpp b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.cpp new file mode 100644 index 0000000000..3f910b9050 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.cpp @@ -0,0 +1,96 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ExtensionBehavior.cpp: Extension name enumeration and data structures for storing extension +// behavior. + +#include "compiler/translator/ExtensionBehavior.h" + +#include "common/debug.h" + +#include + +#define LIST_EXTENSIONS(OP) \ + OP(ARB_texture_rectangle) \ + OP(ARM_shader_framebuffer_fetch) \ + OP(EXT_blend_func_extended) \ + OP(EXT_draw_buffers) \ + OP(EXT_frag_depth) \ + OP(EXT_geometry_shader) \ + OP(EXT_shader_framebuffer_fetch) \ + OP(EXT_shader_texture_lod) \ + OP(EXT_YUV_target) \ + OP(NV_EGL_stream_consumer_external) \ + OP(NV_shader_framebuffer_fetch) \ + OP(OES_EGL_image_external) \ + OP(OES_EGL_image_external_essl3) \ + OP(OES_geometry_shader) \ + OP(OES_standard_derivatives) \ + OP(OVR_multiview) + +namespace sh +{ + +#define RETURN_EXTENSION_NAME_CASE(ext) \ + case TExtension::ext: \ + return "GL_" #ext; + +const char *GetExtensionNameString(TExtension extension) +{ + switch (extension) + { + LIST_EXTENSIONS(RETURN_EXTENSION_NAME_CASE) + default: + UNREACHABLE(); + return ""; + } +} + +#define RETURN_EXTENSION_IF_NAME_MATCHES(ext) \ + if (strcmp(extWithoutGLPrefix, #ext) == 0) \ + { \ + return TExtension::ext; \ + } + +TExtension GetExtensionByName(const char *extension) +{ + // If first characters of the extension don't equal "GL_", early out. + if (strncmp(extension, "GL_", 3) != 0) + { + return TExtension::UNDEFINED; + } + const char *extWithoutGLPrefix = extension + 3; + + LIST_EXTENSIONS(RETURN_EXTENSION_IF_NAME_MATCHES) + + return TExtension::UNDEFINED; +} + +const char *GetBehaviorString(TBehavior b) +{ + switch (b) + { + case EBhRequire: + return "require"; + case EBhEnable: + return "enable"; + case EBhWarn: + return "warn"; + case EBhDisable: + return "disable"; + default: + return nullptr; + } +} + +bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension) +{ + ASSERT(extension != TExtension::UNDEFINED); + auto iter = extBehavior.find(extension); + return iter != extBehavior.end() && + (iter->second == EBhEnable || iter->second == EBhRequire || iter->second == EBhWarn); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h index 782c1c9217..09cc03f10f 100644 --- a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h @@ -3,41 +3,58 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// ExtensionBehavior.h: Extension name enumeration and data structures for storing extension +// behavior. #ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ #define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ #include -#include -typedef enum +namespace sh +{ + +enum class TExtension +{ + UNDEFINED, // Special value used to indicate no extension. + + ARB_texture_rectangle, + ARM_shader_framebuffer_fetch, + EXT_blend_func_extended, + EXT_draw_buffers, + EXT_frag_depth, + EXT_geometry_shader, + EXT_shader_framebuffer_fetch, + EXT_shader_texture_lod, + EXT_YUV_target, + NV_EGL_stream_consumer_external, + NV_shader_framebuffer_fetch, + OES_EGL_image_external, + OES_EGL_image_external_essl3, + OES_geometry_shader, + OES_standard_derivatives, + OVR_multiview +}; + +enum TBehavior { EBhRequire, EBhEnable, EBhWarn, EBhDisable, EBhUndefined -} TBehavior; +}; -inline const char* getBehaviorString(TBehavior b) -{ - switch(b) - { - case EBhRequire: return "require"; - case EBhEnable: return "enable"; - case EBhWarn: return "warn"; - case EBhDisable: return "disable"; - default: return NULL; - } -} - -// 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); -} +const char *GetExtensionNameString(TExtension extension); +TExtension GetExtensionByName(const char *extension); + +const char *GetBehaviorString(TBehavior b); + +// Mapping between extension id and behavior. +typedef std::map TExtensionBehavior; + +bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension); + +} // namespace sh -#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ +#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 index d7f45f7eef..5b5dc580e9 100644 --- a/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.cpp @@ -10,6 +10,9 @@ #include "compiler/translator/VersionGLSL.h" +namespace sh +{ + TExtensionGLSL::TExtensionGLSL(ShShaderOutput output) : TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output)) { @@ -98,3 +101,5 @@ void TExtensionGLSL::checkOperator(TIntermOperator *node) break; } } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h index 6bb84d612d..a1b9cb2225 100644 --- a/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionGLSL.h @@ -12,7 +12,10 @@ #include #include -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ // Traverses the intermediate tree to determine which GLSL extensions are required // to support the shader. @@ -36,4 +39,6 @@ class TExtensionGLSL : public TIntermTraverser std::set mRequiredExtensions; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/FindMain.cpp b/src/3rdparty/angle/src/compiler/translator/FindMain.cpp new file mode 100644 index 0000000000..7417fbac8a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FindMain.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FindMain.cpp: Find the main() function definition in a given AST. + +#include "compiler/translator/FindMain.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +TIntermFunctionDefinition *FindMain(TIntermBlock *root) +{ + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition(); + if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain()) + { + return nodeFunction; + } + } + return nullptr; +} + +TIntermBlock *FindMainBody(TIntermBlock *root) +{ + TIntermFunctionDefinition *main = FindMain(root); + ASSERT(main != nullptr); + TIntermBlock *mainBody = main->getBody(); + ASSERT(mainBody != nullptr); + return mainBody; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/FindMain.h b/src/3rdparty/angle/src/compiler/translator/FindMain.h new file mode 100644 index 0000000000..bf2c45d871 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FindMain.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// FindMain.h: Adds functions to get the main function definition and its body. + +#ifndef COMPILER_TRANSLATOR_FINDMAIN_H_ +#define COMPILER_TRANSLATOR_FINDMAIN_H_ + +namespace sh +{ + +class TIntermBlock; +class TIntermFunctionDefinition; + +TIntermFunctionDefinition *FindMain(TIntermBlock *root); +TIntermBlock *FindMainBody(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_FINDMAIN_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.cpp b/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.cpp new file mode 100644 index 0000000000..a2a10f128d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.cpp @@ -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. +// +// FindSymbol.cpp: +// Utility for finding a symbol node inside an AST tree. + +#include "compiler/translator/FindSymbolNode.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SymbolFinder : public TIntermTraverser +{ + public: + SymbolFinder(const TString &symbolName, TBasicType basicType) + : TIntermTraverser(true, false, false), + mSymbolName(symbolName), + mNodeFound(nullptr), + mBasicType(basicType) + { + } + + void visitSymbol(TIntermSymbol *node) + { + if (node->getBasicType() == mBasicType && node->getSymbol() == mSymbolName) + { + mNodeFound = node; + } + } + + bool isFound() const { return mNodeFound != nullptr; } + const TIntermSymbol *getNode() const { return mNodeFound; } + + private: + TString mSymbolName; + TIntermSymbol *mNodeFound; + TBasicType mBasicType; +}; + +} // anonymous namespace + +const TIntermSymbol *FindSymbolNode(TIntermNode *root, + const TString &symbolName, + TBasicType basicType) +{ + SymbolFinder finder(symbolName, basicType); + root->traverse(&finder); + return finder.getNode(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.h b/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.h new file mode 100644 index 0000000000..08dfb9a222 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/FindSymbolNode.h @@ -0,0 +1,27 @@ +// +// 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. +// +// FindSymbolNode.h: +// Utility for finding a symbol node inside an AST tree. + +#ifndef COMPILER_TRANSLATOR_FIND_SYMBOL_H_ +#define COMPILER_TRANSLATOR_FIND_SYMBOL_H_ + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" + +namespace sh +{ + +class TIntermNode; +class TIntermSymbol; + +const TIntermSymbol *FindSymbolNode(TIntermNode *root, + const TString &symbolName, + TBasicType basicType); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_FIND_SYMBOL_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp index a751b768b7..fba837f55c 100644 --- a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.cpp @@ -3,75 +3,73 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// FlagStd140Structs.cpp: Find structs in std140 blocks, where the padding added in the translator +// conflicts with the "natural" unpadded type. #include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/IntermTraverse.h" + namespace sh { -bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode) +namespace { - if (binaryNode->getRight()->getBasicType() == EbtStruct) - { - switch (binaryNode->getOp()) - { - case EOpIndexDirectInterfaceBlock: - case EOpIndexDirectStruct: - if (isInStd140InterfaceBlock(binaryNode->getLeft())) - { - mFlaggedNodes.push_back(binaryNode); - } - break; - - default: break; - } - return false; - } - if (binaryNode->getOp() == EOpIndexDirectStruct) - { - return false; - } +class FlagStd140StructsTraverser : public TIntermTraverser +{ + public: + FlagStd140StructsTraverser() : TIntermTraverser(true, false, false) {} - return visit == PreVisit; -} + const std::vector getMappedStructs() const { return mMappedStructs; } + + protected: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + + private: + void mapBlockStructMembers(TIntermSymbol *blockDeclarator, TInterfaceBlock *block); + + std::vector mMappedStructs; +}; -void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol) +void FlagStd140StructsTraverser::mapBlockStructMembers(TIntermSymbol *blockDeclarator, + TInterfaceBlock *block) { - if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct) + for (auto *field : block->fields()) { - mFlaggedNodes.push_back(symbol); + if (field->type()->getBasicType() == EbtStruct) + { + MappedStruct mappedStruct; + mappedStruct.blockDeclarator = blockDeclarator; + mappedStruct.field = field; + mMappedStructs.push_back(mappedStruct); + } } } -bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const +bool FlagStd140StructsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) { - TIntermBinary *binaryNode = node->getAsBinaryNode(); - - if (binaryNode) - { - return isInStd140InterfaceBlock(binaryNode->getLeft()); - } - - const TType &type = node->getType(); - - // determine if we are in the standard layout - const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); - if (interfaceBlock) + TIntermTyped *declarator = node->getSequence()->back()->getAsTyped(); + if (declarator->getBasicType() == EbtInterfaceBlock) { - return (interfaceBlock->blockStorage() == EbsStd140); + TInterfaceBlock *block = declarator->getType().getInterfaceBlock(); + if (block->blockStorage() == EbsStd140) + { + mapBlockStructMembers(declarator->getAsSymbolNode(), block); + } } - return false; } -std::vector FlagStd140ValueStructs(TIntermNode *node) +} // anonymous namespace + +std::vector FlagStd140Structs(TIntermNode *node) { - FlagStd140Structs flaggingTraversal; + FlagStd140StructsTraverser flaggingTraversal; node->traverse(&flaggingTraversal); - return flaggingTraversal.getFlaggedNodes(); + return flaggingTraversal.getMappedStructs(); } -} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h index cfcd775af7..f548d8b6ed 100644 --- a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h @@ -3,41 +3,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// FlagStd140Structs.h: Find structs in std140 blocks, where the padding added in the translator +// conflicts with the "natural" unpadded type. #ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ #define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ -#include "compiler/translator/IntermNode.h" +#include namespace sh { -// This class finds references to nested structs of std140 blocks that access -// the nested struct "by value", where the padding added in the translator -// conflicts with the "natural" unpadded type. -class FlagStd140Structs : public TIntermTraverser -{ - public: - - FlagStd140Structs() - : TIntermTraverser(true, false, false) - { - } - - const std::vector getFlaggedNodes() const { return mFlaggedNodes; } +class TField; +class TIntermNode; +class TIntermSymbol; - protected: - bool visitBinary(Visit visit, TIntermBinary *binaryNode) override; - void visitSymbol(TIntermSymbol *symbol) override; - - private: - bool isInStd140InterfaceBlock(TIntermTyped *node) const; - - std::vector mFlaggedNodes; +struct MappedStruct +{ + TIntermSymbol *blockDeclarator; + TField *field; }; -std::vector FlagStd140ValueStructs(TIntermNode *node); - +std::vector FlagStd140Structs(TIntermNode *node); } -#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ +#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp deleted file mode 100644 index 4cc1c26a13..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/ForLoopUnroll.h" - -#include "compiler/translator/ValidateLimitations.h" -#include "angle_gl.h" - -bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node) -{ - if (mUnrollCondition != kSamplerArrayIndex) - return true; - - // If a sampler array index is also the loop index, - // 1) if the index type is integer, mark the loop for unrolling; - // 2) if the index type if float, set a flag to later fail compile. - switch (node->getOp()) - { - case EOpIndexIndirect: - if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode()) - { - TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode(); - if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty()) - { - mVisitSamplerArrayIndexNodeInsideLoop = true; - node->getRight()->traverse(this); - mVisitSamplerArrayIndexNodeInsideLoop = false; - // We have already visited all the children. - return false; - } - } - break; - default: - break; - } - return true; -} - -bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node) -{ - 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 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) - node->setUnrollFlag(true); - } - - TIntermNode *body = node->getBody(); - if (body != nullptr) - { - 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; -} - -void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol) -{ - if (!mVisitSamplerArrayIndexNodeInsideLoop) - return; - TIntermLoop *loop = mLoopStack.findLoop(symbol); - if (loop) - { - switch (symbol->getBasicType()) - { - case EbtFloat: - mSamplerArrayIndexIsFloatLoopIndex = true; - break; - case EbtInt: - loop->setUnrollFlag(true); - break; - default: - UNREACHABLE(); - } - } -} diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h deleted file mode 100644 index 9c49ecad33..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ -#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ - -#include "compiler/translator/LoopInfo.h" - -// This class detects for-loops that needs to be unrolled. -// Currently we support two unroll conditions: -// 1) kForLoopWithIntegerIndex: unroll if the index type is integer. -// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index -// is also the loop integer index, and reject and fail a compile -// where a sampler array index is also the loop float index. -class ForLoopUnrollMarker : public TIntermTraverser -{ - public: - enum UnrollCondition - { - kIntegerIndex, - kSamplerArrayIndex - }; - - ForLoopUnrollMarker(UnrollCondition condition, bool hasRunLoopValidation) - : TIntermTraverser(true, false, false), - mUnrollCondition(condition), - mSamplerArrayIndexIsFloatLoopIndex(false), - mVisitSamplerArrayIndexNodeInsideLoop(false), - mHasRunLoopValidation(hasRunLoopValidation) - { - } - - bool visitBinary(Visit, TIntermBinary *node) override; - bool visitLoop(Visit, TIntermLoop *node) override; - void visitSymbol(TIntermSymbol *node) override; - - bool samplerArrayIndexIsFloatLoopIndex() const - { - return mSamplerArrayIndexIsFloatLoopIndex; - } - - private: - UnrollCondition mUnrollCondition; - TLoopStack mLoopStack; - bool mSamplerArrayIndexIsFloatLoopIndex; - bool mVisitSamplerArrayIndexNodeInsideLoop; - bool mHasRunLoopValidation; -}; - -#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/HashNames.cpp b/src/3rdparty/angle/src/compiler/translator/HashNames.cpp new file mode 100644 index 0000000000..6bc90faf94 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/HashNames.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2017 The ANGLE Project 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/HashNames.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ + +// GLSL ES 3.00.6 section 3.9: the maximum length of an identifier is 1024 characters. +static const unsigned int kESSLMaxIdentifierLength = 1024u; + +static const char *kHashedNamePrefix = "webgl_"; + +// Can't prefix with just _ because then we might introduce a double underscore, which is not safe +// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for +// use by the underlying implementation). u is short for user-defined. +static const char *kUnhashedNamePrefix = "_u"; +static const unsigned int kUnhashedNamePrefixLength = 2u; + +TString HashName(const TString &name, ShHashFunction64 hashFunction) +{ + ASSERT(!name.empty()); + ASSERT(hashFunction); + khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); + TStringStream stream; + stream << kHashedNamePrefix << std::hex << number; + TString hashedName = stream.str(); + return hashedName; +} + +} // anonymous namespace + +TString HashName(const TName &name, ShHashFunction64 hashFunction, NameMap *nameMap) +{ + if (name.getString().empty() || name.isInternal()) + { + return name.getString(); + } + if (hashFunction == nullptr) + { + if (name.getString().length() + kUnhashedNamePrefixLength > kESSLMaxIdentifierLength) + { + // If the identifier length is already close to the limit, we can't prefix it. This is + // not a problem since there are no builtins or ANGLE's internal variables that would + // have as long names and could conflict. + return name.getString(); + } + return kUnhashedNamePrefix + name.getString(); + } + if (nameMap) + { + NameMap::const_iterator it = nameMap->find(name.getString().c_str()); + if (it != nameMap->end()) + return it->second.c_str(); + } + TString hashedName = HashName(name.getString(), hashFunction); + if (nameMap) + { + (*nameMap)[name.getString().c_str()] = hashedName.c_str(); + } + return hashedName; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/HashNames.h b/src/3rdparty/angle/src/compiler/translator/HashNames.h index 09c959f9da..28e861b309 100644 --- a/src/3rdparty/angle/src/compiler/translator/HashNames.h +++ b/src/3rdparty/angle/src/compiler/translator/HashNames.h @@ -9,10 +9,20 @@ #include -#include "compiler/translator/IntermNode.h" +#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/Common.h" -#define HASHED_NAME_PREFIX "webgl_" +namespace sh +{ typedef std::map NameMap; +class TName; + +// Hash user-defined name for GLSL output, with special handling for internal names. +// The nameMap parameter is optional and is used to cache hashed names if set. +TString HashName(const TName &name, ShHashFunction64 hashFunction, NameMap *nameMap); + +} // namespace sh + #endif // COMPILER_TRANSLATOR_HASHNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.cpp new file mode 100644 index 0000000000..40b5e1f1e2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.cpp @@ -0,0 +1,304 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output. +// + +#include "compiler/translator/ImageFunctionHLSL.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +// static +void ImageFunctionHLSL::OutputImageFunctionArgumentList( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction) +{ + if (imageFunction.readonly) + { + out << TextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex"; + } + else + { + out << RWTextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex"; + } + + if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD || + imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) + { + switch (imageFunction.image) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + out << ", int2 p"; + break; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + out << ", int3 p"; + break; + default: + UNREACHABLE(); + } + + if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) + { + switch (imageFunction.image) + { + case EbtImage2D: + case EbtImage3D: + case EbtImageCube: + case EbtImage2DArray: + out << ", float4 data"; + break; + case EbtIImage2D: + case EbtIImage3D: + case EbtIImageCube: + case EbtIImage2DArray: + out << ", int4 data"; + break; + case EbtUImage2D: + case EbtUImage3D: + case EbtUImageCube: + case EbtUImage2DArray: + out << ", uint4 data"; + break; + default: + UNREACHABLE(); + } + } + } +} + +// static +void ImageFunctionHLSL::OutputImageSizeFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImageCube(imageFunction.image)) + { + // "depth" stores either the number of layers in an array texture or 3D depth + out << " uint width; uint height; uint depth;\n" + << " " << imageReference << ".GetDimensions(width, height, depth);\n"; + } + else if (IsImage2D(imageFunction.image)) + { + out << " uint width; uint height;\n" + << " " << imageReference << ".GetDimensions(width, height);\n"; + } + else + UNREACHABLE(); + + if (strcmp(imageFunction.getReturnType(), "int3") == 0) + { + out << " return int3(width, height, depth);\n"; + } + else + { + out << " return int2(width, height);\n"; + } +} + +// static +void ImageFunctionHLSL::OutputImageLoadFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImageCube(imageFunction.image)) + { + out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n"; + } + else if (IsImage2D(imageFunction.image)) + { + out << " return " << imageReference << "[uint2(p.x, p.y)];\n"; + } + else + UNREACHABLE(); +} + +// static +void ImageFunctionHLSL::OutputImageStoreFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image)) + { + out << " " << imageReference << "[p] = data;\n"; + } + else + UNREACHABLE(); +} + +TString ImageFunctionHLSL::ImageFunction::name() const +{ + TString name = "gl_image"; + if (readonly) + { + name += TextureTypeSuffix(image, imageInternalFormat); + } + else + { + name += RWTextureTypeSuffix(image, imageInternalFormat); + } + + switch (method) + { + case Method::SIZE: + name += "Size"; + break; + case Method::LOAD: + name += "Load"; + break; + case Method::STORE: + name += "Store"; + break; + default: + UNREACHABLE(); + } + + return name; +} + +const char *ImageFunctionHLSL::ImageFunction::getReturnType() const +{ + if (method == ImageFunction::Method::SIZE) + { + switch (image) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return "int2"; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return "int3"; + default: + UNREACHABLE(); + } + } + else if (method == ImageFunction::Method::LOAD) + { + switch (image) + { + case EbtImage2D: + case EbtImage3D: + case EbtImageCube: + case EbtImage2DArray: + return "float4"; + case EbtIImage2D: + case EbtIImage3D: + case EbtIImageCube: + case EbtIImage2DArray: + return "int4"; + case EbtUImage2D: + case EbtUImage3D: + case EbtUImageCube: + case EbtUImage2DArray: + return "uint4"; + default: + UNREACHABLE(); + } + } + else if (method == ImageFunction::Method::STORE) + { + return "void"; + } + else + { + UNREACHABLE(); + } + return ""; +} + +bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const +{ + return std::tie(image, imageInternalFormat, readonly, method) < + std::tie(rhs.image, rhs.imageInternalFormat, rhs.readonly, rhs.method); +} + +TString ImageFunctionHLSL::useImageFunction(const TString &name, + const TBasicType &type, + TLayoutImageInternalFormat imageInternalFormat, + bool readonly) +{ + ASSERT(IsImage(type)); + ImageFunction imageFunction; + imageFunction.image = type; + imageFunction.imageInternalFormat = imageInternalFormat; + imageFunction.readonly = readonly; + + if (name == "imageSize") + { + imageFunction.method = ImageFunction::Method::SIZE; + } + else if (name == "imageLoad") + { + imageFunction.method = ImageFunction::Method::LOAD; + } + else if (name == "imageStore") + { + imageFunction.method = ImageFunction::Method::STORE; + } + else + UNREACHABLE(); + + mUsesImage.insert(imageFunction); + return imageFunction.name(); +} + +void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out) +{ + for (const ImageFunction &imageFunction : mUsesImage) + { + // Function header + out << imageFunction.getReturnType() << " " << imageFunction.name() << "("; + + OutputImageFunctionArgumentList(out, imageFunction); + + out << ")\n" + "{\n"; + + TString imageReference("tex"); + + if (imageFunction.method == ImageFunction::Method::SIZE) + { + OutputImageSizeFunctionBody(out, imageFunction, imageReference); + } + else if (imageFunction.method == ImageFunction::Method::LOAD) + { + OutputImageLoadFunctionBody(out, imageFunction, imageReference); + } + else + { + OutputImageStoreFunctionBody(out, imageFunction, imageReference); + } + + out << "}\n" + "\n"; + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.h b/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.h new file mode 100644 index 0000000000..9db17a6bbf --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ImageFunctionHLSL.h @@ -0,0 +1,76 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output. +// + +#ifndef COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ + +#include + +#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/Types.h" + +namespace sh +{ + +class ImageFunctionHLSL final : angle::NonCopyable +{ + public: + // Returns the name of the image function implementation to caller. + // The name that's passed in is the name of the GLSL image function that it should implement. + TString useImageFunction(const TString &name, + const TBasicType &type, + TLayoutImageInternalFormat imageInternalFormat, + bool readonly); + + void imageFunctionHeader(TInfoSinkBase &out); + + private: + struct ImageFunction + { + // See ESSL 3.10.4 section 8.12 for reference about what the different methods below do. + enum class Method + { + SIZE, + LOAD, + STORE + }; + + TString name() const; + + bool operator<(const ImageFunction &rhs) const; + + const char *getReturnType() const; + + TBasicType image; + TLayoutImageInternalFormat imageInternalFormat; + bool readonly; + Method method; + }; + + static void OutputImageFunctionArgumentList( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction); + static void OutputImageSizeFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference); + static void OutputImageLoadFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference); + static void OutputImageStoreFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const TString &imageReference); + using ImageFunctionSet = std::set; + ImageFunctionSet mUsesImage; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InfoSink.cpp b/src/3rdparty/angle/src/compiler/translator/InfoSink.cpp index cd59658ff7..db26aa67e8 100644 --- a/src/3rdparty/angle/src/compiler/translator/InfoSink.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InfoSink.cpp @@ -6,32 +6,27 @@ #include "compiler/translator/InfoSink.h" -void TInfoSinkBase::prefix(TPrefixType p) { - switch(p) { - case EPrefixNone: - break; - case EPrefixWarning: +namespace sh +{ + +void TInfoSinkBase::prefix(Severity severity) +{ + switch (severity) + { + case SH_WARNING: sink.append("WARNING: "); break; - case EPrefixError: + case SH_ERROR: sink.append("ERROR: "); break; - case EPrefixInternalError: - sink.append("INTERNAL ERROR: "); - break; - case EPrefixUnimplemented: - sink.append("UNIMPLEMENTED: "); - break; - case EPrefixNote: - sink.append("NOTE: "); - break; default: sink.append("UNKOWN ERROR: "); break; } } -void TInfoSinkBase::location(int file, int line) { +void TInfoSinkBase::location(int file, int line) +{ TPersistStringStream stream; if (line) stream << file << ":" << line; @@ -42,13 +37,4 @@ void TInfoSinkBase::location(int file, int line) { sink.append(stream.str()); } -void TInfoSinkBase::location(const TSourceLoc& loc) { - location(loc.first_file, loc.first_line); -} - -void TInfoSinkBase::message(TPrefixType p, const TSourceLoc& loc, const char* m) { - prefix(p); - location(loc); - sink.append(m); - sink.append("\n"); -} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/InfoSink.h b/src/3rdparty/angle/src/compiler/translator/InfoSink.h index f47fafa8ee..2705f48d59 100644 --- a/src/3rdparty/angle/src/compiler/translator/InfoSink.h +++ b/src/3rdparty/angle/src/compiler/translator/InfoSink.h @@ -10,38 +10,32 @@ #include #include #include "compiler/translator/Common.h" +#include "compiler/translator/Severity.h" + +namespace sh +{ // Returns the fractional part of the given floating-point number. -inline float fractionalPart(float f) { - float intPart = 0.0f; - return modff(f, &intPart); +inline float fractionalPart(float f) +{ + float intPart = 0.0f; + return modff(f, &intPart); } -// -// TPrefixType is used to centralize how info log messages start. -// See below. -// -enum TPrefixType { - EPrefixNone, - EPrefixWarning, - EPrefixError, - EPrefixInternalError, - EPrefixUnimplemented, - EPrefixNote -}; - // // Encapsulate info logs for all objects that have them. // // The methods are a general set of tools for getting a variety of // messages and types inserted into the log. // -class TInfoSinkBase { -public: +class TInfoSinkBase +{ + public: TInfoSinkBase() {} template - TInfoSinkBase& operator<<(const T& t) { + TInfoSinkBase &operator<<(const T &t) + { TPersistStringStream stream; stream << t; sink.append(stream.str()); @@ -49,33 +43,41 @@ public: } // Override << operator for specific types. It is faster to append strings // and characters directly to the sink. - TInfoSinkBase& operator<<(char c) { + TInfoSinkBase &operator<<(char c) + { sink.append(1, c); return *this; } - TInfoSinkBase& operator<<(const char* str) { + TInfoSinkBase &operator<<(const char *str) + { sink.append(str); return *this; } - TInfoSinkBase& operator<<(const TPersistString& str) { + TInfoSinkBase &operator<<(const TPersistString &str) + { sink.append(str); return *this; } - TInfoSinkBase& operator<<(const TString& str) { + TInfoSinkBase &operator<<(const TString &str) + { sink.append(str.c_str()); return *this; } // Make sure floats are written with correct precision. - TInfoSinkBase& operator<<(float f) { + TInfoSinkBase &operator<<(float f) + { // Make sure that at least one decimal point is written. If a number // does not have a fractional part, the default precision format does // not write the decimal portion which gets interpreted as integer by // the compiler. TPersistStringStream stream; - if (fractionalPart(f) == 0.0f) { + if (fractionalPart(f) == 0.0f) + { stream.precision(1); stream << std::showpoint << std::fixed << f; - } else { + } + else + { stream.unsetf(std::ios::fixed); stream.unsetf(std::ios::scientific); stream.precision(8); @@ -85,8 +87,9 @@ public: return *this; } // Write boolean values as their names instead of integral value. - TInfoSinkBase& operator<<(bool b) { - const char* str = b ? "true" : "false"; + TInfoSinkBase &operator<<(bool b) + { + const char *str = b ? "true" : "false"; sink.append(str); return *this; } @@ -94,23 +97,24 @@ public: void erase() { sink.clear(); } int size() { return static_cast(sink.size()); } - const TPersistString& str() const { return sink; } - const char* c_str() const { return sink.c_str(); } + const TPersistString &str() const { return sink; } + const char *c_str() const { return sink.c_str(); } - void prefix(TPrefixType p); + void prefix(Severity severity); void location(int file, int line); - void location(const TSourceLoc& loc); - void message(TPrefixType p, const TSourceLoc& loc, const char* m); -private: + private: TPersistString sink; }; -class TInfoSink { -public: +class TInfoSink +{ + public: TInfoSinkBase info; TInfoSinkBase debug; TInfoSinkBase obj; }; -#endif // COMPILER_TRANSLATOR_INFOSINK_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INFOSINK_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp index 2f51aada7f..6f8baee96b 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp @@ -6,7 +6,7 @@ // // Create symbols that declare built-in definitions, add built-ins that -// cannot be expressed in the files, and establish mappings between +// cannot be expressed in the files, and establish mappings between // built-in functions and operators. // @@ -16,18 +16,25 @@ #include "compiler/translator/IntermNode.h" #include "angle_gl.h" -void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) +namespace sh { - 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); + +void InsertBuiltInFunctions(sh::GLenum type, + ShShaderSpec spec, + const ShBuiltInResources &resources, + TSymbolTable &symbolTable) +{ + const TType *voidType = TCache::getType(EbtVoid); + 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); @@ -35,113 +42,117 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR // // Angle and Trigonometric Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRadians, genType, "radians", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDegrees, genType, "degrees", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSin, genType, "sin", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCos, genType, "cos", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpTan, genType, "tan", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAsin, genType, "asin", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAcos, genType, "acos", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSinh, genType, "sinh", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpCosh, genType, "cosh", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTanh, genType, "tanh", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAsinh, genType, "asinh", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAcosh, genType, "acosh", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAtanh, genType, "atanh", genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpRadians, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpDegrees, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSin, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpCos, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpTan, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAsin, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAcos, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAtan, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAtan, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpSinh, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpCosh, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTanh, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpAsinh, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpAcosh, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpAtanh, genType, genType); // // Exponential Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpPow, genType, "pow", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp, genType, "exp", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog, genType, "log", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp2, genType, "exp2", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog2, genType, "log2", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSqrt, genType, "sqrt", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpInverseSqrt, genType, "inversesqrt", genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpPow, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpExp, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLog, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpExp2, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLog2, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSqrt, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpInverseSqrt, genType, genType); // // Common Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAbs, genType, "abs", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAbs, genIType, "abs", genIType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSign, genType, "sign", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSign, genIType, "sign", genIType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFloor, genType, "floor", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTrunc, genType, "trunc", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRound, genType, "round", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRoundEven, genType, "roundEven", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCeil, genType, "ceil", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFract, genType, "fract", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, genIType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, int1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, genUType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, uint1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, genIType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, int1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, genUType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, uint1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, genType, genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, int1, int1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, genIType, genIType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, uint1, uint1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, genUType, genUType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genType); - symbolTable.insertBuiltIn(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); - - 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); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float3, "modf", float3, outFloat3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float4, "modf", float4, outFloat4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsNan, genBType, "isnan", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsInf, genBType, "isinf", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToInt, genIType, "floatBitsToInt", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToUint, genUType, "floatBitsToUint", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, "intBitsToFloat", genIType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, "uintBitsToFloat", genUType); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, "packSnorm2x16", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, "packUnorm2x16", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, "packHalf2x16", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackSnorm2x16, float2, "unpackSnorm2x16", uint1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, "unpackUnorm2x16", uint1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, "unpackHalf2x16", uint1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAbs, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpAbs, genIType, genIType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSign, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpSign, genIType, genIType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpFloor, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTrunc, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpRound, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpRoundEven, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpCeil, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpFract, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMod, genType, genType, float1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMod, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMin, genType, genType, float1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMin, genType, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMin, genIType, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMin, genIType, genIType, int1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMin, genUType, genUType, genUType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMin, genUType, genUType, uint1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMax, genType, genType, float1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMax, genType, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMax, genIType, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMax, genIType, genIType, int1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMax, genUType, genUType, genUType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMax, genUType, genUType, uint1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpClamp, genType, genType, float1, float1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpClamp, genType, genType, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpClamp, genIType, genIType, int1, int1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpClamp, genIType, genIType, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpClamp, genUType, genUType, uint1, uint1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpClamp, genUType, genUType, genUType, genUType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMix, genType, genType, genType, float1); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMix, genType, genType, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMix, genType, genType, genType, genBType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpStep, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpStep, genType, float1, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSmoothStep, genType, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSmoothStep, genType, float1, float1, genType); + + const TType *outGenType = TCache::getType(EbtGenType, EvqOut); + const TType *outGenIType = TCache::getType(EbtGenIType, EvqOut); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpModf, genType, genType, outGenType); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpIsNan, genBType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpIsInf, genBType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpFloatBitsToInt, genIType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpFloatBitsToUint, genUType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, genIType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, genUType); + + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFrexp, genType, genType, outGenIType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpLdexp, genType, genType, genIType); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUnpackSnorm2x16, float2, uint1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, uint1); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, uint1); + + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpPackUnorm4x8, uint1, float4); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpPackSnorm4x8, uint1, float4); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUnpackUnorm4x8, float4, uint1); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUnpackSnorm4x8, float4, uint1); // // Geometric Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLength, float1, "length", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDistance, float1, "distance", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDot, float1, "dot", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCross, float3, "cross", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpNormalize, genType, "normalize", genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFaceForward, genType, "faceforward", genType, genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpReflect, genType, "reflect", genType, genType); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRefract, genType, "refract", genType, genType, float1); - - const TType *mat2 = TCache::getType(EbtFloat, 2, 2); - const TType *mat3 = TCache::getType(EbtFloat, 3, 3); - const TType *mat4 = TCache::getType(EbtFloat, 4, 4); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLength, float1, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpDistance, float1, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpDot, float1, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpCross, float3, float3, float3); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpNormalize, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpFaceforward, genType, genType, genType, + genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpReflect, genType, genType, genType); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpRefract, genType, genType, genType, float1); + + 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); @@ -152,45 +163,45 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR // // Matrix Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat2, "matrixCompMult", mat2, mat2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat3, "matrixCompMult", mat3, mat3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat4, "matrixCompMult", mat4, mat4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x3, "matrixCompMult", mat2x3, mat2x3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x2, "matrixCompMult", mat3x2, mat3x2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x4, "matrixCompMult", mat2x4, mat2x4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x2, "matrixCompMult", mat4x2, mat4x2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x4, "matrixCompMult", mat3x4, mat3x4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x3, "matrixCompMult", mat4x3, mat4x3); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2, "outerProduct", float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3, "outerProduct", float3, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4, "outerProduct", float4, float4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x3, "outerProduct", float3, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x2, "outerProduct", float2, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x4, "outerProduct", float4, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x2, "outerProduct", float2, float4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x4, "outerProduct", float4, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x3, "outerProduct", float3, float4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2, "transpose", mat2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3, "transpose", mat3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4, "transpose", mat4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x3, "transpose", mat3x2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x2, "transpose", mat2x3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x4, "transpose", mat4x2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x2, "transpose", mat2x4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x4, "transpose", mat4x3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x3, "transpose", mat3x4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat2, "inverse", mat2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat3, "inverse", mat3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat4, "inverse", mat4); - - const TType *vec = TCache::getType(EbtVec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMulMatrixComponentWise, mat2, mat2, mat2); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMulMatrixComponentWise, mat3, mat3, mat3); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpMulMatrixComponentWise, mat4, mat4, mat4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat2x3, mat2x3, mat2x3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat3x2, mat3x2, mat3x2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat2x4, mat2x4, mat2x4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat4x2, mat4x2, mat4x2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat3x4, mat3x4, mat3x4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpMulMatrixComponentWise, mat4x3, mat4x3, mat4x3); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat2, float2, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat3, float3, float3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat4, float4, float4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat2x3, float3, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat3x2, float2, float3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat2x4, float4, float2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat4x2, float2, float4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat3x4, float4, float3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpOuterProduct, mat4x3, float3, float4); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat2, mat2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat3, mat3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat4, mat4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat2x3, mat3x2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat3x2, mat2x3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat2x4, mat4x2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat4x2, mat2x4); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat3x4, mat4x3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpTranspose, mat4x3, mat3x4); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpDeterminant, float1, mat2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpDeterminant, float1, mat3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpDeterminant, float1, mat4); + + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpInverse, mat2, mat2); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpInverse, mat3, mat3); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpInverse, mat4, mat4); + + const TType *vec = TCache::getType(EbtVec); const TType *ivec = TCache::getType(EbtIVec); const TType *uvec = TCache::getType(EbtUVec); const TType *bvec = TCache::getType(EbtBVec); @@ -198,31 +209,62 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR // // Vector relational functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThan, bvec, "lessThan", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThan, bvec, "greaterThan", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorEqual, bvec, "equal", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", bvec, bvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", vec, vec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", ivec, ivec); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", uvec, uvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", bvec, bvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAny, bool1, "any", bvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAll, bool1, "all", bvec); - symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorLogicalNot, bvec, "not", bvec); - - const TType *sampler2D = TCache::getType(EbtSampler2D); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLessThanComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLessThanComponentWise, bvec, ivec, ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpLessThanComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLessThanEqualComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLessThanEqualComponentWise, bvec, ivec, ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpLessThanEqualComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpGreaterThanComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpGreaterThanComponentWise, bvec, ivec, ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpGreaterThanComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpGreaterThanEqualComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpGreaterThanEqualComponentWise, bvec, ivec, + ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpGreaterThanEqualComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpEqualComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpEqualComponentWise, bvec, ivec, ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpEqualComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpEqualComponentWise, bvec, bvec, bvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpNotEqualComponentWise, bvec, vec, vec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpNotEqualComponentWise, bvec, ivec, ivec); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpNotEqualComponentWise, bvec, uvec, uvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpNotEqualComponentWise, bvec, bvec, bvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAny, bool1, bvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpAll, bool1, bvec); + symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpLogicalNotComponentWise, bvec, bvec); + + // + // Integer functions + // + const TType *outGenUType = TCache::getType(EbtGenUType, EvqOut); + + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldExtract, genIType, genIType, int1, + int1); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldExtract, genUType, genUType, int1, + int1); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldInsert, genIType, genIType, genIType, + int1, int1); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldInsert, genUType, genUType, genUType, + int1, int1); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldReverse, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldReverse, genUType, genUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitCount, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitCount, genIType, genUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFindLSB, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFindLSB, genIType, genUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFindMSB, genIType, genIType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpFindMSB, genIType, genUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUaddCarry, genUType, genUType, genUType, + outGenUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUsubBorrow, genUType, genUType, genUType, + outGenUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUmulExtended, voidType, genUType, genUType, + outGenUType, outGenUType); + symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpImulExtended, voidType, genIType, genIType, + outGenIType, outGenIType); + + const TType *sampler2D = TCache::getType(EbtSampler2D); const TType *samplerCube = TCache::getType(EbtSamplerCube); // @@ -233,13 +275,15 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4); symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3); - if (resources.OES_EGL_image_external) + if (resources.OES_EGL_image_external || resources.NV_EGL_stream_consumer_external) { const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, + float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, + float4); } if (resources.ARB_texture_rectangle) @@ -247,8 +291,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR const TType *sampler2DRect = TCache::getType(EbtSampler2DRect); symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, + float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, + float4); } if (resources.EXT_shader_texture_lod) @@ -256,49 +302,68 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR /* The *Grad* variants are new to both vertex and fragment shaders; the fragment * shader specific pieces are added separately below. */ - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DGradEXT", sampler2D, float2, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DGradEXT", sampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DProjGradEXT", sampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DProjGradEXT", sampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "textureCubeGradEXT", samplerCube, float3, float3, float3); } if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, + float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, + float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, + float1); if (resources.OES_standard_derivatives) { - symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType); + symbolTable.insertBuiltInOp(ESSL1_BUILTINS, EOpDFdx, + TExtension::OES_standard_derivatives, genType, genType); + symbolTable.insertBuiltInOp(ESSL1_BUILTINS, EOpDFdy, + TExtension::OES_standard_derivatives, genType, genType); + symbolTable.insertBuiltInOp(ESSL1_BUILTINS, EOpFwidth, + TExtension::OES_standard_derivatives, genType, genType); } if (resources.EXT_shader_texture_lod) { - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DLodEXT", sampler2D, float2, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float3, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float4, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeLodEXT", samplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DLodEXT", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DProjLodEXT", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "texture2DProjLodEXT", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, TExtension::EXT_shader_texture_lod, float4, + "textureCubeLodEXT", samplerCube, float3, float1); } } if (type == GL_VERTEX_SHADER) { - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, + float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, + float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, + float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, + float1); } const TType *gvec4 = TCache::getType(EbtGVec4); - const TType *gsampler2D = TCache::getType(EbtGSampler2D); - const TType *gsamplerCube = TCache::getType(EbtGSamplerCube); - const TType *gsampler3D = TCache::getType(EbtGSampler3D); + const TType *gsampler2D = TCache::getType(EbtGSampler2D); + const TType *gsamplerCube = TCache::getType(EbtGSamplerCube); + const TType *gsampler3D = TCache::getType(EbtGSampler3D); const TType *gsampler2DArray = TCache::getType(EbtGSampler2DArray); + const TType *gsampler2DMS = TCache::getType(EbtGSampler2DMS); // // Texture Functions for GLSL ES 3.0 @@ -315,32 +380,91 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1); + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float4); + } + + if (resources.EXT_YUV_target) + { + const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texture", + samplerExternal2DY2YEXT, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "textureProj", + samplerExternal2DY2YEXT, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "textureProj", + samplerExternal2DY2YEXT, float4); + + const TType *yuvCscStandardEXT = TCache::getType(EbtYuvCscStandardEXT); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float3, "rgb_2_yuv", + float3, yuvCscStandardEXT); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float3, "yuv_2_rgb", + float3, yuvCscStandardEXT); + } + if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, + float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1); + + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float4, float1); + } + + if (resources.EXT_YUV_target) + { + const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texture", + samplerExternal2DY2YEXT, float2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, + "textureProj", samplerExternal2DY2YEXT, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, + "textureProj", samplerExternal2DY2YEXT, float4, float1); + } } - const TType *sampler2DShadow = TCache::getType(EbtSampler2DShadow); - const TType *samplerCubeShadow = TCache::getType(EbtSamplerCubeShadow); + 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); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DArrayShadow, float4); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, + float1); if (type == GL_FRAGMENT_SHADER) { - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, + float1); } symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2D, int1); @@ -350,135 +474,398 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2DShadow, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2DMS); + + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerExternalOES, int1); + } + + if (resources.EXT_YUV_target) + { + const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, int2, "textureSize", + samplerExternal2DY2YEXT, int1); + } if (type == GL_FRAGMENT_SHADER) { - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, genType, "dFdx", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, genType, "dFdy", genType); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, genType, "fwidth", genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpDFdx, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpDFdy, genType, genType); + symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpFwidth, genType, genType); } symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, + int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, + int2); if (type == GL_FRAGMENT_SHADER) { - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, + int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, + int2, float1); } symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, + int2); if (type == GL_FRAGMENT_SHADER) { - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, + int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, + int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, + int3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, + float4, int2, float1); } - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, float1, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, + int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, + int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, + float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, + float1, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float4, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler3D, float4, float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, float1); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, float1, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, float1, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, + float1); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, + float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, + float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, + float1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, + float4, float1, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, float3, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, float2, float2); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, float2, float2, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, float3, float3, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, float2, float2, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, float2, float2, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, float4, float2, float2, int2); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, float2, float2); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, float2, float2, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, float2, float2, int2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2); + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texelFetch", samplerExternalOES, int2, + int1); + } + + if (resources.EXT_YUV_target) + { + const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texelFetch", + samplerExternal2DY2YEXT, int2, int1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, + int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, + int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, + int1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, + float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, + float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, + float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, + float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, + float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, + float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, + float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, + float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, + float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, + float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, + float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, + float4, float2, float2, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, + float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, + float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, + float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, + float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, + float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, + float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, + float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, + float4, float2, float2, int2); + + const TType *atomicCounter = TCache::getType(EbtAtomicCounter); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounter", atomicCounter); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounterIncrement", atomicCounter); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounterDecrement", atomicCounter); + + // Insert all atomic memory functions + const TType *int1InOut = TCache::getType(EbtInt, EvqInOut); + const TType *uint1InOut = TCache::getType(EbtUInt, EvqInOut); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicAdd", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicAdd", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicMin", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicMin", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicMax", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicMax", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicAnd", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicAnd", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicOr", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicOr", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicXor", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicXor", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicExchange", uint1InOut, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicExchange", int1InOut, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCompSwap", uint1InOut, uint1, uint1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicCompSwap", int1InOut, int1, int1); + + const TType *gimage2D = TCache::getType(EbtGImage2D); + const TType *gimage3D = TCache::getType(EbtGImage3D); + const TType *gimage2DArray = TCache::getType(EbtGImage2DArray); + const TType *gimageCube = TCache::getType(EbtGImageCube); + + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2D, int2, gvec4); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage3D, int3, gvec4); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2DArray, int3, gvec4); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimageCube, int3, gvec4); + + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2D, int2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage3D, int3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2DArray, int3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimageCube, int3); + + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int2, "imageSize", gimage2D); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage3D); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage2DArray); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int2, "imageSize", gimageCube); + + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpMemoryBarrier, voidType, + "memoryBarrier"); + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpMemoryBarrierAtomicCounter, + voidType, "memoryBarrierAtomicCounter"); + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpMemoryBarrierBuffer, + voidType, "memoryBarrierBuffer"); + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpMemoryBarrierImage, voidType, + "memoryBarrierImage"); + + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "texelFetch", gsampler2DMS, int2, int1); + + // Insert all variations of textureGather. + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2D, float2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2D, float2, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2DArray, float3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2DArray, float3, + int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsamplerCube, float3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsamplerCube, float3, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DShadow, float2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DShadow, float2, + float1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DArrayShadow, + float3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DArrayShadow, + float3, float1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", samplerCubeShadow, float3); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", samplerCubeShadow, float3, + float1); + + // Insert all variations of textureGatherOffset. + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2D, float2, + int2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2D, float2, + int2, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2DArray, + float3, int2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2DArray, + float3, int2, int1); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGatherOffset", sampler2DShadow, + float2, float1, int2); + symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGatherOffset", sampler2DArrayShadow, + float3, float1, int2); + + if (type == GL_COMPUTE_SHADER) + { + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpBarrier, voidType, + "barrier"); + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpMemoryBarrierShared, + voidType, "memoryBarrierShared"); + symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpGroupMemoryBarrier, + voidType, "groupMemoryBarrier"); + } + + if (type == GL_GEOMETRY_SHADER_OES) + { + TExtension extension = TExtension::OES_geometry_shader; + symbolTable.insertBuiltInFunctionNoParametersExt(ESSL3_1_BUILTINS, extension, EOpEmitVertex, + voidType, "EmitVertex"); + symbolTable.insertBuiltInFunctionNoParametersExt(ESSL3_1_BUILTINS, extension, + EOpEndPrimitive, voidType, "EndPrimitive"); + } // // Depth range in window coordinates // - TFieldList *fields = NewPoolTFieldList(); + TFieldList *fields = NewPoolTFieldList(); TSourceLoc zeroSourceLoc = {0, 0, 0, 0}; - TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"), zeroSourceLoc); - TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"), zeroSourceLoc); - TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"), zeroSourceLoc); + auto highpFloat1 = new TType(EbtFloat, EbpHigh, EvqGlobal, 1); + TField *near = new TField(highpFloat1, NewPoolTString("near"), zeroSourceLoc); + TField *far = new TField(highpFloat1, NewPoolTString("far"), zeroSourceLoc); + TField *diff = new TField(highpFloat1, NewPoolTString("diff"), zeroSourceLoc); fields->push_back(near); fields->push_back(far); fields->push_back(diff); - TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields); - TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true); - symbolTable.insert(COMMON_BUILTINS, depthRangeParameters); - TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct)); - depthRange->setQualifier(EvqUniform); - symbolTable.insert(COMMON_BUILTINS, depthRange); + TStructure *depthRangeStruct = + new TStructure(&symbolTable, NewPoolTString("gl_DepthRangeParameters"), fields); + symbolTable.insertStructType(COMMON_BUILTINS, depthRangeStruct); + TType depthRangeType(depthRangeStruct); + depthRangeType.setQualifier(EvqUniform); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_DepthRange", depthRangeType); // // Implementation dependent built-in constants. // - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors); - - symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors); - - if (spec != SH_CSS_SHADERS_SPEC) + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs, + EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", + resources.MaxVertexUniformVectors, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", + resources.MaxVertexTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", + resources.MaxCombinedTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", + resources.MaxTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", + resources.MaxFragmentUniformVectors, EbpMedium); + + symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors, + EbpMedium); + + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers, + EbpMedium); + if (resources.EXT_blend_func_extended) { - 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.insertConstIntExt(COMMON_BUILTINS, TExtension::EXT_blend_func_extended, + "gl_MaxDualSourceDrawBuffersEXT", + resources.MaxDualSourceDrawBuffers, EbpMedium); } - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", resources.MaxProgramTexelOffset); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", + resources.MaxVertexOutputVectors, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", + resources.MaxFragmentInputVectors, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", + resources.MinProgramTexelOffset, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", + resources.MaxProgramTexelOffset, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxImageUnits", resources.MaxImageUnits, + EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexImageUniforms", + resources.MaxVertexImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentImageUniforms", + resources.MaxFragmentImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeImageUniforms", + resources.MaxComputeImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedImageUniforms", + resources.MaxCombinedImageUniforms, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedShaderOutputResources", + resources.MaxCombinedShaderOutputResources, EbpMedium); + + symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupCount", + resources.MaxComputeWorkGroupCount, EbpHigh); + symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupSize", + resources.MaxComputeWorkGroupSize, EbpHigh); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeUniformComponents", + resources.MaxComputeUniformComponents, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeTextureImageUnits", + resources.MaxComputeTextureImageUnits, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounters", + resources.MaxComputeAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounterBuffers", + resources.MaxComputeAtomicCounterBuffers, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounters", + resources.MaxVertexAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounters", + resources.MaxFragmentAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounters", + resources.MaxCombinedAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBindings", + resources.MaxAtomicCounterBindings, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounterBuffers", + resources.MaxVertexAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounterBuffers", + resources.MaxFragmentAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounterBuffers", + resources.MaxCombinedAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBufferSize", + resources.MaxAtomicCounterBufferSize, EbpMedium); + + if (resources.OES_geometry_shader) + { + TExtension ext = TExtension::OES_geometry_shader; + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryInputComponents", + resources.MaxGeometryInputComponents, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryOutputComponents", + resources.MaxGeometryOutputComponents, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryImageUniforms", + resources.MaxGeometryImageUniforms, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryTextureImageUnits", + resources.MaxGeometryTextureImageUnits, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryOutputVertices", + resources.MaxGeometryOutputVertices, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryTotalOutputComponents", + resources.MaxGeometryTotalOutputComponents, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryUniformComponents", + resources.MaxGeometryUniformComponents, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryAtomicCounters", + resources.MaxGeometryAtomicCounters, EbpMedium); + symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryAtomicCounterBuffers", + resources.MaxGeometryAtomicCounterBuffers, EbpMedium); + } } -void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, +void IdentifyBuiltIns(sh::GLenum type, + ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) { @@ -486,136 +873,263 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, // Insert some special built-in variables that are not in // the built-in header files. // + + if (resources.OVR_multiview && type != GL_COMPUTE_SHADER) + { + symbolTable.insertVariableExt(ESSL3_BUILTINS, TExtension::OVR_multiview, "gl_ViewID_OVR", + TType(EbtUInt, EbpHigh, EvqViewIDOVR, 1)); + + // ESSL 1.00 doesn't have unsigned integers, so gl_ViewID_OVR is a signed integer in ESSL + // 1.00. This is specified in the WEBGL_multiview spec. + symbolTable.insertVariableExt(ESSL1_BUILTINS, TExtension::OVR_multiview, "gl_ViewID_OVR", + TType(EbtInt, EbpHigh, EvqViewIDOVR, 1)); + } + switch (type) { - case GL_FRAGMENT_SHADER: - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), - TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), - TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"), - TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); - - // - // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available. - // Instead, css_MixColor and css_ColorMatrix are available. - // - if (spec != SH_CSS_SHADERS_SPEC) + case GL_FRAGMENT_SHADER: { - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), - TType(EbtFloat, EbpMedium, EvqFragColor, 4))); - TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); - fragData.setArraySize(resources.MaxDrawBuffers); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_FragCoord", + TType(EbtFloat, EbpMedium, EvqFragCoord, 4)); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_FrontFacing", + TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_PointCoord", + TType(EbtFloat, EbpMedium, EvqPointCoord, 2)); + + symbolTable.insertVariable(ESSL1_BUILTINS, "gl_FragColor", + TType(EbtFloat, EbpMedium, EvqFragColor, 4)); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4); + if (spec != SH_WEBGL2_SPEC && spec != SH_WEBGL3_SPEC) + { + fragData.makeArray(resources.MaxDrawBuffers); + } + else + { + fragData.makeArray(1u); + } + symbolTable.insertVariable(ESSL1_BUILTINS, "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)); + symbolTable.insertVariableExt( + ESSL1_BUILTINS, TExtension::EXT_blend_func_extended, "gl_SecondaryFragColorEXT", + TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)); + TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1); + secondaryFragData.makeArray(resources.MaxDualSourceDrawBuffers); + symbolTable.insertVariableExt(ESSL1_BUILTINS, TExtension::EXT_blend_func_extended, + "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, - EvqFragDepthEXT, 1))); + symbolTable.insertVariableExt( + ESSL1_BUILTINS, TExtension::EXT_frag_depth, "gl_FragDepthEXT", + TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, + EvqFragDepthEXT, 1)); } - symbolTable.insert(ESSL3_BUILTINS, - new TVariable(NewPoolTString("gl_FragDepth"), - TType(EbtFloat, EbpHigh, EvqFragDepth, 1))); + symbolTable.insertVariable(ESSL3_BUILTINS, "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); - lastFragData.setArraySize(resources.MaxDrawBuffers); + TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1); + lastFragData.makeArray(resources.MaxDrawBuffers); if (resources.EXT_shader_framebuffer_fetch) { - symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + symbolTable.insertVariableExt(ESSL1_BUILTINS, + TExtension::EXT_shader_framebuffer_fetch, + "gl_LastFragData", lastFragData); } else if (resources.NV_shader_framebuffer_fetch) { - symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragColor"), - TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); - symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + symbolTable.insertVariableExt( + ESSL1_BUILTINS, TExtension::NV_shader_framebuffer_fetch, "gl_LastFragColor", + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)); + symbolTable.insertVariableExt(ESSL1_BUILTINS, + TExtension::NV_shader_framebuffer_fetch, + "gl_LastFragData", lastFragData); } } else if (resources.ARM_shader_framebuffer_fetch) { - symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragColorARM"), - TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + symbolTable.insertVariableExt( + ESSL1_BUILTINS, TExtension::ARM_shader_framebuffer_fetch, "gl_LastFragColorARM", + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)); + } + + if (resources.OES_geometry_shader) + { + TExtension extension = TExtension::OES_geometry_shader; + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveID", + TType(EbtInt, EbpHigh, EvqPrimitiveID, 1)); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Layer", + TType(EbtInt, EbpHigh, EvqLayer, 1)); } + + break; } - else + case GL_VERTEX_SHADER: { - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), - TType(EbtFloat, EbpMedium, EvqGlobal, 4))); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"), - TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_Position", + TType(EbtFloat, EbpHigh, EvqPosition, 4)); + symbolTable.insertVariable(COMMON_BUILTINS, "gl_PointSize", + TType(EbtFloat, EbpMedium, EvqPointSize, 1)); + symbolTable.insertVariable(ESSL3_BUILTINS, "gl_InstanceID", + TType(EbtInt, EbpHigh, EvqInstanceID, 1)); + symbolTable.insertVariable(ESSL3_BUILTINS, "gl_VertexID", + TType(EbtInt, EbpHigh, EvqVertexID, 1)); + + // For internal use by ANGLE - not exposed to the parser. + symbolTable.insertVariable(GLSL_BUILTINS, "gl_ViewportIndex", + TType(EbtInt, EbpHigh, EvqViewportIndex)); + // gl_Layer exists in other shader stages in ESSL, but not in vertex shader so far. + symbolTable.insertVariable(GLSL_BUILTINS, "gl_Layer", TType(EbtInt, EbpHigh, EvqLayer)); + break; + } + case GL_COMPUTE_SHADER: + { + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_NumWorkGroups", + TType(EbtUInt, EbpUndefined, EvqNumWorkGroups, 3)); + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_WorkGroupSize", + TType(EbtUInt, EbpUndefined, EvqWorkGroupSize, 3)); + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_WorkGroupID", + TType(EbtUInt, EbpUndefined, EvqWorkGroupID, 3)); + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_LocalInvocationID", + TType(EbtUInt, EbpUndefined, EvqLocalInvocationID, 3)); + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_GlobalInvocationID", + TType(EbtUInt, EbpUndefined, EvqGlobalInvocationID, 3)); + symbolTable.insertVariable(ESSL3_1_BUILTINS, "gl_LocalInvocationIndex", + TType(EbtUInt, EbpUndefined, EvqLocalInvocationIndex, 1)); + break; } - break; - - case GL_VERTEX_SHADER: - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), - TType(EbtFloat, EbpHigh, EvqPosition, 4))); - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), - TType(EbtFloat, EbpMedium, EvqPointSize, 1))); - symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), - TType(EbtInt, EbpHigh, EvqInstanceID, 1))); - break; - - default: - assert(false && "Language not supported"); + case GL_GEOMETRY_SHADER_OES: + { + TExtension extension = TExtension::OES_geometry_shader; + + // Add built-in interface block gl_PerVertex and the built-in array gl_in. + // TODO(jiawei.shao@intel.com): implement GL_OES_geometry_point_size. + const TString *glPerVertexString = NewPoolTString("gl_PerVertex"); + symbolTable.insertInterfaceBlockNameExt(ESSL3_1_BUILTINS, extension, glPerVertexString); + + TFieldList *fieldList = NewPoolTFieldList(); + TSourceLoc zeroSourceLoc = {0, 0, 0, 0}; + TField *glPositionField = new TField(new TType(EbtFloat, EbpHigh, EvqPosition, 4), + NewPoolTString("gl_Position"), zeroSourceLoc); + fieldList->push_back(glPositionField); + + TInterfaceBlock *glInBlock = new TInterfaceBlock( + glPerVertexString, fieldList, NewPoolTString("gl_in"), TLayoutQualifier::Create()); + + // The array size of gl_in is undefined until we get a valid input primitive + // declaration. + TType glInType(glInBlock, EvqPerVertexIn, TLayoutQualifier::Create()); + glInType.makeArray(0u); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_in", glInType); + + TType glPositionType(EbtFloat, EbpHigh, EvqPosition, 4); + glPositionType.setInterfaceBlock(new TInterfaceBlock( + glPerVertexString, fieldList, nullptr, TLayoutQualifier::Create())); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Position", + glPositionType); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveIDIn", + TType(EbtInt, EbpHigh, EvqPrimitiveIDIn, 1)); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_InvocationID", + TType(EbtInt, EbpHigh, EvqInvocationID, 1)); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveID", + TType(EbtInt, EbpHigh, EvqPrimitiveID, 1)); + symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Layer", + TType(EbtInt, EbpHigh, EvqLayer, 1)); + + break; + } + default: + UNREACHABLE(); } } -void InitExtensionBehavior(const ShBuiltInResources& resources, - TExtensionBehavior& extBehavior) +void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavior &extBehavior) { if (resources.OES_standard_derivatives) - extBehavior["GL_OES_standard_derivatives"] = EBhUndefined; + { + extBehavior[TExtension::OES_standard_derivatives] = EBhUndefined; + } if (resources.OES_EGL_image_external) - extBehavior["GL_OES_EGL_image_external"] = EBhUndefined; + { + extBehavior[TExtension::OES_EGL_image_external] = EBhUndefined; + } + if (resources.OES_EGL_image_external_essl3) + { + extBehavior[TExtension::OES_EGL_image_external_essl3] = EBhUndefined; + } + if (resources.NV_EGL_stream_consumer_external) + { + extBehavior[TExtension::NV_EGL_stream_consumer_external] = EBhUndefined; + } if (resources.ARB_texture_rectangle) - extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined; + { + // Special: ARB_texture_rectangle extension does not follow the standard for #extension + // directives - it is enabled by default. An extension directive may still disable it. + extBehavior[TExtension::ARB_texture_rectangle] = EBhEnable; + } if (resources.EXT_blend_func_extended) - extBehavior["GL_EXT_blend_func_extended"] = EBhUndefined; + { + extBehavior[TExtension::EXT_blend_func_extended] = EBhUndefined; + } if (resources.EXT_draw_buffers) - extBehavior["GL_EXT_draw_buffers"] = EBhUndefined; + { + extBehavior[TExtension::EXT_draw_buffers] = EBhUndefined; + } if (resources.EXT_frag_depth) - extBehavior["GL_EXT_frag_depth"] = EBhUndefined; + { + extBehavior[TExtension::EXT_frag_depth] = EBhUndefined; + } if (resources.EXT_shader_texture_lod) - extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined; + { + extBehavior[TExtension::EXT_shader_texture_lod] = EBhUndefined; + } if (resources.EXT_shader_framebuffer_fetch) - extBehavior["GL_EXT_shader_framebuffer_fetch"] = EBhUndefined; + { + extBehavior[TExtension::EXT_shader_framebuffer_fetch] = EBhUndefined; + } if (resources.NV_shader_framebuffer_fetch) - extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined; + { + extBehavior[TExtension::NV_shader_framebuffer_fetch] = EBhUndefined; + } if (resources.ARM_shader_framebuffer_fetch) - extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined; + { + extBehavior[TExtension::ARM_shader_framebuffer_fetch] = EBhUndefined; + } + if (resources.OVR_multiview) + { + extBehavior[TExtension::OVR_multiview] = EBhUndefined; + } + if (resources.EXT_YUV_target) + { + extBehavior[TExtension::EXT_YUV_target] = EBhUndefined; + } + if (resources.OES_geometry_shader) + { + extBehavior[TExtension::OES_geometry_shader] = EBhUndefined; + extBehavior[TExtension::EXT_geometry_shader] = EBhUndefined; + } } void ResetExtensionBehavior(TExtensionBehavior &extBehavior) { - for (auto ext_iter = extBehavior.begin(); - ext_iter != extBehavior.end(); - ++ext_iter) + for (auto &ext : extBehavior) { - ext_iter->second = EBhUndefined; + if (ext.first == TExtension::ARB_texture_rectangle) + { + ext.second = EBhEnable; + } + else + { + ext.second = EBhUndefined; + } } } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.h b/src/3rdparty/angle/src/compiler/translator/Initialize.h index c43ce3417a..2e61218a0f 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.h +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.h @@ -11,14 +11,21 @@ #include "compiler/translator/Compiler.h" #include "compiler/translator/SymbolTable.h" -void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table); +namespace sh +{ -void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, - const ShBuiltInResources& resources, - TSymbolTable& symbolTable); +void InsertBuiltInFunctions(sh::GLenum type, + ShShaderSpec spec, + const ShBuiltInResources &resources, + TSymbolTable &table); -void InitExtensionBehavior(const ShBuiltInResources& resources, - TExtensionBehavior& extensionBehavior); +void IdentifyBuiltIns(sh::GLenum type, + ShShaderSpec spec, + const ShBuiltInResources &resources, + TSymbolTable &symbolTable); + +void InitExtensionBehavior(const ShBuiltInResources &resources, + TExtensionBehavior &extensionBehavior); // Resets the behavior of the extensions listed in |extensionBehavior| to the // undefined state. These extensions will only be those initially supported in @@ -26,4 +33,6 @@ void InitExtensionBehavior(const ShBuiltInResources& resources, // extensions will remain unsupported. void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior); -#endif // COMPILER_TRANSLATOR_INITIALIZE_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INITIALIZE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp index 713965389f..43c215f52b 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.cpp @@ -7,24 +7,22 @@ #include "compiler/translator/Cache.h" #include "compiler/translator/InitializeDll.h" #include "compiler/translator/InitializeGlobals.h" -#include "compiler/translator/InitializeParseContext.h" #include "common/platform.h" #include +namespace sh +{ + bool InitProcess() { - if (!InitializePoolIndex()) { + if (!InitializePoolIndex()) + { assert(0 && "InitProcess(): Failed to initalize global pool"); return false; } - if (!InitializeParseContextIndex()) { - assert(0 && "InitProcess(): Failed to initalize parse context"); - return false; - } - TCache::initialize(); return true; @@ -32,7 +30,8 @@ bool InitProcess() void DetachProcess() { - FreeParseContextIndex(); FreePoolIndex(); TCache::destroy(); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h index 4c400760f6..87f7251470 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h @@ -6,8 +6,10 @@ #ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_ #define COMPILER_TRANSLATOR_INITIALIZEDLL_H_ +namespace sh +{ bool InitProcess(); void DetachProcess(); +} // namespace sh -#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_ - +#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h index 8c65cb28da..9a67ed0e04 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h @@ -10,4 +10,4 @@ bool InitializePoolIndex(); void FreePoolIndex(); -#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ +#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp deleted file mode 100644 index c35cedb348..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.cpp +++ /dev/null @@ -1,42 +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. -// - -#include "compiler/translator/InitializeParseContext.h" - -#include "common/tls.h" - -#include - -TLSIndex GlobalParseContextIndex = TLS_INVALID_INDEX; - -bool InitializeParseContextIndex() -{ - assert(GlobalParseContextIndex == TLS_INVALID_INDEX); - - GlobalParseContextIndex = CreateTLSIndex(); - return GlobalParseContextIndex != TLS_INVALID_INDEX; -} - -void FreeParseContextIndex() -{ - assert(GlobalParseContextIndex != TLS_INVALID_INDEX); - - DestroyTLSIndex(GlobalParseContextIndex); - GlobalParseContextIndex = TLS_INVALID_INDEX; -} - -void SetGlobalParseContext(TParseContext* context) -{ - assert(GlobalParseContextIndex != TLS_INVALID_INDEX); - SetTLSValue(GlobalParseContextIndex, context); -} - -TParseContext* GetGlobalParseContext() -{ - assert(GlobalParseContextIndex != TLS_INVALID_INDEX); - return static_cast(GetTLSValue(GlobalParseContextIndex)); -} - diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h deleted file mode 100644 index 70dac702e2..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ -#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ - -bool InitializeParseContextIndex(); -void FreeParseContextIndex(); - -class TParseContext; -extern void SetGlobalParseContext(TParseContext* context); -extern TParseContext* GetGlobalParseContext(); - -#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp index 86d3e6bc83..aa1a042fac 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp @@ -6,112 +6,285 @@ #include "compiler/translator/InitializeVariables.h" +#include "angle_gl.h" #include "common/debug.h" +#include "compiler/translator/FindMain.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ namespace { -TIntermConstantUnion *constructFloatConstUnionNode(const TType &type) +void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable); + +void AddStructZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable); + +TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode) { - TType myType = type; - unsigned char size = static_cast(myType.getNominalSize()); - if (myType.isMatrix()) - size *= size; - TConstantUnion *u = new TConstantUnion[size]; - for (int ii = 0; ii < size; ++ii) - u[ii].setFConst(0.0f); - - myType.clearArrayness(); - myType.setQualifier(EvqConst); - TIntermConstantUnion *node = new TIntermConstantUnion(u, myType); - return node; + TIntermTyped *zero = CreateZeroNode(initializedNode->getType()); + return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero); } -TIntermConstantUnion *constructIndexNode(int index) +void AddZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) { - TConstantUnion *u = new TConstantUnion[1]; - u[0].setIConst(index); + if (initializedNode->isArray()) + { + AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut, + symbolTable); + } + else if (initializedNode->getType().isStructureContainingArrays() || + initializedNode->getType().isNamelessStruct()) + { + AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut, + symbolTable); + } + else + { + initSequenceOut->push_back(CreateZeroInitAssignment(initializedNode)); + } +} - TType type(EbtInt, EbpUndefined, EvqConst, 1); - TIntermConstantUnion *node = new TIntermConstantUnion(u, type); - return node; +void AddStructZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + ASSERT(initializedNode->getBasicType() == EbtStruct); + const TStructure *structType = initializedNode->getType().getStruct(); + for (int i = 0; i < static_cast(structType->fields().size()); ++i) + { + TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, + initializedNode->deepCopy(), CreateIndexNode(i)); + // Structs can't be defined inside structs, so the type of a struct field can't be a + // nameless struct. + ASSERT(!element->getType().isNamelessStruct()); + AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable); + } } -} // namespace anonymous +void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i) + { + TIntermBinary *element = + new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i)); + AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable); + } +} -bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) +void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) { - bool visitChildren = !mCodeInserted; - switch (node->getOp()) + ASSERT(initializedNode->isArray()); + TSymbolUniqueId indexSymbol(symbolTable); + + TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexSymbol, TType(EbtInt), EvqTemporary); + TIntermDeclaration *indexInit = + CreateTempInitDeclarationNode(indexSymbol, CreateZeroNode(TType(EbtInt)), EvqTemporary); + TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize()); + TIntermBinary *indexSmallerThanSize = + new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode); + TIntermUnary *indexIncrement = new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy()); + + TIntermBlock *forLoopBody = new TIntermBlock(); + TIntermSequence *forLoopBodySeq = forLoopBody->getSequence(); + + TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(), + indexSymbolNode->deepCopy()); + AddZeroInitSequence(element, true, forLoopBodySeq, symbolTable); + + TIntermLoop *forLoop = + new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody); + initSequenceOut->push_back(forLoop); +} + +void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + // The array elements are assigned one by one to keep the AST compatible with ESSL 1.00 which + // doesn't have array assignment. We'll do this either with a for loop or just a list of + // statements assigning to each array index. Note that it is important to have the array init in + // the right order to workaround http://crbug.com/709317 + bool isSmallArray = initializedNode->getOutermostArraySize() <= 1u || + (initializedNode->getBasicType() != EbtStruct && + !initializedNode->getType().isArrayOfArrays() && + initializedNode->getOutermostArraySize() <= 3u); + if (initializedNode->getQualifier() == EvqFragData || + initializedNode->getQualifier() == EvqFragmentOut || isSmallArray || + !canUseLoopsToInitialize) + { + // Fragment outputs should not be indexed by non-constant indices. + // Also it doesn't make sense to use loops to initialize very small arrays. + AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize, initSequenceOut, + symbolTable); + } + else { - case EOpSequence: - break; - case EOpFunction: - { - // Function definition. - ASSERT(visit == PreVisit); - if (node->getName() == "main(") + AddArrayZeroInitForLoop(initializedNode, initSequenceOut, symbolTable); + } +} + +void InsertInitCode(TIntermSequence *mainBody, + const InitVariableList &variables, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize) +{ + for (const auto &var : variables) + { + TString name = TString(var.name.c_str()); + size_t pos = name.find_last_of('['); + if (pos != TString::npos) { - TIntermSequence *sequence = node->getSequence(); - ASSERT((sequence->size() == 1) || (sequence->size() == 2)); - TIntermAggregate *body = NULL; - if (sequence->size() == 1) - { - body = new TIntermAggregate(EOpSequence); - sequence->push_back(body); - } - else + name = name.substr(0, pos); + } + + TIntermTyped *initializedSymbol = nullptr; + if (var.isBuiltIn()) + { + initializedSymbol = ReferenceBuiltInVariable(name, *symbolTable, shaderVersion); + if (initializedSymbol->getQualifier() == EvqFragData && + !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers)) { - body = (*sequence)[1]->getAsAggregate(); + // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be + // written to. + // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up + // with a good way to do it. Right now "gl_FragData" in symbol table is initialized + // to have the array size of MaxDrawBuffers, and the initialization happens before + // the shader sets the extensions it is using. + initializedSymbol = + new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0)); } - ASSERT(body); - insertInitCode(body->getSequence()); - mCodeInserted = true; } - break; - } - default: - visitChildren = false; - break; + else + { + initializedSymbol = ReferenceGlobalVariable(name, *symbolTable); + } + ASSERT(initializedSymbol != nullptr); + + TIntermSequence *initCode = + CreateInitCode(initializedSymbol, canUseLoopsToInitialize, symbolTable); + mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end()); } - return visitChildren; } -void InitializeVariables::insertInitCode(TIntermSequence *sequence) +class InitializeLocalsTraverser : public TIntermTraverser { - for (size_t ii = 0; ii < mVariables.size(); ++ii) + public: + InitializeLocalsTraverser(int shaderVersion, + TSymbolTable *symbolTable, + bool canUseLoopsToInitialize) + : TIntermTraverser(true, false, false, symbolTable), + mShaderVersion(shaderVersion), + mCanUseLoopsToInitialize(canUseLoopsToInitialize) { - const InitVariableInfo &varInfo = mVariables[ii]; + } - if (varInfo.type.isArray()) + protected: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + for (TIntermNode *declarator : *node->getSequence()) { - for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index) + if (!mInGlobalScope && !declarator->getAsBinaryNode()) { - TIntermBinary *assign = new TIntermBinary(EOpAssign); - sequence->insert(sequence->begin(), assign); - - TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); - TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); - indexDirect->setLeft(symbol); - TIntermConstantUnion *indexNode = constructIndexNode(index); - indexDirect->setRight(indexNode); - - assign->setLeft(indexDirect); + TIntermSymbol *symbol = declarator->getAsSymbolNode(); + ASSERT(symbol); + if (symbol->getSymbol() == "") + { + continue; + } - TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); - assign->setRight(zeroConst); + // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not + // support array constructors or assigning arrays. + bool arrayConstructorUnavailable = + (symbol->isArray() || symbol->getType().isStructureContainingArrays()) && + mShaderVersion == 100; + // Nameless struct constructors can't be referred to, so they also need to be + // initialized one element at a time. + // TODO(oetuaho): Check if it makes sense to initialize using a loop, even if we + // could use an initializer. It could at least reduce code size for very large + // arrays, but could hurt runtime performance. + if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct()) + { + // SimplifyLoopConditions should have been run so the parent node of this node + // should not be a loop. + ASSERT(getParentNode()->getAsLoopNode() == nullptr); + // SeparateDeclarations should have already been run, so we don't need to worry + // about further declarators in this declaration depending on the effects of + // this declarator. + ASSERT(node->getSequence()->size() == 1); + insertStatementsInParentBlock( + TIntermSequence(), + *CreateInitCode(symbol, mCanUseLoopsToInitialize, mSymbolTable)); + } + else + { + TIntermBinary *init = + new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType())); + queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD); + } } } - else - { - TIntermBinary *assign = new TIntermBinary(EOpAssign); - sequence->insert(sequence->begin(), assign); - TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); - assign->setLeft(symbol); - TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); - assign->setRight(zeroConst); - } - + return false; } + + private: + int mShaderVersion; + bool mCanUseLoopsToInitialize; +}; + +} // namespace anonymous + +TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable) +{ + TIntermSequence *initCode = new TIntermSequence(); + AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, initCode, symbolTable); + return initCode; +} + +void InitializeUninitializedLocals(TIntermBlock *root, + int shaderVersion, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable) +{ + InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize); + root->traverse(&traverser); + traverser.updateTree(); +} + +void InitializeVariables(TIntermBlock *root, + const InitVariableList &vars, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize) +{ + TIntermBlock *body = FindMainBody(root); + InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior, + canUseLoopsToInitialize); } +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h index 2a141ec91c..1a7b3c0f24 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h @@ -7,45 +7,47 @@ #ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ #define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ +#include + +#include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/IntermNode.h" -class InitializeVariables : public TIntermTraverser +namespace sh { - public: - struct InitVariableInfo - { - TString name; - TType type; - - InitVariableInfo(const TString &_name, const TType &_type) - : name(_name), - type(_type) - { - } - }; - typedef TVector InitVariableInfoList; - - InitializeVariables(const InitVariableInfoList &vars) - : TIntermTraverser(true, false, false), - mVariables(vars), - mCodeInserted(false) - { - } - - protected: - 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; } - - bool visitAggregate(Visit visit, TIntermAggregate *node) override; - - private: - void insertInitCode(TIntermSequence *sequence); - - InitVariableInfoList mVariables; - bool mCodeInserted; -}; +class TSymbolTable; + +typedef std::vector InitVariableList; + +// For all of the functions below: If canUseLoopsToInitialize is set, for loops are used instead of +// a large number of initializers where it can make sense, such as for initializing large arrays. + +// Return a sequence of assignment operations to initialize "initializedSymbol". initializedSymbol +// may be an array, struct or any combination of these, as long as it contains only basic types. +TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable); + +// Initialize all uninitialized local variables, so that undefined behavior is avoided. +void InitializeUninitializedLocals(TIntermBlock *root, + int shaderVersion, + bool canUseLoopsToInitialize, + TSymbolTable *symbolTable); + +// This function can initialize all the types that CreateInitCode is able to initialize. All +// variables must be globals which can be found in the symbol table. For now it is used for the +// following two scenarios: +// 1. Initializing gl_Position; +// 2. Initializing output variables referred to in the shader source. +// Note: The type of each lvalue in an initializer is retrieved from the symbol table. gl_FragData +// requires special handling because the number of indices which can be initialized is determined by +// enabled extensions. +void InitializeVariables(TIntermBlock *root, + const InitVariableList &vars, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize); + +} // namespace sh #endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp index 2a92860088..a57ffcb4bc 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp @@ -17,14 +17,18 @@ #include "common/mathutil.h" #include "common/matrix_utils.h" -#include "compiler/translator/HashNames.h" +#include "compiler/translator/Diagnostics.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ namespace { -const float kPi = 3.14159265358979323846f; +const float kPi = 3.14159265358979323846f; const float kDegreesToRadiansMultiplier = kPi / 180.0f; const float kRadiansToDegreesMultiplier = 180.0f / kPi; @@ -33,72 +37,40 @@ TPrecision GetHigherPrecision(TPrecision left, TPrecision right) return left > right ? left : right; } -bool ValidateMultiplication(TOperator op, const TType &left, const TType &right) -{ - switch (op) - { - case EOpMul: - case EOpMulAssign: - return left.getNominalSize() == right.getNominalSize() && - left.getSecondarySize() == right.getSecondarySize(); - case EOpVectorTimesScalar: - case EOpVectorTimesScalarAssign: - return true; - case EOpVectorTimesMatrix: - return left.getNominalSize() == right.getRows(); - case EOpVectorTimesMatrixAssign: - return left.getNominalSize() == right.getRows() && - left.getNominalSize() == right.getCols(); - case EOpMatrixTimesVector: - return left.getCols() == right.getNominalSize(); - case EOpMatrixTimesScalar: - case EOpMatrixTimesScalarAssign: - return true; - case EOpMatrixTimesMatrix: - return left.getCols() == right.getRows(); - case EOpMatrixTimesMatrixAssign: - return left.getCols() == right.getCols() && - left.getRows() == right.getRows(); - - default: - UNREACHABLE(); - return false; - } -} - TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size) { TConstantUnion *constUnion = new TConstantUnion[size]; for (unsigned int i = 0; i < size; ++i) - constUnion[i] = constant; + constUnion[i] = constant; return constUnion; } -void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType, - TInfoSink &infoSink, TConstantUnion *result) +void UndefinedConstantFoldingError(const TSourceLoc &loc, + TOperator op, + TBasicType basicType, + TDiagnostics *diagnostics, + 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()); + diagnostics->warning(loc, "operation result is undefined for the values passed in", + GetOperatorString(op)); switch (basicType) { - 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; + 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; } } @@ -123,7 +95,7 @@ float VectorDotProduct(const TConstantUnion *paramArray1, return result; } -TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, +TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode, TQualifier qualifier) { @@ -145,8 +117,9 @@ angle::Matrix GetMatrix(const TConstantUnion *paramArray, 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(); + // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below + // so that the created matrix will have the expected dimensions after the transpose. + return angle::Matrix(elements, cols, rows).transpose(); } angle::Matrix GetMatrix(const TConstantUnion *paramArray, const unsigned int &size) @@ -163,7 +136,7 @@ void SetUnionArrayFromMatrix(const angle::Matrix &m, TConstantUnion *resu { // 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(); + angle::Matrix result = m.transpose(); std::vector resultElements = result.elements(); for (size_t i = 0; i < resultElements.size(); i++) resultArray[i].setFConst(resultElements[i]); @@ -171,7 +144,6 @@ void SetUnionArrayFromMatrix(const angle::Matrix &m, TConstantUnion *resu } // namespace anonymous - //////////////////////////////////////////////////////////////// // // Member functions of the nodes used for building the tree. @@ -181,90 +153,214 @@ void SetUnionArrayFromMatrix(const angle::Matrix &m, TConstantUnion *resu void TIntermTyped::setTypePreservePrecision(const TType &t) { TPrecision precision = getPrecision(); - mType = t; + mType = t; ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined); mType.setPrecision(precision); } #define REPLACE_IF_IS(node, type, original, replacement) \ - if (node == original) { \ - node = static_cast(replacement); \ - return true; \ + if (node == original) \ + { \ + node = static_cast(replacement); \ + return true; \ } -bool TIntermLoop::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { + ASSERT(original != nullptr); // This risks replacing multiple children. 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, TIntermAggregate, original, replacement); + REPLACE_IF_IS(mBody, TIntermBlock, original, replacement); return false; } -bool TIntermBranch::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement); return false; } -bool TIntermBinary::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); + return false; +} + +bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement); REPLACE_IF_IS(mRight, TIntermTyped, original, replacement); return false; } -bool TIntermUnary::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); return false; } -bool TIntermAggregate::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement); + return false; +} + +bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement); + REPLACE_IF_IS(mBody, TIntermBlock, original, replacement); + return false; +} + +bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { - for (size_t ii = 0; ii < mSequence.size(); ++ii) + return replaceChildNodeInternal(original, replacement); +} + +bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement) +{ + for (size_t ii = 0; ii < getSequence()->size(); ++ii) { - REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement); + REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement); } return false; } -bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements) +bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original, + const TIntermSequence &replacements) { - for (auto it = mSequence.begin(); it < mSequence.end(); ++it) + for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it) { if (*it == original) { - it = mSequence.erase(it); - mSequence.insert(it, replacements.begin(), replacements.end()); + it = getSequence()->erase(it); + getSequence()->insert(it, replacements.begin(), replacements.end()); return true; } } return false; } -bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions) +bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position, + const TIntermSequence &insertions) { - if (position > mSequence.size()) + if (position > getSequence()->size()) { return false; } - auto it = mSequence.begin() + position; - mSequence.insert(it, insertions.begin(), insertions.end()); + auto it = getSequence()->begin() + position; + getSequence()->insert(it, insertions.begin(), insertions.end()); return true; } +TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func, + TIntermSequence *arguments) +{ + TIntermAggregate *callNode = + new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments); + callNode->getFunctionSymbolInfo()->setFromFunction(func); + return callNode; +} + +TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type, + const TSymbolUniqueId &id, + const TName &name, + TIntermSequence *arguments) +{ + TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments); + callNode->getFunctionSymbolInfo()->setId(id); + callNode->getFunctionSymbolInfo()->setNameObj(name); + return callNode; +} + +TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func, + TIntermSequence *arguments) +{ + TIntermAggregate *callNode = + new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments); + callNode->getFunctionSymbolInfo()->setFromFunction(func); + // Note that name needs to be set before texture function type is determined. + callNode->setBuiltInFunctionPrecision(); + return callNode; +} + +TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, + TIntermSequence *arguments) +{ + return new TIntermAggregate(type, EOpConstruct, arguments); +} + +TIntermAggregate *TIntermAggregate::Create(const TType &type, + TOperator op, + TIntermSequence *arguments) +{ + TIntermAggregate *node = new TIntermAggregate(type, op, arguments); + ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall + ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall + ASSERT(!node->isConstructor()); // Should use CreateConstructor + return node; +} + +TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments) + : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false) +{ + if (arguments != nullptr) + { + mArguments.swap(*arguments); + } + setTypePrecisionAndQualifier(type); +} + +void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type) +{ + setType(type); + mType.setQualifier(EvqTemporary); + if (!isFunctionCall()) + { + if (isConstructor()) + { + // Structs should not be precision qualified, the individual members may be. + // Built-in types on the other hand should be precision qualified. + if (getBasicType() != EbtStruct) + { + setPrecisionFromChildren(); + } + } + else + { + setPrecisionForBuiltInOp(); + } + if (areChildrenConstQualified()) + { + mType.setQualifier(EvqConst); + } + } +} + bool TIntermAggregate::areChildrenConstQualified() { - for (TIntermNode *&child : mSequence) + for (TIntermNode *&arg : mArguments) { - TIntermTyped *typed = child->getAsTyped(); - if (typed && typed->getQualifier() != EvqConst) + TIntermTyped *typedArg = arg->getAsTyped(); + if (typedArg && typedArg->getQualifier() != EvqConst) { return false; } @@ -281,9 +377,9 @@ void TIntermAggregate::setPrecisionFromChildren() return; } - TPrecision precision = EbpUndefined; - TIntermSequence::iterator childIter = mSequence.begin(); - while (childIter != mSequence.end()) + TPrecision precision = EbpUndefined; + TIntermSequence::iterator childIter = mArguments.begin(); + while (childIter != mArguments.end()) { TIntermTyped *typed = (*childIter)->getAsTyped(); if (typed) @@ -293,51 +389,149 @@ void TIntermAggregate::setPrecisionFromChildren() mType.setPrecision(precision); } +void TIntermAggregate::setPrecisionForBuiltInOp() +{ + ASSERT(!isConstructor()); + ASSERT(!isFunctionCall()); + if (!setPrecisionForSpecialBuiltInOp()) + { + setPrecisionFromChildren(); + } +} + +bool TIntermAggregate::setPrecisionForSpecialBuiltInOp() +{ + switch (mOp) + { + case EOpBitfieldExtract: + mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision()); + mGotPrecisionFromChildren = true; + return true; + case EOpBitfieldInsert: + mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(), + mArguments[1]->getAsTyped()->getPrecision())); + mGotPrecisionFromChildren = true; + return true; + case EOpUaddCarry: + case EOpUsubBorrow: + mType.setPrecision(EbpHigh); + return true; + default: + return false; + } +} + void TIntermAggregate::setBuiltInFunctionPrecision() { // All built-ins returning bool should be handled as ops, not functions. ASSERT(getBasicType() != EbtBool); + ASSERT(mOp == EOpCallBuiltInFunction); TPrecision precision = EbpUndefined; - TIntermSequence::iterator childIter = mSequence.begin(); - while (childIter != mSequence.end()) + for (TIntermNode *arg : mArguments) { - TIntermTyped *typed = (*childIter)->getAsTyped(); + TIntermTyped *typed = arg->getAsTyped(); // ESSL spec section 8: texture functions get their precision from the sampler. if (typed && IsSampler(typed->getBasicType())) { precision = typed->getPrecision(); break; } - ++childIter; } // 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.getString().find("textureSize") == 0) + if (mFunctionInfo.getName().find("textureSize") == 0) mType.setPrecision(EbpHigh); else mType.setPrecision(precision); } -bool TIntermSelection::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +TString TIntermAggregate::getSymbolTableMangledName() const +{ + ASSERT(!isConstructor()); + switch (mOp) + { + case EOpCallInternalRawFunction: + case EOpCallBuiltInFunction: + case EOpCallFunctionInAST: + return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments); + default: + TString opString = GetOperatorString(mOp); + return TFunction::GetMangledNameFromCall(opString, mArguments); + } +} + +bool TIntermAggregate::hasSideEffects() const +{ + if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects()) + { + for (TIntermNode *arg : mArguments) + { + if (arg->getAsTyped()->hasSideEffects()) + { + return true; + } + } + return false; + } + // Conservatively assume most aggregate operators have side-effects + return true; +} + +void TIntermBlock::appendStatement(TIntermNode *statement) +{ + // Declaration nodes with no children can appear if it was an empty declaration or if all the + // declarators just added constants to the symbol table instead of generating code. We still + // need to add the declaration to the AST in that case because it might be relevant to the + // validity of switch/case. + if (statement != nullptr) + { + mStatements.push_back(statement); + } +} + +void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter) +{ + ASSERT(parameter != nullptr); + mParameters.push_back(parameter); +} + +void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator) +{ + ASSERT(declarator != nullptr); + ASSERT(declarator->getAsSymbolNode() != nullptr || + (declarator->getAsBinaryNode() != nullptr && + declarator->getAsBinaryNode()->getOp() == EOpInitialize)); + ASSERT(mDeclarators.empty() || + declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType())); + mDeclarators.push_back(declarator); +} + +bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement); + REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement); + return false; +} + +bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); - REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement); - REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement); + REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement); return false; } -bool TIntermSwitch::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mInit, TIntermTyped, original, replacement); - REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement); + REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement); + ASSERT(mStatementList); return false; } -bool TIntermCase::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); return false; @@ -351,28 +545,104 @@ TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node mLine = node.mLine; } +bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters() +{ + TIntermAggregate *constructor = getAsAggregate(); + if (!constructor || !constructor->isConstructor()) + { + return false; + } + for (TIntermNode *&node : *constructor->getSequence()) + { + if (!node->getAsConstantUnion()) + return false; + } + return true; +} + TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node) { mUnionArrayPointer = node.mUnionArrayPointer; } +void TFunctionSymbolInfo::setFromFunction(const TFunction &function) +{ + setName(function.getName()); + setId(TSymbolUniqueId(function)); +} + +TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id) + : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false) +{ +} + +TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info) + : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects) +{ + if (info.mId) + { + mId = new TSymbolUniqueId(*info.mId); + } +} + +TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info) +{ + mName = info.mName; + if (info.mId) + { + mId = new TSymbolUniqueId(*info.mId); + } + else + { + mId = nullptr; + } + return *this; +} + +void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id) +{ + mId = new TSymbolUniqueId(id); +} + +const TSymbolUniqueId &TFunctionSymbolInfo::getId() const +{ + ASSERT(mId); + return *mId; +} + TIntermAggregate::TIntermAggregate(const TIntermAggregate &node) : TIntermOperator(node), - mName(node.mName), - mUserDefined(node.mUserDefined), - mFunctionId(node.mFunctionId), mUseEmulatedFunction(node.mUseEmulatedFunction), - mGotPrecisionFromChildren(node.mGotPrecisionFromChildren) + mGotPrecisionFromChildren(node.mGotPrecisionFromChildren), + mFunctionInfo(node.mFunctionInfo) { - for (TIntermNode *child : node.mSequence) + for (TIntermNode *arg : node.mArguments) { - TIntermTyped *typedChild = child->getAsTyped(); - ASSERT(typedChild != nullptr); - TIntermTyped *childCopy = typedChild->deepCopy(); - mSequence.push_back(childCopy); + TIntermTyped *typedArg = arg->getAsTyped(); + ASSERT(typedArg != nullptr); + TIntermTyped *argCopy = typedArg->deepCopy(); + mArguments.push_back(argCopy); } } +TIntermAggregate *TIntermAggregate::shallowCopy() const +{ + TIntermSequence *copySeq = new TIntermSequence(); + copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end()); + TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq); + *copyNode->getFunctionSymbolInfo() = mFunctionInfo; + copyNode->setLine(mLine); + return copyNode; +} + +TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node) +{ + TIntermTyped *operandCopy = node.mOperand->deepCopy(); + ASSERT(operandCopy != nullptr); + mOperand = operandCopy; + mSwizzleOffsets = node.mSwizzleOffsets; +} + TIntermBinary::TIntermBinary(const TIntermBinary &node) : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp) { @@ -391,176 +661,422 @@ TIntermUnary::TIntermUnary(const TIntermUnary &node) mOperand = operandCopy; } -TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node) +TIntermTernary::TIntermTernary(const TIntermTernary &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(); + TIntermTyped *trueCopy = node.mTrueExpression->deepCopy(); + TIntermTyped *falseCopy = node.mFalseExpression->deepCopy(); ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr); - mCondition = conditionCopy; - mTrueBlock = trueCopy; - mFalseBlock = falseCopy; + mCondition = conditionCopy; + mTrueExpression = trueCopy; + mFalseExpression = falseCopy; } -// -// Say whether or not an operation node changes the value of a variable. -// bool TIntermOperator::isAssignment() const { - switch (mOp) - { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - case EOpAssign: - case EOpAddAssign: - case EOpSubAssign: - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - case EOpDivAssign: - case EOpIModAssign: - case EOpBitShiftLeftAssign: - case EOpBitShiftRightAssign: - case EOpBitwiseAndAssign: - case EOpBitwiseXorAssign: - case EOpBitwiseOrAssign: - return true; - default: - return false; - } + return IsAssignment(mOp); } bool TIntermOperator::isMultiplication() const { switch (mOp) { - case EOpMul: - case EOpMatrixTimesMatrix: - case EOpMatrixTimesVector: - case EOpMatrixTimesScalar: - case EOpVectorTimesMatrix: - case EOpVectorTimesScalar: - return true; - default: - return false; + 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 -// bool TIntermOperator::isConstructor() const +{ + return (mOp == EOpConstruct); +} + +bool TIntermOperator::isFunctionCall() const { switch (mOp) { - case EOpConstructVec2: - 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: - case EOpConstructIVec3: - case EOpConstructIVec4: - case EOpConstructInt: - case EOpConstructUVec2: - case EOpConstructUVec3: - case EOpConstructUVec4: - case EOpConstructUInt: - case EOpConstructBVec2: - case EOpConstructBVec3: - case EOpConstructBVec4: - case EOpConstructBool: - case EOpConstructStruct: - return true; - default: - return false; + case EOpCallFunctionInAST: + case EOpCallBuiltInFunction: + case EOpCallInternalRawFunction: + return true; + default: + return false; } } -// -// Make sure the type of a unary operator is appropriate for its -// combination of operation and operand type. -// -void TIntermUnary::promote(const TType *funcReturnType) +TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right) { - switch (mOp) + if (left.isMatrix()) { - case EOpFloatBitsToInt: - case EOpFloatBitsToUint: - case EOpIntBitsToFloat: - case EOpUintBitsToFloat: - case EOpPackSnorm2x16: - case EOpPackUnorm2x16: - case EOpPackHalf2x16: - case EOpUnpackSnorm2x16: - case EOpUnpackUnorm2x16: - mType.setPrecision(EbpHigh); - break; - case EOpUnpackHalf2x16: - mType.setPrecision(EbpMedium); - break; - default: - setType(mOperand->getType()); + if (right.isMatrix()) + { + return EOpMatrixTimesMatrix; + } + else + { + if (right.isVector()) + { + return EOpMatrixTimesVector; + } + else + { + return EOpMatrixTimesScalar; + } + } } - - if (funcReturnType != nullptr) + else { - if (funcReturnType->getBasicType() == EbtBool) + if (right.isMatrix()) { - // Bool types should not have precision. - setType(*funcReturnType); + if (left.isVector()) + { + return EOpVectorTimesMatrix; + } + else + { + return EOpMatrixTimesScalar; + } } else { - // Precision of the node has been set based on the operand. - setTypePreservePrecision(*funcReturnType); + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMul; + } + else + { + return EOpVectorTimesScalar; + } } } +} - if (mOperand->getQualifier() == EvqConst) - mType.setQualifier(EvqConst); +TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right) +{ + if (left.isMatrix()) + { + if (right.isMatrix()) + { + return EOpMatrixTimesMatrixAssign; + } + else + { + // right should be scalar, but this may not be validated yet. + return EOpMatrixTimesScalarAssign; + } + } else - mType.setQualifier(EvqTemporary); + { + if (right.isMatrix()) + { + // Left should be a vector, but this may not be validated yet. + return EOpVectorTimesMatrixAssign; + } + else + { + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMulAssign; + } + else + { + // left should be vector and right should be scalar, but this may not be validated + // yet. + return EOpVectorTimesScalarAssign; + } + } + } } // -// Establishes the type of the resultant operation, as well as -// makes the operator the correct one for the operands. -// -// For lots of operations it should already be established that the operand -// combination is valid, but returns false if operator can't work on operands. +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. // -bool TIntermBinary::promote(TInfoSink &infoSink) +void TIntermUnary::promote() { - ASSERT(mLeft->isArray() == mRight->isArray()); + if (mOp == EOpArrayLength) + { + // Special case: the qualifier of .length() doesn't depend on the operand qualifier. + setType(TType(EbtInt, EbpUndefined, EvqConst)); + return; + } - // - // Base assumption: just make the type the same as the left - // operand. Then only deviations from this need be coded. - // - setType(mLeft->getType()); + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; - // The result gets promoted to the highest precision. - TPrecision higherPrecision = GetHigherPrecision( - mLeft->getPrecision(), mRight->getPrecision()); - getTypePointer()->setPrecision(higherPrecision); + unsigned char operandPrimarySize = + static_cast(mOperand->getType().getNominalSize()); + switch (mOp) + { + case EOpFloatBitsToInt: + setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpFloatBitsToUint: + setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + setType(TType(EbtUInt, EbpHigh, resultQualifier)); + break; + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + setType(TType(EbtFloat, EbpHigh, resultQualifier, 2)); + break; + case EOpUnpackHalf2x16: + setType(TType(EbtFloat, EbpMedium, resultQualifier, 2)); + break; + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + setType(TType(EbtFloat, EbpMedium, resultQualifier, 4)); + break; + case EOpAny: + case EOpAll: + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + case EOpLength: + case EOpDeterminant: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier)); + break; + case EOpTranspose: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier, + static_cast(mOperand->getType().getRows()), + static_cast(mOperand->getType().getCols()))); + break; + case EOpIsInf: + case EOpIsNan: + setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize)); + break; + case EOpBitfieldReverse: + setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpBitCount: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + case EOpFindLSB: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + case EOpFindMSB: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + default: + setType(mOperand->getType()); + mType.setQualifier(resultQualifier); + break; + } +} + +TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector &swizzleOffsets) + : TIntermTyped(TType(EbtFloat, EbpUndefined)), + mOperand(operand), + mSwizzleOffsets(swizzleOffsets) +{ + ASSERT(mSwizzleOffsets.size() <= 4); + promote(); +} + +TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand) + : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false) +{ + promote(); +} + +TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right) + : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false) +{ + promote(); +} + +TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line) + : TIntermNode(), mSymbol(symbol) +{ + ASSERT(symbol); + setLine(line); +} + +TIntermTernary::TIntermTernary(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) + : TIntermTyped(trueExpression->getType()), + mCondition(cond), + mTrueExpression(trueExpression), + mFalseExpression(falseExpression) +{ + getTypePointer()->setQualifier( + TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression)); +} + +TIntermLoop::TIntermLoop(TLoopType type, + TIntermNode *init, + TIntermTyped *cond, + TIntermTyped *expr, + TIntermBlock *body) + : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body) +{ + // Declaration nodes with no children can appear if all the declarators just added constants to + // the symbol table instead of generating code. They're no-ops so don't add them to the tree. + if (mInit && mInit->getAsDeclarationNode() && + mInit->getAsDeclarationNode()->getSequence()->empty()) + { + mInit = nullptr; + } +} + +TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB) + : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB) +{ + // Prune empty false blocks so that there won't be unnecessary operations done on it. + if (mFalseBlock && mFalseBlock->getSequence()->empty()) + { + mFalseBlock = nullptr; + } +} + +TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList) + : TIntermNode(), mInit(init), mStatementList(statementList) +{ + ASSERT(mStatementList); +} + +void TIntermSwitch::setStatementList(TIntermBlock *statementList) +{ + ASSERT(statementList); + mStatementList = statementList; +} + +// static +TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) +{ + if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst && + falseExpression->getQualifier() == EvqConst) + { + return EvqConst; + } + return EvqTemporary; +} + +TIntermTyped *TIntermTernary::fold() +{ + if (mCondition->getAsConstantUnion()) + { + if (mCondition->getAsConstantUnion()->getBConst(0)) + { + mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier()); + return mTrueExpression; + } + else + { + mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier()); + return mFalseExpression; + } + } + return this; +} + +void TIntermSwizzle::promote() +{ + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; + + auto numFields = mSwizzleOffsets.size(); + setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier, + static_cast(numFields))); +} + +bool TIntermSwizzle::hasDuplicateOffsets() const +{ + int offsetCount[4] = {0u, 0u, 0u, 0u}; + for (const auto offset : mSwizzleOffsets) + { + offsetCount[offset]++; + if (offsetCount[offset] > 1) + { + return true; + } + } + return false; +} + +bool TIntermSwizzle::offsetsMatch(int offset) const +{ + return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset; +} + +void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const +{ + for (const int offset : mSwizzleOffsets) + { + switch (offset) + { + case 0: + *out << "x"; + break; + case 1: + *out << "y"; + break; + case 2: + *out << "z"; + break; + case 3: + *out << "w"; + break; + default: + UNREACHABLE(); + } + } +} + +TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion, + const TIntermTyped *left, + const TIntermTyped *right) +{ + // 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 EvqTemporary; + } + return EvqConst; +} + +// Establishes the type of the result of the binary operation. +void TIntermBinary::promote() +{ + ASSERT(!isMultiplication() || + mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType())); + + // Comma is handled as a special case. Note that the comma node qualifier depends on the shader + // version and so is not being set here. + if (mOp == EOpComma) + { + setType(mRight->getType()); + return; + } + + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + setType(mLeft->getType()); TQualifier resultQualifier = EvqConst; // Binary operations results in temporary variables unless both @@ -571,8 +1087,56 @@ bool TIntermBinary::promote(TInfoSink &infoSink) getTypePointer()->setQualifier(EvqTemporary); } - const int nominalSize = - std::max(mLeft->getNominalSize(), mRight->getNominalSize()); + // Handle indexing ops. + switch (mOp) + { + case EOpIndexDirect: + case EOpIndexIndirect: + if (mLeft->isArray()) + { + mType.toArrayElementType(); + } + else if (mLeft->isMatrix()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier, + static_cast(mLeft->getRows()))); + } + else if (mLeft->isVector()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier)); + } + else + { + UNREACHABLE(); + } + return; + case EOpIndexDirectStruct: + { + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + case EOpIndexDirectInterfaceBlock: + { + const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + default: + break; + } + + ASSERT(mLeft->isArray() == mRight->isArray()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // // All scalars or structs. Code after this test assumes this case is removed! @@ -581,316 +1145,319 @@ bool TIntermBinary::promote(TInfoSink &infoSink) { switch (mOp) { - // - // Promote to conditional - // - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - setType(TType(EbtBool, EbpUndefined)); - break; + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; - // - // And and Or operate on conditionals - // - case EOpLogicalAnd: - case EOpLogicalXor: - case EOpLogicalOr: - ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); - setType(TType(EbtBool, EbpUndefined)); - break; + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalXor: + case EOpLogicalOr: + ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; - default: - break; + default: + break; } - return true; + return; } // If we reach here, at least one of the operands is vector or matrix. // The other operand could be a scalar, vector, or matrix. - // Can these two operands be combined? - // TBasicType basicType = mLeft->getBasicType(); + switch (mOp) { - case EOpMul: - if (!mLeft->isMatrix() && mRight->isMatrix()) - { - if (mLeft->isVector()) - { - mOp = EOpVectorTimesMatrix; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(mRight->getCols()), 1)); - } - else + case EOpMul: + break; + case EOpMatrixTimesScalar: + if (mRight->isMatrix()) { - mOp = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, resultQualifier, static_cast(mRight->getCols()), static_cast(mRight->getRows()))); } - } - else if (mLeft->isMatrix() && !mRight->isMatrix()) - { - if (mRight->isVector()) - { - mOp = EOpMatrixTimesVector; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(mLeft->getRows()), 1)); - } - else - { - mOp = EOpMatrixTimesScalar; - } - } - else if (mLeft->isMatrix() && mRight->isMatrix()) - { - mOp = EOpMatrixTimesMatrix; + break; + case EOpMatrixTimesVector: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast(mLeft->getRows()), 1)); + break; + case EOpMatrixTimesMatrix: setType(TType(basicType, higherPrecision, resultQualifier, static_cast(mRight->getCols()), static_cast(mLeft->getRows()))); + break; + case EOpVectorTimesScalar: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast(nominalSize), 1)); + break; + case EOpVectorTimesMatrix: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast(mRight->getCols()), 1)); + break; + case EOpMulAssign: + case EOpVectorTimesScalarAssign: + case EOpVectorTimesMatrixAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType())); + break; + case EOpAssign: + case EOpInitialize: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + { + const int secondarySize = + std::max(mLeft->getSecondarySize(), mRight->getSecondarySize()); + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast(nominalSize), + static_cast(secondarySize))); + ASSERT(!mLeft->isArray() && !mRight->isArray()); + break; } - else if (!mLeft->isMatrix() && !mRight->isMatrix()) - { - if (mLeft->isVector() && mRight->isVector()) - { - // leave as component product - } - else if (mLeft->isVector() || mRight->isVector()) - { - mOp = EOpVectorTimesScalar; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(nominalSize), 1)); - } - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Missing elses"); - return false; - } + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; - if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) - { - return false; - } - break; + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + case EOpIndexDirectStruct: + // These ops should be already fully handled. + UNREACHABLE(); + break; + default: + UNREACHABLE(); + break; + } +} - case EOpMulAssign: - if (!mLeft->isMatrix() && mRight->isMatrix()) +const TConstantUnion *TIntermConstantUnion::foldIndexing(int index) +{ + if (isArray()) + { + ASSERT(index < static_cast(getType().getOutermostArraySize())); + TType arrayElementType = getType(); + arrayElementType.toArrayElementType(); + size_t arrayElementSize = arrayElementType.getObjectSize(); + return &mUnionArrayPointer[arrayElementSize * index]; + } + else if (isMatrix()) + { + ASSERT(index < getType().getCols()); + int size = getType().getRows(); + return &mUnionArrayPointer[size * index]; + } + else if (isVector()) + { + ASSERT(index < getType().getNominalSize()); + return &mUnionArrayPointer[index]; + } + else + { + UNREACHABLE(); + return nullptr; + } +} + +TIntermTyped *TIntermSwizzle::fold() +{ + TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); + if (operandConstant == nullptr) + { + return this; + } + + TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()]; + for (size_t i = 0; i < mSwizzleOffsets.size(); ++i) + { + constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i)); + } + return CreateFoldedNode(constArray, this, mType.getQualifier()); +} + +TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics) +{ + TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion(); + TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion(); + switch (mOp) + { + case EOpComma: { - if (mLeft->isVector()) + if (mLeft->hasSideEffects()) { - mOp = EOpVectorTimesMatrixAssign; - } - else - { - return false; + return this; } + mRight->getTypePointer()->setQualifier(mType.getQualifier()); + return mRight; } - else if (mLeft->isMatrix() && !mRight->isMatrix()) + case EOpIndexDirect: { - if (mRight->isVector()) + if (leftConstant == nullptr || rightConstant == nullptr) { - return false; + return this; } - else + int index = rightConstant->getIConst(0); + + const TConstantUnion *constArray = leftConstant->foldIndexing(index); + if (!constArray) { - mOp = EOpMatrixTimesScalarAssign; + return this; } + return CreateFoldedNode(constArray, this, mType.getQualifier()); } - else if (mLeft->isMatrix() && mRight->isMatrix()) + case EOpIndexDirectStruct: { - mOp = EOpMatrixTimesMatrixAssign; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(mRight->getCols()), - static_cast(mLeft->getRows()))); - } - else if (!mLeft->isMatrix() && !mRight->isMatrix()) - { - if (mLeft->isVector() && mRight->isVector()) + if (leftConstant == nullptr || rightConstant == nullptr) { - // leave as component product + return this; } - else if (mLeft->isVector() || mRight->isVector()) + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + size_t index = static_cast(rightConstant->getIConst(0)); + + size_t previousFieldsSize = 0; + for (size_t i = 0; i < index; ++i) { - if (!mLeft->isVector()) - return false; - mOp = EOpVectorTimesScalarAssign; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(mLeft->getNominalSize()), 1)); + previousFieldsSize += fields[i]->type()->getObjectSize(); } - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Missing elses"); - return false; - } - if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) - { - return false; + const TConstantUnion *constArray = leftConstant->getUnionArrayPointer(); + return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier()); } - break; - - case EOpAssign: - case EOpInitialize: - // No more additional checks are needed. - ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && - (mLeft->getSecondarySize() == mRight->getSecondarySize())); - break; - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpIMod: - case EOpBitShiftLeft: - case EOpBitShiftRight: - case EOpBitwiseAnd: - case EOpBitwiseXor: - case EOpBitwiseOr: - case EOpAddAssign: - case EOpSubAssign: - case EOpDivAssign: - case EOpIModAssign: - case EOpBitShiftLeftAssign: - case EOpBitShiftRightAssign: - case EOpBitwiseAndAssign: - case EOpBitwiseXorAssign: - case EOpBitwiseOrAssign: - if ((mLeft->isMatrix() && mRight->isVector()) || - (mLeft->isVector() && mRight->isMatrix())) - { - return false; - } - - // Are the sizes compatible? - if (mLeft->getNominalSize() != mRight->getNominalSize() || - mLeft->getSecondarySize() != mRight->getSecondarySize()) - { - // If the nominal sizes of operands do not match: - // One of them must be a scalar. - if (!mLeft->isScalar() && !mRight->isScalar()) - return false; - - // In the case of compound assignment other than multiply-assign, - // the right side needs to be a scalar. Otherwise a vector/matrix - // would be assigned to a scalar. A scalar can't be shifted by a - // vector either. - if (!mRight->isScalar() && - (isAssignment() || - mOp == EOpBitShiftLeft || - mOp == EOpBitShiftRight)) - return false; - } - + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + // Can never be constant folded. + return this; + default: { - const int secondarySize = std::max( - mLeft->getSecondarySize(), mRight->getSecondarySize()); - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast(nominalSize), - static_cast(secondarySize))); - if (mLeft->isArray()) + if (leftConstant == nullptr || rightConstant == nullptr) { - ASSERT(mLeft->getArraySize() == mRight->getArraySize()); - mType.setArraySize(mLeft->getArraySize()); + return this; + } + TConstantUnion *constArray = + leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine()); + if (!constArray) + { + return this; } - } - break; - - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && - (mLeft->getSecondarySize() == mRight->getSecondarySize())); - setType(TType(EbtBool, EbpUndefined)); - break; - default: - return false; + // Nodes may be constant folded without being qualified as constant. + return CreateFoldedNode(constArray, this, mType.getQualifier()); + } } - return true; } -TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink) +TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics) { - TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion(); - TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion(); - if (leftConstant == nullptr || rightConstant == nullptr) - { - return nullptr; - } - TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink); + TConstantUnion *constArray = nullptr; - // Nodes may be constant folded without being qualified as constant. - TQualifier resultQualifier = EvqConst; - if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) + if (mOp == EOpArrayLength) { - resultQualifier = EvqTemporary; + // The size of runtime-sized arrays may only be determined at runtime. + if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray()) + { + return this; + } + constArray = new TConstantUnion[1]; + constArray->setIConst(mOperand->getOutermostArraySize()); } - return CreateFoldedNode(constArray, this, resultQualifier); -} - -TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) -{ - TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); - if (operandConstant == nullptr) + else { - return nullptr; - } + TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); + if (operandConstant == nullptr) + { + return this; + } - TConstantUnion *constArray = nullptr; - switch (mOp) + 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: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + constArray = operandConstant->foldUnaryNonComponentWise(mOp); + break; + default: + constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics); + break; + } + } + if (constArray == nullptr) { - 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; + return this; } // Nodes may be constant folded without being qualified as constant. - TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary; - return CreateFoldedNode(constArray, this, resultQualifier); + return CreateFoldedNode(constArray, this, mType.getQualifier()); } -TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) +TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics) { // Make sure that all params are constant before actual constant folding. for (auto *param : *getSequence()) { if (param->getAsConstantUnion() == nullptr) { - return nullptr; + return this; } } TConstantUnion *constArray = nullptr; if (isConstructor()) - constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink); + constArray = TIntermConstantUnion::FoldAggregateConstructor(this); else - constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink); + constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics); // Nodes may be constant folded without being qualified as constant. - TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary; - return CreateFoldedNode(constArray, this, resultQualifier); + return CreateFoldedNode(constArray, this, getQualifier()); } // @@ -899,15 +1466,15 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) // // Returns the constant value to keep using or nullptr. // -TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, + TIntermConstantUnion *rightNode, + TDiagnostics *diagnostics, + const TSourceLoc &line) { const TConstantUnion *leftArray = getUnionArrayPointer(); const TConstantUnion *rightArray = rightNode->getUnionArrayPointer(); - if (!leftArray) - return nullptr; - if (!rightArray) - return nullptr; + ASSERT(leftArray && rightArray); size_t objectSize = getType().getObjectSize(); @@ -919,48 +1486,45 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1) { // for a case like float f = 1.2 + vec4(2, 3, 4, 5); - leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize()); + leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize()); objectSize = rightNode->getType().getObjectSize(); } TConstantUnion *resultArray = nullptr; - switch(op) + 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; + case EOpAdd: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line); + break; + case EOpSub: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line); + break; - 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; + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line); + break; - case EOpMatrixTimesMatrix: + case EOpMatrixTimesMatrix: { - if (getType().getBasicType() != EbtFloat || - rightNode->getBasicType() != EbtFloat) - { - infoSink.info.message( - EPrefixInternalError, getLine(), - "Constant Folding cannot be done for matrix multiply"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat); - const int leftCols = getCols(); - const int leftRows = getRows(); - const int rightCols = rightNode->getType().getCols(); - const int rightRows = rightNode->getType().getRows(); + 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; @@ -975,94 +1539,155 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn resultArray[resultRows * column + row].setFConst( resultArray[resultRows * column + row].getFConst() + leftArray[i * leftRows + row].getFConst() * - rightArray[column * rightRows + i].getFConst()); + rightArray[column * rightRows + i].getFConst()); } } } } break; - case EOpDiv: - case EOpIMod: + case EOpDiv: + case EOpIMod: { resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { - case EbtFloat: - if (rightArray[i] == 0.0f) - { - infoSink.info.message(EPrefixWarning, getLine(), - "Divide by zero error during constant folding"); - resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); - } - else + case EbtFloat: { ASSERT(op == EOpDiv); - resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst()); - } - break; - - 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) + float dividend = leftArray[i].getFConst(); + float divisor = rightArray[i].getFConst(); + if (divisor == 0.0f) + { + if (dividend == 0.0f) + { + diagnostics->warning( + getLine(), + "Zero divided by zero during constant folding generated NaN", + "/"); + resultArray[i].setFConst(std::numeric_limits::quiet_NaN()); + } + else + { + diagnostics->warning(getLine(), + "Divide by zero during constant folding", "/"); + bool negativeResult = + std::signbit(dividend) != std::signbit(divisor); + resultArray[i].setFConst( + negativeResult ? -std::numeric_limits::infinity() + : std::numeric_limits::infinity()); + } + } + else if (gl::isInf(dividend) && gl::isInf(divisor)) { - resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst()); + diagnostics->warning(getLine(), + "Infinity divided by infinity during constant " + "folding generated NaN", + "/"); + resultArray[i].setFConst(std::numeric_limits::quiet_NaN()); } else { - ASSERT(op == EOpIMod); - resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst()); + float result = dividend / divisor; + if (!gl::isInf(dividend) && gl::isInf(result)) + { + diagnostics->warning( + getLine(), "Constant folded division overflowed to infinity", + "/"); + } + resultArray[i].setFConst(result); } + break; } - break; + case EbtInt: + if (rightArray[i] == 0) + { + diagnostics->warning( + getLine(), "Divide by zero error during constant folding", "/"); + resultArray[i].setIConst(INT_MAX); + } + else + { + int lhs = leftArray[i].getIConst(); + int divisor = rightArray[i].getIConst(); + if (op == EOpDiv) + { + // Check for the special case where the minimum representable number + // is + // divided by -1. If left alone this leads to integer overflow in + // C++. + // ESSL 3.00.6 section 4.1.3 Integers: + // "However, for the case where the minimum representable value is + // divided by -1, it is allowed to return either the minimum + // representable value or the maximum representable value." + if (lhs == -0x7fffffff - 1 && divisor == -1) + { + resultArray[i].setIConst(0x7fffffff); + } + else + { + resultArray[i].setIConst(lhs / divisor); + } + } + else + { + ASSERT(op == EOpIMod); + if (lhs < 0 || divisor < 0) + { + // ESSL 3.00.6 section 5.9: Results of modulus are undefined + // when + // either one of the operands is negative. + diagnostics->warning(getLine(), + "Negative modulus operator operand " + "encountered during constant folding", + "%"); + resultArray[i].setIConst(0); + } + else + { + resultArray[i].setIConst(lhs % divisor); + } + } + } + break; - 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) + case EbtUInt: + if (rightArray[i] == 0) { - resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst()); + diagnostics->warning( + getLine(), "Divide by zero error during constant folding", "/"); + resultArray[i].setUConst(UINT_MAX); } else { - ASSERT(op == EOpIMod); - resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst()); + if (op == EOpDiv) + { + resultArray[i].setUConst(leftArray[i].getUConst() / + rightArray[i].getUConst()); + } + else + { + ASSERT(op == EOpIMod); + resultArray[i].setUConst(leftArray[i].getUConst() % + rightArray[i].getUConst()); + } } - } - break; + break; - default: - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant folding cannot be done for \"/\""); - return nullptr; + default: + UNREACHABLE(); + return nullptr; } } } break; - case EOpMatrixTimesVector: + case EOpMatrixTimesVector: { - if (rightNode->getBasicType() != EbtFloat) - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant Folding cannot be done for matrix times vector"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(rightNode->getBasicType() == EbtFloat); const int matrixCols = getCols(); const int matrixRows = getRows(); @@ -1074,22 +1699,19 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn resultArray[matrixRow].setFConst(0.0f); for (int col = 0; col < matrixCols; col++) { - resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() + - leftArray[col * matrixRows + matrixRow].getFConst() * - rightArray[col].getFConst()); + resultArray[matrixRow].setFConst( + resultArray[matrixRow].getFConst() + + leftArray[col * matrixRows + matrixRow].getFConst() * + rightArray[col].getFConst()); } } } break; - case EOpVectorTimesMatrix: + case EOpVectorTimesMatrix: { - if (getType().getBasicType() != EbtFloat) - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant Folding cannot be done for vector times matrix"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(getType().getBasicType() == EbtFloat); const int matrixCols = rightNode->getType().getCols(); const int matrixRows = rightNode->getType().getRows(); @@ -1101,15 +1723,16 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn resultArray[matrixCol].setFConst(0.0f); for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) { - resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() + - leftArray[matrixRow].getFConst() * - rightArray[matrixCol * matrixRows + matrixRow].getFConst()); + resultArray[matrixCol].setFConst( + resultArray[matrixCol].getFConst() + + leftArray[matrixRow].getFConst() * + rightArray[matrixCol * matrixRows + matrixRow].getFConst()); } } } break; - case EOpLogicalAnd: + case EOpLogicalAnd: { resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) @@ -1119,7 +1742,7 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn } break; - case EOpLogicalOr: + case EOpLogicalOr: { resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) @@ -1129,79 +1752,74 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn } break; - case EOpLogicalXor: + case EOpLogicalXor: { + ASSERT(getType().getBasicType() == EbtBool); 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; - } + resultArray[i].setBConst(leftArray[i] != rightArray[i]); } } 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 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] = + TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line); + break; + case EOpBitShiftRight: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line); + break; - case EOpLessThan: - ASSERT(objectSize == 1); - resultArray = new TConstantUnion[1]; - resultArray->setBConst(*leftArray < *rightArray); - 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 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 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 EOpGreaterThanEqual: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(!(*leftArray < *rightArray)); + break; - case EOpEqual: - case EOpNotEqual: + case EOpEqual: + case EOpNotEqual: { resultArray = new TConstantUnion[1]; - bool equal = true; + bool equal = true; for (size_t i = 0; i < objectSize; i++) { if (leftArray[i] != rightArray[i]) @@ -1221,38 +1839,29 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Invalid operator for constant folding"); - return nullptr; + default: + UNREACHABLE(); + 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) +// The fold functions do operations on a constant at GLSL compile time, without generating run-time +// code. Returns the constant value to keep using. Nullptr should not be returned. +TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op) { - // - // Do operations where the return type has a different number of components compared to the operand type. - // + // Do operations where the return type may have a different number of components compared to the + // operand type. const TConstantUnion *operandArray = getUnionArrayPointer(); - if (!operandArray) - return nullptr; + ASSERT(operandArray); - size_t objectSize = getType().getObjectSize(); + size_t objectSize = getType().getObjectSize(); TConstantUnion *resultArray = nullptr; switch (op) { - case EOpAny: - if (getType().getBasicType() == EbtBool) - { + case EOpAny: + ASSERT(getType().getBasicType() == EbtBool); resultArray = new TConstantUnion(); resultArray->setBConst(false); for (size_t i = 0; i < objectSize; i++) @@ -1264,16 +1873,9 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator } } break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpAll: - if (getType().getBasicType() == EbtBool) - { + case EOpAll: + ASSERT(getType().getBasicType() == EbtBool); resultArray = new TConstantUnion(); resultArray->setBConst(true); for (size_t i = 0; i < objectSize; i++) @@ -1285,89 +1887,55 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator } } break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpLength: - if (getType().getBasicType() == EbtFloat) - { + case EOpLength: + ASSERT(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) + case EOpTranspose: { + ASSERT(getType().getBasicType() == EbtFloat); resultArray = new TConstantUnion[objectSize]; angle::Matrix result = - GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose(); + GetMatrix(operandArray, getType().getRows(), getType().getCols()).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) + case EOpDeterminant: { + ASSERT(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) + case EOpInverse: { + ASSERT(getType().getBasicType() == EbtFloat); unsigned int size = getType().getNominalSize(); ASSERT(size >= 2 && size <= 4); - resultArray = new TConstantUnion[objectSize]; + 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) - { + case EOpPackSnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); ASSERT(getType().getNominalSize() == 2); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + 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) + case EOpUnpackSnorm2x16: { + ASSERT(getType().getBasicType() == EbtUInt); resultArray = new TConstantUnion[2]; float f1, f2; gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2); @@ -1375,29 +1943,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator 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) - { + case EOpPackUnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); ASSERT(getType().getNominalSize() == 2); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + 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) + case EOpUnpackUnorm2x16: { + ASSERT(getType().getBasicType() == EbtUInt); resultArray = new TConstantUnion[2]; float f1, f2; gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2); @@ -1405,304 +1962,320 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator resultArray[1].setFConst(f2); break; } - else + + case EOpPackHalf2x16: + ASSERT(getType().getBasicType() == EbtFloat); + ASSERT(getType().getNominalSize() == 2); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + break; + + case EOpUnpackHalf2x16: { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; + ASSERT(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; } - case EOpPackHalf2x16: - if (getType().getBasicType() == EbtFloat) + case EOpPackUnorm4x8: { - ASSERT(getType().getNominalSize() == 2); + ASSERT(getType().getBasicType() == EbtFloat); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + resultArray->setUConst( + gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(), + operandArray[2].getFConst(), operandArray[3].getFConst())); break; } - else + case EOpPackSnorm4x8: { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; + ASSERT(getType().getBasicType() == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(), + operandArray[2].getFConst(), operandArray[3].getFConst())); + break; } - - case EOpUnpackHalf2x16: - if (getType().getBasicType() == EbtUInt) + case EOpUnpackUnorm4x8: { - resultArray = new TConstantUnion[2]; - float f1, f2; - gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2); - resultArray[0].setFConst(f1); - resultArray[1].setFConst(f2); + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[4]; + float f[4]; + gl::UnpackUnorm4x8(operandArray[0].getUConst(), f); + for (size_t i = 0; i < 4; ++i) + { + resultArray[i].setFConst(f[i]); + } break; } - else + case EOpUnpackSnorm4x8: { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[4]; + float f[4]; + gl::UnpackSnorm4x8(operandArray[0].getUConst(), f); + for (size_t i = 0; i < 4; ++i) + { + resultArray[i].setFConst(f[i]); + } + break; } - break; - default: - break; + default: + UNREACHABLE(); + break; } return resultArray; } -TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op, + TDiagnostics *diagnostics) { - // - // Do unary operations where the return type is the same as operand type. - // + // Do unary operations where each component of the result is computed based on the corresponding + // component of the operand. Also folds normalize, though the divisor in that case takes all + // components into account. const TConstantUnion *operandArray = getUnionArrayPointer(); - if (!operandArray) - return nullptr; + ASSERT(operandArray); size_t objectSize = getType().getObjectSize(); TConstantUnion *resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { - switch(op) + 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()))); + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(-operandArray[i].getFConst()); + break; + case EbtInt: + if (operandArray[i] == std::numeric_limits::min()) + { + // The minimum representable integer doesn't have a positive + // counterpart, rather the negation overflows and in ESSL is supposed to + // wrap back to the minimum representable integer. Make sure that we + // don't actually let the negation overflow, which has undefined + // behavior in C++. + resultArray[i].setIConst(std::numeric_limits::min()); + } + else + { + resultArray[i].setIConst(-operandArray[i].getIConst()); + } + break; + case EbtUInt: + if (operandArray[i] == 0x80000000u) + { + resultArray[i].setUConst(0x80000000u); + } + else + { + resultArray[i].setUConst(static_cast( + -static_cast(operandArray[i].getUConst()))); + } + break; + default: + UNREACHABLE(); + return nullptr; + } 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()))); + 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: + UNREACHABLE(); + return nullptr; + } 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()); + case EOpLogicalNot: + switch (getType().getBasicType()) + { + case EbtBool: + resultArray[i].setBConst(!operandArray[i].getBConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } 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()); + case EOpBitwiseNot: + switch (getType().getBasicType()) + { + case EbtInt: + resultArray[i].setIConst(~operandArray[i].getIConst()); + break; + case EbtUInt: + resultArray[i].setUConst(~operandArray[i].getUConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpRadians: - if (getType().getBasicType() == EbtFloat) - { + case EOpRadians: + ASSERT(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) - { + case EOpDegrees: + ASSERT(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 EOpSin: + foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]); + 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 EOpCos: + foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]); + 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 EOpTan: + foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]); + break; - case EOpAtan: - if (!foldFloatTypeUnary(operandArray[i], &atanf, 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 (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]); + break; - case EOpSinh: - if (!foldFloatTypeUnary(operandArray[i], &sinhf, 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 (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]); + break; - case EOpCosh: - if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpAtan: + foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]); + break; - case EOpTanh: - if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpSinh: + foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]); + break; - case EOpAsinh: - if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpCosh: + foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]); + 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 EOpTanh: + foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]); + 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 EOpAsinh: + foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]); + break; - case EOpAbs: - switch (getType().getBasicType()) - { - case EbtFloat: - resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); + case EOpAcosh: + // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]); break; - case EbtInt: - resultArray[i].setIConst(abs(operandArray[i].getIConst())); + + case EOpAtanh: + // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) >= 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]); break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpSign: - switch (getType().getBasicType()) - { - case EbtFloat: + case EOpAbs: + switch (getType().getBasicType()) { - 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); + case EbtFloat: + resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst(abs(operandArray[i].getIConst())); + break; + default: + UNREACHABLE(); + return nullptr; } break; - case EbtInt: + + case EOpSign: + switch (getType().getBasicType()) { - int iConst = operandArray[i].getIConst(); - int iResult = 0; - if (iConst > 0) - iResult = 1; - else if (iConst < 0) - iResult = -1; - resultArray[i].setIConst(iResult); + 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: + UNREACHABLE(); + return nullptr; } 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 EOpFloor: + foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]); + break; - case EOpTrunc: - if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpTrunc: + foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]); + break; - case EOpRound: - if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpRound: + foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]); + break; - case EOpRoundEven: - if (getType().getBasicType() == EbtFloat) + case EOpRoundEven: { + ASSERT(getType().getBasicType() == EbtFloat); float x = operandArray[i].getFConst(); float result; float fractPart = modff(x, &result); @@ -1713,197 +2286,226 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, 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 EOpCeil: + foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]); + break; - case EOpFract: - if (getType().getBasicType() == EbtFloat) + case EOpFract: { + ASSERT(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) - { + case EOpIsNan: + ASSERT(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) - { + case EOpIsInf: + ASSERT(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) - { + case EOpFloatBitsToInt: + ASSERT(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) - { + case EOpFloatBitsToUint: + ASSERT(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) - { + case EOpIntBitsToFloat: + ASSERT(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) - { + case EOpUintBitsToFloat: + ASSERT(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 EOpExp: + foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]); + 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 EOpLog: + // For log(x), results are undefined if x <= 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + break; - case EOpExp2: - if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpExp2: + foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]); + 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 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 (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + 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 EOpSqrt: + // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + 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 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 (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + resultArray[i].setFConst(1.0f / resultArray[i].getFConst()); + } + break; - case EOpVectorLogicalNot: - if (getType().getBasicType() == EbtBool) - { + case EOpLogicalNotComponentWise: + ASSERT(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) + case EOpNormalize: { - float x = operandArray[i].getFConst(); + ASSERT(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]); + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &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) + case EOpBitfieldReverse: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + uint32_t result = gl::BitfieldReverse(value); + if (getType().getBasicType() == EbtInt) + { + resultArray[i].setIConst(static_cast(result)); + } + else + { + resultArray[i].setUConst(result); + } + break; + } + case EOpBitCount: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + int result = gl::BitCount(value); + resultArray[i].setIConst(result); + break; + } + case EOpFindLSB: { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + resultArray[i].setIConst(gl::FindLSB(value)); + break; + } + case EOpFindMSB: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + int intValue = operandArray[i].getIConst(); + value = static_cast(intValue); + if (intValue < 0) + { + // Look for zero instead of one in value. This also handles the intValue == + // -1 special case, where the return value needs to be -1. + value = ~value; + } + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + resultArray[i].setIConst(gl::FindMSB(value)); + break; + } + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + ASSERT(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; + default: + return nullptr; } } return resultArray; } -bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc, - TInfoSink &infoSink, TConstantUnion *result) const +void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + 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; + ASSERT(getType().getBasicType() == EbtFloat); + result->setFConst(builtinFunc(parameter.getFConst())); } // static -TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate, - TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate) { ASSERT(aggregate->getSequence()->size() > 0u); size_t resultSize = aggregate->getType().getObjectSize(); @@ -1958,7 +2560,7 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate int argumentCols = argumentConstant->getType().getCols(); int argumentRows = argumentConstant->getType().getRows(); int resultCols = aggregate->getType().getCols(); - int resultRows = aggregate->getType().getRows(); + int resultRows = aggregate->getType().getRows(); for (int col = 0; col < resultCols; ++col) { for (int row = 0; row < resultRows; ++row) @@ -2001,664 +2603,728 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate return resultArray; } +bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op) +{ + switch (op) + { + case EOpAtan: + case EOpPow: + case EOpMod: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothStep: + case EOpLdexp: + case EOpMulMatrixComponentWise: + case EOpOuterProduct: + case EOpEqualComponentWise: + case EOpNotEqualComponentWise: + case EOpLessThanComponentWise: + case EOpLessThanEqualComponentWise: + case EOpGreaterThanComponentWise: + case EOpGreaterThanEqualComponentWise: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceforward: + case EOpReflect: + case EOpRefract: + case EOpBitfieldExtract: + case EOpBitfieldInsert: + return true; + default: + return false; + } +} + // static -TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics) { - TOperator op = aggregate->getOp(); - TIntermSequence *sequence = aggregate->getSequence(); - unsigned int paramsCount = static_cast(sequence->size()); - std::vector unionArrays(paramsCount); - std::vector objectSizes(paramsCount); + TOperator op = aggregate->getOp(); + TIntermSequence *arguments = aggregate->getSequence(); + unsigned int argsCount = static_cast(arguments->size()); + std::vector unionArrays(argsCount); + std::vector objectSizes(argsCount); size_t maxObjectSize = 0; TBasicType basicType = EbtVoid; TSourceLoc loc; - for (unsigned int i = 0; i < paramsCount; i++) + for (unsigned int i = 0; i < argsCount; i++) { - TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion(); - ASSERT(paramConstant != nullptr); // Should be checked already. + TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion(); + ASSERT(argConstant != nullptr); // Should be checked already. if (i == 0) { - basicType = paramConstant->getType().getBasicType(); - loc = paramConstant->getLine(); + basicType = argConstant->getType().getBasicType(); + loc = argConstant->getLine(); } - unionArrays[i] = paramConstant->getUnionArrayPointer(); - objectSizes[i] = paramConstant->getType().getObjectSize(); + unionArrays[i] = argConstant->getUnionArrayPointer(); + objectSizes[i] = argConstant->getType().getObjectSize(); if (objectSizes[i] > maxObjectSize) maxObjectSize = objectSizes[i]; } - if (!(*sequence)[0]->getAsTyped()->isMatrix()) + if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct) { - for (unsigned int i = 0; i < paramsCount; i++) + for (unsigned int i = 0; i < argsCount; i++) if (objectSizes[i] != maxObjectSize) unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize); } TConstantUnion *resultArray = nullptr; - if (paramsCount == 2) + + switch (op) { - // - // Binary built-in - // - switch (op) + case EOpAtan: { - case EOpAtan: + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - 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)); - } - } + 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, diagnostics, &resultArray[i]); else - UNREACHABLE(); + resultArray[i].setFConst(atan2f(y, x)); } break; + } - case EOpPow: + case EOpPow: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - 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)); - } - } + 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, diagnostics, &resultArray[i]); + else if (x == 0.0f && y <= 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); else - UNREACHABLE(); + resultArray[i].setFConst(powf(x, y)); } break; + } - case EOpMod: + case EOpMod: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - if (basicType == EbtFloat) - { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) - { - float x = unionArrays[0][i].getFConst(); - float y = unionArrays[1][i].getFConst(); - resultArray[i].setFConst(x - y * floorf(x / y)); - } - } - else - UNREACHABLE(); + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + resultArray[i].setFConst(x - y * floorf(x / y)); } break; + } - case EOpMin: + case EOpMin: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); + 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())); + 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())); + case EbtUInt: + resultArray[i].setUConst( + std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - case EOpMax: + case EOpMax: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); + 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())); + 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())); + case EbtUInt: + resultArray[i].setUConst( + std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - 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(); - } + case EOpStep: + { + ASSERT(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); break; + } - case EOpLessThan: + case EOpLessThanComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst()); + 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()); + 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()); + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() < + unionArrays[1][i].getUConst()); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - case EOpLessThanEqual: + case EOpLessThanEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst()); + 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()); + 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()); + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() <= + unionArrays[1][i].getUConst()); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - case EOpGreaterThan: + case EOpGreaterThanComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst()); + 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()); + 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()); + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() > + unionArrays[1][i].getUConst()); break; - default: + default: UNREACHABLE(); break; - } } } break; - - case EOpGreaterThanEqual: + } + case EOpGreaterThanEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst()); + 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()); + 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()); + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() >= + unionArrays[1][i].getUConst()); break; - default: + default: UNREACHABLE(); break; - } } } - break; + } + break; - case EOpVectorEqual: + case EOpEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst()); + 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()); + 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()); + 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()); + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() == + unionArrays[1][i].getBConst()); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - case EOpVectorNotEqual: + case EOpNotEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) - { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst()); + 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()); + 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()); + 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()); + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() != + unionArrays[1][i].getBConst()); break; - default: + default: UNREACHABLE(); break; - } } } break; + } - case EOpDistance: - if (basicType == EbtFloat) + case EOpDistance: + { + ASSERT(basicType == EbtFloat); + TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize]; + resultArray = new TConstantUnion(); + for (size_t i = 0; i < maxObjectSize; i++) { - 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)); + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + distanceArray[i].setFConst(x - y); } - else - UNREACHABLE(); + resultArray->setFConst(VectorLength(distanceArray, maxObjectSize)); break; + } - case EOpDot: - - if (basicType == EbtFloat) - { - resultArray = new TConstantUnion(); - resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); - } - else - UNREACHABLE(); + case EOpDot: + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); break; - case EOpCross: - if (basicType == EbtFloat && maxObjectSize == 3) - { - 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(); + case EOpCross: + { + ASSERT(basicType == EbtFloat && maxObjectSize == 3); + 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); break; + } - case EOpReflect: - if (basicType == EbtFloat) + case EOpReflect: + { + ASSERT(basicType == EbtFloat); + // 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++) { - // genType reflect (genType I, genType N) : - // For the incident vector I and surface orientation N, returns the reflection direction: - // I - 2 * dot(N, I) * N. - resultArray = new TConstantUnion[maxObjectSize]; - float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); - for (size_t i = 0; i < maxObjectSize; i++) - { - float result = unionArrays[0][i].getFConst() - - 2.0f * dotProduct * unionArrays[1][i].getFConst(); - resultArray[i].setFConst(result); - } + float result = unionArrays[0][i].getFConst() - + 2.0f * dotProduct * unionArrays[1][i].getFConst(); + resultArray[i].setFConst(result); } - else - UNREACHABLE(); break; + } - case EOpMul: - if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() && - (*sequence)[1]->getAsTyped()->isMatrix()) - { - // Perform component-wise matrix multiplication. - resultArray = new TConstantUnion[maxObjectSize]; - int size = (*sequence)[0]->getAsTyped()->getNominalSize(); - angle::Matrix result = - GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size)); - SetUnionArrayFromMatrix(result, resultArray); - } - else - UNREACHABLE(); + case EOpMulMatrixComponentWise: + { + ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() && + (*arguments)[1]->getAsTyped()->isMatrix()); + // Perform component-wise matrix multiplication. + resultArray = new TConstantUnion[maxObjectSize]; + int size = (*arguments)[0]->getAsTyped()->getNominalSize(); + angle::Matrix result = + GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size)); + SetUnionArrayFromMatrix(result, resultArray); break; + } - case EOpOuterProduct: - if (basicType == EbtFloat) - { - size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize(); - size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize(); - resultArray = new TConstantUnion[numRows * numCols]; - angle::Matrix result = - GetMatrix(unionArrays[0], 1, static_cast(numCols)) - .outerProduct(GetMatrix(unionArrays[1], static_cast(numRows), 1)); - SetUnionArrayFromMatrix(result, resultArray); - } - else - UNREACHABLE(); + case EOpOuterProduct: + { + ASSERT(basicType == EbtFloat); + size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize(); + size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize(); + resultArray = new TConstantUnion[numRows * numCols]; + angle::Matrix result = + GetMatrix(unionArrays[0], static_cast(numRows), 1) + .outerProduct(GetMatrix(unionArrays[1], 1, static_cast(numCols))); + SetUnionArrayFromMatrix(result, resultArray); break; - - default: - UNREACHABLE(); - // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above. - return nullptr; } - } - else if (paramsCount == 3) - { - // - // Ternary built-in - // - switch (op) + + case EOpClamp: { - case EOpClamp: + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + switch (basicType) { - switch (basicType) + case EbtFloat: { - 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)); - } + 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, diagnostics, + &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)); - } + } + + 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, diagnostics, + &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)); - } + } + 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, diagnostics, + &resultArray[i]); + else + resultArray[i].setUConst(gl::clamp(x, min, max)); break; - default: + } + default: UNREACHABLE(); break; - } } } break; + } - case EOpMix: + case EOpMix: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - if (basicType == EbtFloat) + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType(); + if (type == 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(); - 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); - } - } + // 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); } - else - UNREACHABLE(); } break; + } - case EOpSmoothStep: + case EOpSmoothStep: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - if (basicType == EbtFloat) + 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) { - 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)); - } - } + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); } else - UNREACHABLE(); + { + // 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; + } - case EOpFaceForward: - if (basicType == EbtFloat) + case EOpLdexp: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - // 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++) + float x = unionArrays[0][i].getFConst(); + int exp = unionArrays[1][i].getIConst(); + if (exp > 128) { - if (dotProduct < 0) - resultArray[i].setFConst(unionArrays[0][i].getFConst()); - else - resultArray[i].setFConst(-unionArrays[0][i].getFConst()); + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); } - } - else - UNREACHABLE(); - break; - - 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++) + else { - 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()); + resultArray[i].setFConst(gl::Ldexp(x, exp)); } } - 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; } - } - return resultArray; -} -// static -TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction) -{ - if (hashFunction == NULL || name.empty()) - return name; - khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); - TStringStream stream; - stream << HASHED_NAME_PREFIX << std::hex << number; - TString hashedName = stream.str(); - return hashedName; -} + case EOpFaceforward: + { + ASSERT(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++) + { + if (dotProduct < 0) + resultArray[i].setFConst(unionArrays[0][i].getFConst()); + else + resultArray[i].setFConst(-unionArrays[0][i].getFConst()); + } + break; + } -void TIntermTraverser::updateTree() -{ - for (size_t ii = 0; ii < mInsertions.size(); ++ii) - { - const NodeInsertMultipleEntry &insertion = mInsertions[ii]; - ASSERT(insertion.parent); - if (!insertion.insertionsAfter.empty()) + case EOpRefract: { - bool inserted = insertion.parent->insertChildNodes(insertion.position + 1, - insertion.insertionsAfter); - ASSERT(inserted); - UNUSED_ASSERTION_VARIABLE(inserted); + ASSERT(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()); + } + break; } - if (!insertion.insertionsBefore.empty()) + case EOpBitfieldExtract: { - bool inserted = - insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore); - ASSERT(inserted); - UNUSED_ASSERTION_VARIABLE(inserted); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; ++i) + { + int offset = unionArrays[1][0].getIConst(); + int bits = unionArrays[2][0].getIConst(); + if (bits == 0) + { + if (aggregate->getBasicType() == EbtInt) + { + resultArray[i].setIConst(0); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + resultArray[i].setUConst(0); + } + } + else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32) + { + UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics, + &resultArray[i]); + } + else + { + // bits can be 32 here, so we need to avoid bit shift overflow. + uint32_t maskMsb = 1u << (bits - 1); + uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset; + if (aggregate->getBasicType() == EbtInt) + { + uint32_t value = static_cast(unionArrays[0][i].getIConst()); + uint32_t resultUnsigned = (value & mask) >> offset; + if ((resultUnsigned & maskMsb) != 0) + { + // The most significant bits (from bits+1 to the most significant bit) + // should be set to 1. + uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits; + resultUnsigned |= higherBitsMask; + } + resultArray[i].setIConst(static_cast(resultUnsigned)); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t value = unionArrays[0][i].getUConst(); + resultArray[i].setUConst((value & mask) >> offset); + } + } + } + break; } - } - for (size_t ii = 0; ii < mReplacements.size(); ++ii) - { - const NodeUpdateEntry &replacement = mReplacements[ii]; - ASSERT(replacement.parent); - bool replaced = replacement.parent->replaceChildNode( - replacement.original, replacement.replacement); - ASSERT(replaced); - UNUSED_ASSERTION_VARIABLE(replaced); - - if (!replacement.originalBecomesChildOfReplacement) + case EOpBitfieldInsert: { - // In AST traversing, a parent is visited before its children. - // 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) + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; ++i) { - NodeUpdateEntry &replacement2 = mReplacements[jj]; - if (replacement2.parent == replacement.original) - replacement2.parent = replacement.replacement; + int offset = unionArrays[2][0].getIConst(); + int bits = unionArrays[3][0].getIConst(); + if (bits == 0) + { + if (aggregate->getBasicType() == EbtInt) + { + int32_t base = unionArrays[0][i].getIConst(); + resultArray[i].setIConst(base); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t base = unionArrays[0][i].getUConst(); + resultArray[i].setUConst(base); + } + } + else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32) + { + UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics, + &resultArray[i]); + } + else + { + // bits can be 32 here, so we need to avoid bit shift overflow. + uint32_t maskMsb = 1u << (bits - 1); + uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset; + uint32_t baseMask = ~insertMask; + if (aggregate->getBasicType() == EbtInt) + { + uint32_t base = static_cast(unionArrays[0][i].getIConst()); + uint32_t insert = static_cast(unionArrays[1][i].getIConst()); + uint32_t resultUnsigned = + (base & baseMask) | ((insert << offset) & insertMask); + resultArray[i].setIConst(static_cast(resultUnsigned)); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t base = unionArrays[0][i].getUConst(); + uint32_t insert = unionArrays[1][i].getUConst(); + resultArray[i].setUConst((base & baseMask) | + ((insert << offset) & insertMask)); + } + } } + break; } - } - 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(); + default: + UNREACHABLE(); + return nullptr; + } + return resultArray; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.h b/src/3rdparty/angle/src/compiler/translator/IntermNode.h index ad500e2b1f..2170916201 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.h +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.h @@ -25,14 +25,27 @@ #include "compiler/translator/Common.h" #include "compiler/translator/ConstantUnion.h" #include "compiler/translator/Operator.h" +#include "compiler/translator/SymbolUniqueId.h" #include "compiler/translator/Types.h" +namespace sh +{ + +class TDiagnostics; + class TIntermTraverser; class TIntermAggregate; +class TIntermBlock; +class TIntermInvariantDeclaration; +class TIntermDeclaration; +class TIntermFunctionPrototype; +class TIntermFunctionDefinition; +class TIntermSwizzle; class TIntermBinary; class TIntermUnary; class TIntermConstantUnion; -class TIntermSelection; +class TIntermTernary; +class TIntermIfElse; class TIntermSwitch; class TIntermCase; class TIntermTyped; @@ -41,8 +54,10 @@ class TIntermLoop; class TInfoSink; class TInfoSinkBase; class TIntermRaw; +class TIntermBranch; class TSymbolTable; +class TFunction; // 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. @@ -79,7 +94,7 @@ class TIntermNode : angle::NonCopyable mLine.first_file = mLine.last_file = 0; mLine.first_line = mLine.last_line = 0; } - virtual ~TIntermNode() { } + virtual ~TIntermNode() {} const TSourceLoc &getLine() const { return mLine; } void setLine(const TSourceLoc &l) { mLine = l; } @@ -87,20 +102,27 @@ class TIntermNode : angle::NonCopyable virtual void traverse(TIntermTraverser *) = 0; virtual TIntermTyped *getAsTyped() { return 0; } virtual TIntermConstantUnion *getAsConstantUnion() { return 0; } + virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; } virtual TIntermAggregate *getAsAggregate() { return 0; } + virtual TIntermBlock *getAsBlock() { return nullptr; } + virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; } + virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() { return nullptr; } + virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; } + virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; } virtual TIntermBinary *getAsBinaryNode() { return 0; } virtual TIntermUnary *getAsUnaryNode() { return 0; } - virtual TIntermSelection *getAsSelectionNode() { return 0; } + virtual TIntermTernary *getAsTernaryNode() { return nullptr; } + virtual TIntermIfElse *getAsIfElseNode() { return nullptr; } virtual TIntermSwitch *getAsSwitchNode() { return 0; } virtual TIntermCase *getAsCaseNode() { return 0; } virtual TIntermSymbol *getAsSymbolNode() { return 0; } virtual TIntermLoop *getAsLoopNode() { return 0; } virtual TIntermRaw *getAsRawNode() { return 0; } + virtual TIntermBranch *getAsBranchNode() { return 0; } // Replace a child node. Return true if |original| is a child // node and it is replaced; otherwise, return false. - virtual bool replaceChildNode( - TIntermNode *original, TIntermNode *replacement) = 0; + virtual bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) = 0; protected: TSourceLoc mLine; @@ -121,12 +143,15 @@ struct TIntermNodePair class TIntermTyped : public TIntermNode { public: - TIntermTyped(const TType &t) : mType(t) { } + TIntermTyped(const TType &t) : mType(t) {} virtual TIntermTyped *deepCopy() const = 0; TIntermTyped *getAsTyped() override { return this; } + // True if executing the expression represented by this node affects state, like values of + // variables. False if the executing the expression only computes its return value without + // affecting state. May return true conservatively. virtual bool hasSideEffects() const = 0; void setType(const TType &t) { mType = t; } @@ -137,6 +162,7 @@ class TIntermTyped : public TIntermNode TBasicType getBasicType() const { return mType.getBasicType(); } TQualifier getQualifier() const { return mType.getQualifier(); } TPrecision getPrecision() const { return mType.getPrecision(); } + TMemoryQualifier getMemoryQualifier() const { return mType.getMemoryQualifier(); } int getCols() const { return mType.getCols(); } int getRows() const { return mType.getRows(); } int getNominalSize() const { return mType.getNominalSize(); } @@ -144,14 +170,16 @@ class TIntermTyped : public TIntermNode bool isInterfaceBlock() const { return mType.isInterfaceBlock(); } bool isMatrix() const { return mType.isMatrix(); } - bool isArray() const { return mType.isArray(); } + bool isArray() const { return mType.isArray(); } bool isVector() const { return mType.isVector(); } bool isScalar() const { return mType.isScalar(); } bool isScalarInt() const { return mType.isScalarInt(); } const char *getBasicString() const { return mType.getBasicString(); } TString getCompleteString() const { return mType.getCompleteString(); } - int getArraySize() const { return mType.getArraySize(); } + unsigned int getOutermostArraySize() const { return mType.getOutermostArraySize(); } + + bool isConstructorWithOnlyConstantUnionParameters(); protected: TType mType; @@ -176,10 +204,7 @@ class TIntermLoop : public TIntermNode TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, - TIntermAggregate *body) - : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false) - { - } + TIntermBlock *body); TIntermLoop *getAsLoopNode() override { return this; } void traverse(TIntermTraverser *it) override; @@ -189,19 +214,19 @@ class TIntermLoop : public TIntermNode TIntermNode *getInit() { return mInit; } TIntermTyped *getCondition() { return mCond; } TIntermTyped *getExpression() { return mExpr; } - TIntermAggregate *getBody() { return mBody; } + TIntermBlock *getBody() { return mBody; } - void setUnrollFlag(bool flag) { mUnrollFlag = flag; } - bool getUnrollFlag() const { return mUnrollFlag; } + void setInit(TIntermNode *init) { mInit = init; } + void setCondition(TIntermTyped *condition) { mCond = condition; } + void setExpression(TIntermTyped *expression) { mExpr = expression; } + void setBody(TIntermBlock *body) { mBody = body; } protected: TLoopType mType; - TIntermNode *mInit; // for-loop initialization - TIntermTyped *mCond; // loop exit condition - TIntermTyped *mExpr; // for-loop expression - TIntermAggregate *mBody; // loop body - - bool mUnrollFlag; // Whether the loop should be unrolled or not. + TIntermNode *mInit; // for-loop initialization + TIntermTyped *mCond; // loop exit condition + TIntermTyped *mExpr; // for-loop expression + TIntermBlock *mBody; // loop body }; // @@ -210,17 +235,16 @@ class TIntermLoop : public TIntermNode class TIntermBranch : public TIntermNode { public: - TIntermBranch(TOperator op, TIntermTyped *e) - : mFlowOp(op), - mExpression(e) { } + TIntermBranch(TOperator op, TIntermTyped *e) : mFlowOp(op), mExpression(e) {} void traverse(TIntermTraverser *it) override; + TIntermBranch *getAsBranchNode() override { return this; } bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; TOperator getFlowOp() { return mFlowOp; } - TIntermTyped* getExpression() { return mExpression; } + TIntermTyped *getExpression() { return mExpression; } -protected: + protected: TOperator mFlowOp; TIntermTyped *mExpression; // non-zero except for "return exp;" statements }; @@ -234,7 +258,7 @@ class TIntermSymbol : public TIntermTyped // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. // If sym comes from per process globalpoolallocator, then it causes increased memory usage // per compile it is essential to use "symbol = sym" to assign to symbol - TIntermSymbol(int id, const TString &symbol, const TType &type) + TIntermSymbol(const TSymbolUniqueId &id, const TString &symbol, const TType &type) : TIntermTyped(type), mId(id), mSymbol(symbol) { } @@ -243,11 +267,10 @@ class TIntermSymbol : public TIntermTyped bool hasSideEffects() const override { return false; } - int getId() const { return mId; } + int getId() const { return mId.get(); } const TString &getSymbol() const { return mSymbol.getString(); } const TName &getName() const { return mSymbol; } - - void setId(int newId) { mId = newId; } + TName &getName() { return mSymbol; } void setInternal(bool internal) { mSymbol.setInternal(internal); } @@ -256,7 +279,7 @@ class TIntermSymbol : public TIntermTyped bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } protected: - int mId; + const TSymbolUniqueId mId; TName mSymbol; private: @@ -269,9 +292,7 @@ class TIntermSymbol : public TIntermTyped class TIntermRaw : public TIntermTyped { public: - TIntermRaw(const TType &type, const TString &rawText) - : TIntermTyped(type), - mRawText(rawText) { } + TIntermRaw(const TType &type, const TString &rawText) : TIntermTyped(type), mRawText(rawText) {} TIntermRaw(const TIntermRaw &) = delete; TIntermTyped *deepCopy() const override @@ -305,6 +326,7 @@ class TIntermConstantUnion : public TIntermTyped TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type) : TIntermTyped(type), mUnionArrayPointer(unionPointer) { + ASSERT(unionPointer); } TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); } @@ -332,6 +354,7 @@ class TIntermConstantUnion : public TIntermTyped void replaceConstantUnion(const TConstantUnion *safeConstantUnion) { + ASSERT(safeConstantUnion); // Previous union pointer freed on pool deallocation. mUnionArrayPointer = safeConstantUnion; } @@ -340,21 +363,27 @@ class TIntermConstantUnion : public TIntermTyped 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); + TConstantUnion *foldBinary(TOperator op, + TIntermConstantUnion *rightNode, + TDiagnostics *diagnostics, + const TSourceLoc &line); + const TConstantUnion *foldIndexing(int index); + TConstantUnion *foldUnaryNonComponentWise(TOperator op); + TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics); - static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate, - TInfoSink &infoSink); - static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink); + static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate); + static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics); protected: // 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; + typedef float (*FloatTypeUnaryFunc)(float); + void foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + TConstantUnion *result) const; TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! }; @@ -366,25 +395,57 @@ class TIntermOperator : public TIntermTyped { public: TOperator getOp() const { return mOp; } - void setOp(TOperator op) { mOp = op; } bool isAssignment() const; bool isMultiplication() const; bool isConstructor() const; + // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific + // ops. + bool isFunctionCall() const; + bool hasSideEffects() const override { return isAssignment(); } protected: - TIntermOperator(TOperator op) - : TIntermTyped(TType(EbtFloat, EbpUndefined)), - mOp(op) {} - TIntermOperator(TOperator op, const TType &type) - : TIntermTyped(type), - mOp(op) {} + TIntermOperator(TOperator op) : TIntermTyped(TType(EbtFloat, EbpUndefined)), mOp(op) {} + TIntermOperator(TOperator op, const TType &type) : TIntermTyped(type), mOp(op) {} TIntermOperator(const TIntermOperator &) = default; - TOperator mOp; + const TOperator mOp; +}; + +// Node for vector swizzles. +class TIntermSwizzle : public TIntermTyped +{ + public: + // This constructor determines the type of the node based on the operand. + TIntermSwizzle(TIntermTyped *operand, const TVector &swizzleOffsets); + + TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); } + + TIntermSwizzle *getAsSwizzleNode() override { return this; }; + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasSideEffects() const override { return mOperand->hasSideEffects(); } + + TIntermTyped *getOperand() { return mOperand; } + void writeOffsetsAsXYZW(TInfoSinkBase *out) const; + + bool hasDuplicateOffsets() const; + bool offsetsMatch(int offset) const; + + TIntermTyped *fold(); + + protected: + TIntermTyped *mOperand; + TVector mSwizzleOffsets; + + private: + void promote(); + + TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private! }; // @@ -393,12 +454,17 @@ class TIntermOperator : public TIntermTyped class TIntermBinary : public TIntermOperator { public: - TIntermBinary(TOperator op) - : TIntermOperator(op), - mAddIndexClamp(false) {} + // This constructor determines the type of the binary node based on the operands and op. + TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right); TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } + static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right); + static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right); + static TQualifier GetCommaQualifier(int shaderVersion, + const TIntermTyped *left, + const TIntermTyped *right); + TIntermBinary *getAsBinaryNode() override { return this; }; void traverse(TIntermTraverser *it) override; bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; @@ -408,24 +474,23 @@ class TIntermBinary : public TIntermOperator return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); } - void setLeft(TIntermTyped *node) { mLeft = node; } - void setRight(TIntermTyped *node) { mRight = node; } TIntermTyped *getLeft() const { return mLeft; } TIntermTyped *getRight() const { return mRight; } - bool promote(TInfoSink &); - TIntermTyped *fold(TInfoSink &infoSink); + TIntermTyped *fold(TDiagnostics *diagnostics); void setAddIndexClamp() { mAddIndexClamp = true; } bool getAddIndexClamp() { return mAddIndexClamp; } protected: - TIntermTyped* mLeft; - TIntermTyped* mRight; + TIntermTyped *mLeft; + TIntermTyped *mRight; // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. bool mAddIndexClamp; private: + void promote(); + TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! }; @@ -435,14 +500,7 @@ class TIntermBinary : public TIntermOperator class TIntermUnary : public TIntermOperator { public: - TIntermUnary(TOperator op, const TType &type) - : TIntermOperator(op, type), - mOperand(NULL), - mUseEmulatedFunction(false) {} - TIntermUnary(TOperator op) - : TIntermOperator(op), - mOperand(NULL), - mUseEmulatedFunction(false) {} + TIntermUnary(TOperator op, TIntermTyped *operand); TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } @@ -452,10 +510,8 @@ class TIntermUnary : public TIntermOperator 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); + TIntermTyped *fold(TDiagnostics *diagnostics); void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } @@ -468,495 +524,394 @@ class TIntermUnary : public TIntermOperator bool mUseEmulatedFunction; private: + void promote(); + TIntermUnary(const TIntermUnary &node); // note: not deleted, just private! }; +class TFunctionSymbolInfo +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TFunctionSymbolInfo(const TSymbolUniqueId &id); + TFunctionSymbolInfo() : mId(nullptr), mKnownToNotHaveSideEffects(false) {} + + TFunctionSymbolInfo(const TFunctionSymbolInfo &info); + TFunctionSymbolInfo &operator=(const TFunctionSymbolInfo &info); + + void setFromFunction(const TFunction &function); + + void setNameObj(const TName &name) { mName = name; } + const TName &getNameObj() const { return mName; } + + const TString &getName() const { return mName.getString(); } + void setName(const TString &name) { mName.setString(name); } + bool isMain() const { return mName.getString() == "main"; } + + void setKnownToNotHaveSideEffects(bool knownToNotHaveSideEffects) + { + mKnownToNotHaveSideEffects = knownToNotHaveSideEffects; + } + bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; } + + void setId(const TSymbolUniqueId &functionId); + const TSymbolUniqueId &getId() const; + + bool isImageFunction() const + { + return getName() == "imageSize" || getName() == "imageLoad" || getName() == "imageStore"; + } + + private: + TName mName; + TSymbolUniqueId *mId; + bool mKnownToNotHaveSideEffects; +}; + typedef TVector TIntermSequence; typedef TVector TQualifierList; +// +// This is just to help yacc. +// +struct TIntermFunctionCallOrMethod +{ + TIntermSequence *arguments; + TIntermNode *thisNode; +}; + +// Interface for node classes that have an arbitrarily sized set of children. +class TIntermAggregateBase +{ + public: + virtual ~TIntermAggregateBase() {} + + virtual TIntermSequence *getSequence() = 0; + virtual const TIntermSequence *getSequence() const = 0; + + bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements); + bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions); + + protected: + TIntermAggregateBase() {} + + bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement); +}; + // // Nodes that operate on an arbitrary sized set of children. // -class TIntermAggregate : public TIntermOperator +class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase { public: - TIntermAggregate() - : TIntermOperator(EOpNull), - mUserDefined(false), - mUseEmulatedFunction(false), - mGotPrecisionFromChildren(false) - { - } - TIntermAggregate(TOperator op) - : TIntermOperator(op), - mUseEmulatedFunction(false), - mGotPrecisionFromChildren(false) - { - } - ~TIntermAggregate() { } + static TIntermAggregate *CreateFunctionCall(const TFunction &func, TIntermSequence *arguments); + + // If using this, ensure that there's a consistent function definition with the same symbol id + // added to the AST. + static TIntermAggregate *CreateFunctionCall(const TType &type, + const TSymbolUniqueId &id, + const TName &name, + TIntermSequence *arguments); + + static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, + TIntermSequence *arguments); + static TIntermAggregate *CreateConstructor(const TType &type, + TIntermSequence *arguments); + static TIntermAggregate *Create(const TType &type, TOperator op, TIntermSequence *arguments); + ~TIntermAggregate() {} // Note: only supported for nodes that can be a part of an expression. TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); } + TIntermAggregate *shallowCopy() const; + 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 - bool hasSideEffects() const override { return true; } - TIntermTyped *fold(TInfoSink &infoSink); - TIntermSequence *getSequence() { return &mSequence; } + bool hasSideEffects() const override; - 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(); } + static bool CanFoldAggregateBuiltInOp(TOperator op); + TIntermTyped *fold(TDiagnostics *diagnostics); - void setUserDefined() { mUserDefined = true; } - bool isUserDefined() const { return mUserDefined; } + TIntermSequence *getSequence() override { return &mArguments; } + const TIntermSequence *getSequence() const override { return &mArguments; } - void setFunctionId(int functionId) { mFunctionId = functionId; } - int getFunctionId() const { return mFunctionId; } + TString getSymbolTableMangledName() const; 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; } + TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; } + const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; } + protected: - TIntermSequence mSequence; - TName mName; - bool mUserDefined; // used for user defined function names - int mFunctionId; + TIntermSequence mArguments; // If set to true, replace the built-in function call with an emulated one - // to work around driver bugs. + // to work around driver bugs. Only for calls mapped to ops other than EOpCall*. bool mUseEmulatedFunction; bool mGotPrecisionFromChildren; + TFunctionSymbolInfo mFunctionInfo; + private: + TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments); + TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private! + + void setTypePrecisionAndQualifier(const TType &type); + + bool areChildrenConstQualified(); + + void setPrecisionFromChildren(); + + void setPrecisionForBuiltInOp(); + + // Returns true if precision was set according to special rules for this built-in. + bool setPrecisionForSpecialBuiltInOp(); + + // Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol + // info needs to be set before calling this. + void setBuiltInFunctionPrecision(); }; -// -// For if tests. -// -class TIntermSelection : public TIntermTyped +// A list of statements. Either the root node which contains declarations and function definitions, +// or a block that can be marked with curly braces {}. +class TIntermBlock : public TIntermNode, public TIntermAggregateBase { public: - TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB) - : TIntermTyped(TType(EbtVoid, EbpUndefined)), - mCondition(cond), - mTrueBlock(trueB), - mFalseBlock(falseB) {} - TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB, - const TType &type) - : TIntermTyped(type), - mCondition(cond), - mTrueBlock(trueB), - mFalseBlock(falseB) {} - - // Note: only supported for ternary operator nodes. - TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); } + TIntermBlock() : TIntermNode() {} + ~TIntermBlock() {} + TIntermBlock *getAsBlock() override { return this; } void traverse(TIntermTraverser *it) override; bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - // Conservatively assume selections have side-effects - bool hasSideEffects() const override { return true; } + // Only intended for initially building the block. + void appendStatement(TIntermNode *statement); - bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } - TIntermNode *getCondition() const { return mCondition; } - TIntermNode *getTrueBlock() const { return mTrueBlock; } - TIntermNode *getFalseBlock() const { return mFalseBlock; } - TIntermSelection *getAsSelectionNode() override { return this; } + TIntermSequence *getSequence() override { return &mStatements; } + const TIntermSequence *getSequence() const override { return &mStatements; } protected: - TIntermTyped *mCondition; - TIntermNode *mTrueBlock; - TIntermNode *mFalseBlock; - - private: - TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private! + TIntermSequence mStatements; }; -// -// Switch statement. -// -class TIntermSwitch : public TIntermNode +// Function prototype. May be in the AST either as a function prototype declaration or as a part of +// a function definition. The type of the node is the function return type. +class TIntermFunctionPrototype : public TIntermTyped, public TIntermAggregateBase { public: - TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList) - : TIntermNode(), - mInit(init), - mStatementList(statementList) + // TODO(oetuaho@nvidia.com): See if TFunctionSymbolInfo could be added to constructor + // parameters. + TIntermFunctionPrototype(const TType &type, const TSymbolUniqueId &id) + : TIntermTyped(type), mFunctionInfo(id) { } + ~TIntermFunctionPrototype() {} + TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; } void traverse(TIntermTraverser *it) override; - bool replaceChildNode( - TIntermNode *original, TIntermNode *replacement) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - TIntermSwitch *getAsSwitchNode() override { return this; } + TIntermTyped *deepCopy() const override + { + UNREACHABLE(); + return nullptr; + } + bool hasSideEffects() const override + { + UNREACHABLE(); + return true; + } - TIntermTyped *getInit() { return mInit; } - TIntermAggregate *getStatementList() { return mStatementList; } - void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; } + // Only intended for initially building the declaration. + void appendParameter(TIntermSymbol *parameter); + + TIntermSequence *getSequence() override { return &mParameters; } + const TIntermSequence *getSequence() const override { return &mParameters; } + + TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; } + const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; } protected: - TIntermTyped *mInit; - TIntermAggregate *mStatementList; + TIntermSequence mParameters; + + TFunctionSymbolInfo mFunctionInfo; }; -// -// Case label. -// -class TIntermCase : public TIntermNode +// Node for function definitions. The prototype child node stores the function header including +// parameters, and the body child node stores the function body. +class TIntermFunctionDefinition : public TIntermNode { public: - TIntermCase(TIntermTyped *condition) - : TIntermNode(), - mCondition(condition) + TIntermFunctionDefinition(TIntermFunctionPrototype *prototype, TIntermBlock *body) + : TIntermNode(), mPrototype(prototype), mBody(body) { + ASSERT(prototype != nullptr); + ASSERT(body != nullptr); } + TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; } void traverse(TIntermTraverser *it) override; - bool replaceChildNode( - TIntermNode *original, TIntermNode *replacement) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - TIntermCase *getAsCaseNode() override { return this; } + TIntermFunctionPrototype *getFunctionPrototype() const { return mPrototype; } + TIntermBlock *getBody() const { return mBody; } - bool hasCondition() const { return mCondition != nullptr; } - TIntermTyped *getCondition() const { return mCondition; } + const TFunctionSymbolInfo *getFunctionSymbolInfo() const + { + return mPrototype->getFunctionSymbolInfo(); + } - protected: - TIntermTyped *mCondition; + private: + TIntermFunctionPrototype *mPrototype; + TIntermBlock *mBody; }; -enum Visit +// Struct, interface block or variable declaration. Can contain multiple variable declarators. +class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase { - PreVisit, - InVisit, - PostVisit + public: + TIntermDeclaration() : TIntermNode() {} + ~TIntermDeclaration() {} + + TIntermDeclaration *getAsDeclarationNode() override { return this; } + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + // Only intended for initially building the declaration. + // The declarator node should be either TIntermSymbol or TIntermBinary with op set to + // EOpInitialize. + void appendDeclarator(TIntermTyped *declarator); + + TIntermSequence *getSequence() override { return &mDeclarators; } + const TIntermSequence *getSequence() const override { return &mDeclarators; } + protected: + TIntermSequence mDeclarators; }; -// -// 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. -// -class TIntermTraverser : angle::NonCopyable +// Specialized declarations for attributing invariance. +class TIntermInvariantDeclaration : public TIntermNode { public: - POOL_ALLOCATOR_NEW_DELETE(); - TIntermTraverser(bool preVisit, bool inVisit, bool postVisit) - : preVisit(preVisit), - inVisit(inVisit), - postVisit(postVisit), - mDepth(0), - mMaxDepth(0), - mTemporaryIndex(nullptr) - { - } - virtual ~TIntermTraverser() {} - - 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); + TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line); - protected: - void incrementDepth(TIntermNode *current) - { - mDepth++; - mMaxDepth = std::max(mMaxDepth, mDepth); - mPath.push_back(current); - } + virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() override { return this; } - void decrementDepth() - { - mDepth--; - mPath.pop_back(); - } + TIntermSymbol *getSymbol() { return mSymbol; } - TIntermNode *getParentNode() - { - return mPath.size() == 0 ? NULL : mPath.back(); - } + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - void pushParentBlock(TIntermAggregate *node); - void incrementParentBlockPos(); - void popParentBlock(); + private: + TIntermSymbol *mSymbol; +}; - bool parentNodeIsBlock() - { - return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node; - } +// For ternary operators like a ? b : c. +class TIntermTernary : public TIntermTyped +{ + public: + TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression); - const bool preVisit; - const bool inVisit; - const bool postVisit; + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - int mDepth; - int mMaxDepth; + TIntermTyped *getCondition() const { return mCondition; } + TIntermTyped *getTrueExpression() const { return mTrueExpression; } + TIntermTyped *getFalseExpression() const { return mFalseExpression; } + TIntermTernary *getAsTernaryNode() override { return this; } - // All the nodes from root to the current node's parent during traversing. - TVector mPath; + TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); } - // To replace a single node with another on the parent node - struct NodeUpdateEntry - { - NodeUpdateEntry(TIntermNode *_parent, - TIntermNode *_original, - TIntermNode *_replacement, - bool _originalBecomesChildOfReplacement) - : parent(_parent), - original(_original), - replacement(_replacement), - originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {} - - TIntermNode *parent; - TIntermNode *original; - TIntermNode *replacement; - bool originalBecomesChildOfReplacement; - }; - - // 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 + bool hasSideEffects() const override { - 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/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(); + return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() || + mFalseExpression->hasSideEffects(); + } + + TIntermTyped *fold(); 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; + TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private! + + static TQualifier DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression); + + TIntermTyped *mCondition; + TIntermTyped *mTrueExpression; + TIntermTyped *mFalseExpression; }; -// 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 +class TIntermIfElse : public TIntermNode { 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() {} + TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB); - void traverseBinary(TIntermBinary *node) override; - void traverseUnary(TIntermUnary *node) override; - void traverseAggregate(TIntermAggregate *node) override; + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - protected: - bool isLValueRequiredHere() const - { - return mOperatorRequiresLValue || mInFunctionCallOutParameter; - } + TIntermTyped *getCondition() const { return mCondition; } + TIntermBlock *getTrueBlock() const { return mTrueBlock; } + TIntermBlock *getFalseBlock() const { return mFalseBlock; } + TIntermIfElse *getAsIfElseNode() override { return this; } - // Return true if the prototype or definition of the function being called has been encountered - // during traversal. - bool isInFunctionMap(const TIntermAggregate *callNode) const; + protected: + TIntermTyped *mCondition; + TIntermBlock *mTrueBlock; + TIntermBlock *mFalseBlock; +}; - 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; } +// +// Switch statement. +// +class TIntermSwitch : public TIntermNode +{ + public: + TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList); - // Add a function encountered during traversal to the function map. - void addToFunctionMap(const TName &name, TIntermSequence *paramSequence); + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - // Return the parameters sequence from the function definition or prototype. - TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode); + TIntermSwitch *getAsSwitchNode() override { return this; } - // Track whether an l-value is required inside a function call. - void setInFunctionCallOutParameter(bool inOutParameter); - bool isInFunctionCallOutParameter() const; + TIntermTyped *getInit() { return mInit; } + TIntermBlock *getStatementList() { return mStatementList; } - bool mOperatorRequiresLValue; - bool mInFunctionCallOutParameter; + // Must be called with a non-null statementList. + void setStatementList(TIntermBlock *statementList); - 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; + protected: + TIntermTyped *mInit; + TIntermBlock *mStatementList; }; // -// For traversing the tree, and computing max depth. -// Takes a maximum depth limit to prevent stack overflow. +// Case label. // -class TMaxDepthTraverser : public TIntermTraverser +class TIntermCase : public TIntermNode { public: - POOL_ALLOCATOR_NEW_DELETE(); - TMaxDepthTraverser(int depthLimit) - : TIntermTraverser(true, true, false), - mDepthLimit(depthLimit) { } + TIntermCase(TIntermTyped *condition) : TIntermNode(), mCondition(condition) {} - 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(); } + void traverse(TIntermTraverser *it) override; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - protected: - bool depthCheck() const { return mMaxDepth < mDepthLimit; } + TIntermCase *getAsCaseNode() override { return this; } - int mDepthLimit; + bool hasCondition() const { return mCondition != nullptr; } + TIntermTyped *getCondition() const { return mCondition; } + + protected: + TIntermTyped *mCondition; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_INTERMNODE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.cpp new file mode 100644 index 0000000000..567e8f7440 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.cpp @@ -0,0 +1,157 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#include "compiler/translator/IntermNodePatternMatcher.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) +{ +} + +// static +bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) +{ + return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && + node->getLeft()->getBasicType() != EbtStruct; +} + +bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr && + !parentNode->getAsBlock()) + { + return true; + } + } + + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + if (node->getRight()->hasSideEffects() && + (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermUnary *node) +{ + if ((mMask & kArrayLengthMethod) != 0) + { + if (node->getOp() == EOpArrayLength) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) +{ + // L-value tracking information is needed to check for dynamic indexing in L-value. + // Traversers that don't track l-values can still use this class and match binary nodes with + // this variation of this method if they don't need to check for dynamic indexing in l-values. + ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0); + return matchInternal(node, parentNode); +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, + TIntermNode *parentNode, + bool isLValueRequiredHere) +{ + if (matchInternal(node, parentNode)) + { + return true; + } + if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0) + { + if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (parentNode != nullptr) + { + TIntermBinary *parentBinary = parentNode->getAsBinaryNode(); + bool parentIsAssignment = + (parentBinary != nullptr && + (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize)); + + if (node->getType().isArray() && !parentIsAssignment && + (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock()) + { + return true; + } + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermTernary *node) +{ + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + return true; + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermDeclaration *node) +{ + if ((mMask & kMultiDeclaration) != 0) + { + if (node->getSequence()->size() > 1) + { + return true; + } + } + if ((mMask & kArrayDeclaration) != 0) + { + if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays()) + { + return true; + } + // Need to check from all declarators whether they are arrays since that may vary between + // declarators. + for (TIntermNode *declarator : *node->getSequence()) + { + if (declarator->getAsTyped()->isArray()) + { + return true; + } + } + } + if ((mMask & kNamelessStructDeclaration) != 0) + { + TIntermTyped *declarator = node->getSequence()->front()->getAsTyped(); + if (declarator->getBasicType() == EbtStruct && + declarator->getType().getStruct()->name() == "") + { + return true; + } + } + return false; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.h b/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.h new file mode 100644 index 0000000000..997fc2ef10 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermNodePatternMatcher.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#ifndef COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_ +#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_ + +namespace sh +{ + +class TIntermAggregate; +class TIntermBinary; +class TIntermDeclaration; +class TIntermNode; +class TIntermTernary; +class TIntermUnary; + +class IntermNodePatternMatcher +{ + public: + static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node); + + enum PatternType + { + // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf + kUnfoldedShortCircuitExpression = 0x0001, + + // Matches expressions that return arrays with the exception of simple statements where a + // constructor or function call result is assigned. + kExpressionReturningArray = 0x0001 << 1, + + // Matches dynamic indexing of vectors or matrices in l-values. + kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2, + + // Matches declarations with more than one declared variables. + kMultiDeclaration = 0x0001 << 3, + + // Matches declarations of arrays. + kArrayDeclaration = 0x0001 << 4, + + // Matches declarations of structs where the struct type does not have a name. + kNamelessStructDeclaration = 0x0001 << 5, + + // Matches array length() method. + kArrayLengthMethod = 0x0001 << 6 + }; + IntermNodePatternMatcher(const unsigned int mask); + + bool match(TIntermUnary *node); + + bool match(TIntermBinary *node, TIntermNode *parentNode); + + // Use this version for checking binary node matches in case you're using flag + // kDynamicIndexingOfVectorOrMatrixInLValue. + bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere); + + bool match(TIntermAggregate *node, TIntermNode *parentNode); + bool match(TIntermTernary *node); + bool match(TIntermDeclaration *node); + + private: + const unsigned int mMask; + + bool matchInternal(TIntermBinary *node, TIntermNode *parentNode); +}; + +} // namespace sh + +#endif diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode_util.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode_util.cpp new file mode 100644 index 0000000000..9f1f596c43 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode_util.cpp @@ -0,0 +1,254 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly +// meant to be used in AST transforms. + +#include "compiler/translator/IntermNode_util.h" + +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +TName GetInternalFunctionName(const char *name) +{ + TString nameStr(name); + TName nameObj(nameStr); + nameObj.setInternal(true); + return nameObj; +} + +const TFunction *LookUpBuiltInFunction(const TString &name, + const TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + TString mangledName = TFunction::GetMangledNameFromCall(name, *arguments); + TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion); + if (symbol) + { + ASSERT(symbol->isFunction()); + return static_cast(symbol); + } + return nullptr; +} + +} // anonymous namespace + +TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TType &returnType, + const char *name, + const TSymbolUniqueId &functionId) +{ + TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId); + functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name)); + return functionNode; +} + +TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TType &returnType, + const char *name, + TIntermBlock *functionBody, + const TSymbolUniqueId &functionId) +{ + TIntermFunctionPrototype *prototypeNode = + CreateInternalFunctionPrototypeNode(returnType, name, functionId); + return new TIntermFunctionDefinition(prototypeNode, functionBody); +} + +TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType, + const char *name, + const TSymbolUniqueId &functionId, + TIntermSequence *arguments) +{ + TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall( + returnType, functionId, GetInternalFunctionName(name), arguments); + return functionNode; +} + +TIntermTyped *CreateZeroNode(const TType &type) +{ + TType constType(type); + constType.setQualifier(EvqConst); + + if (!type.isArray() && type.getBasicType() != EbtStruct) + { + size_t size = constType.getObjectSize(); + TConstantUnion *u = new TConstantUnion[size]; + for (size_t i = 0; i < size; ++i) + { + switch (type.getBasicType()) + { + case EbtFloat: + u[i].setFConst(0.0f); + break; + case EbtInt: + u[i].setIConst(0); + break; + case EbtUInt: + u[i].setUConst(0u); + break; + case EbtBool: + u[i].setBConst(false); + break; + default: + // CreateZeroNode is called by ParseContext that keeps parsing even when an + // error occurs, so it is possible for CreateZeroNode to be called with + // non-basic types. This happens only on error condition but CreateZeroNode + // needs to return a value with the correct type to continue the typecheck. + // That's why we handle non-basic type by setting whatever value, we just need + // the type to be right. + u[i].setIConst(42); + break; + } + } + + TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); + return node; + } + + if (type.getBasicType() == EbtVoid) + { + // Void array. This happens only on error condition, similarly to the case above. We don't + // have a constructor operator for void, so this needs special handling. We'll end up with a + // value without the array type, but that should not be a problem. + while (constType.isArray()) + { + constType.toArrayElementType(); + } + return CreateZeroNode(constType); + } + + TIntermSequence *arguments = new TIntermSequence(); + + if (type.isArray()) + { + TType elementType(type); + elementType.toArrayElementType(); + + size_t arraySize = type.getOutermostArraySize(); + for (size_t i = 0; i < arraySize; ++i) + { + arguments->push_back(CreateZeroNode(elementType)); + } + } + else + { + ASSERT(type.getBasicType() == EbtStruct); + + const TStructure *structure = type.getStruct(); + for (const auto &field : structure->fields()) + { + arguments->push_back(CreateZeroNode(*field->type())); + } + } + + return TIntermAggregate::CreateConstructor(constType, arguments); +} + +TIntermConstantUnion *CreateIndexNode(int index) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +TIntermConstantUnion *CreateBoolNode(bool value) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setBConst(value); + + TType type(EbtBool, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +TIntermSymbol *CreateTempSymbolNode(const TSymbolUniqueId &id, + const TType &type, + TQualifier qualifier) +{ + TInfoSinkBase symbolNameOut; + symbolNameOut << "s" << id.get(); + TString symbolName = symbolNameOut.c_str(); + + TIntermSymbol *node = new TIntermSymbol(id, symbolName, type); + node->setInternal(true); + + ASSERT(qualifier == EvqTemporary || qualifier == EvqConst || qualifier == EvqGlobal); + node->getTypePointer()->setQualifier(qualifier); + + // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created + // symbol. This might need to be done in other places as well. + return node; +} + +TIntermDeclaration *CreateTempInitDeclarationNode(const TSymbolUniqueId &id, + TIntermTyped *initializer, + TQualifier qualifier) +{ + ASSERT(initializer != nullptr); + TIntermSymbol *tempSymbol = CreateTempSymbolNode(id, initializer->getType(), qualifier); + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer); + tempDeclaration->appendDeclarator(tempInit); + return tempDeclaration; +} + +TIntermBlock *EnsureBlock(TIntermNode *node) +{ + if (node == nullptr) + return nullptr; + TIntermBlock *blockNode = node->getAsBlock(); + if (blockNode != nullptr) + return blockNode; + + blockNode = new TIntermBlock(); + blockNode->setLine(node->getLine()); + blockNode->appendStatement(node); + return blockNode; +} + +TIntermSymbol *ReferenceGlobalVariable(const TString &name, const TSymbolTable &symbolTable) +{ + TVariable *var = reinterpret_cast(symbolTable.findGlobal(name)); + ASSERT(var); + return new TIntermSymbol(var->getUniqueId(), name, var->getType()); +} + +TIntermSymbol *ReferenceBuiltInVariable(const TString &name, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TVariable *var = + reinterpret_cast(symbolTable.findBuiltIn(name, shaderVersion, true)); + ASSERT(var); + return new TIntermSymbol(var->getUniqueId(), name, var->getType()); +} + +TIntermTyped *CreateBuiltInFunctionCallNode(const TString &name, + TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion); + ASSERT(fn); + TOperator op = fn->getBuiltInOp(); + if (op != EOpNull) + { + if (arguments->size() == 1) + { + return new TIntermUnary(op, arguments->at(0)->getAsTyped()); + } + return TIntermAggregate::Create(fn->getReturnType(), op, arguments); + } + return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode_util.h b/src/3rdparty/angle/src/compiler/translator/IntermNode_util.h new file mode 100644 index 0000000000..6f3b0674f0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode_util.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermNode_util.h: High-level utilities for creating AST nodes and node hierarchies. Mostly meant +// to be used in AST transforms. + +#ifndef COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ +#define COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TType &returnType, + const char *name, + const TSymbolUniqueId &functionId); +TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TType &returnType, + const char *name, + TIntermBlock *functionBody, + const TSymbolUniqueId &functionId); +TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType, + const char *name, + const TSymbolUniqueId &functionId, + TIntermSequence *arguments); + +TIntermTyped *CreateZeroNode(const TType &type); +TIntermConstantUnion *CreateIndexNode(int index); +TIntermConstantUnion *CreateBoolNode(bool value); + +TIntermSymbol *CreateTempSymbolNode(const TSymbolUniqueId &id, + const TType &type, + TQualifier qualifier); +TIntermDeclaration *CreateTempInitDeclarationNode(const TSymbolUniqueId &id, + TIntermTyped *initializer, + TQualifier qualifier); + +// If the input node is nullptr, return nullptr. +// If the input node is a block node, return it. +// If the input node is not a block node, put it inside a block node and return that. +TIntermBlock *EnsureBlock(TIntermNode *node); + +// Should be called from inside Compiler::compileTreeImpl() where the global level is in scope. +TIntermSymbol *ReferenceGlobalVariable(const TString &name, const TSymbolTable &symbolTable); + +// Note: this can access desktop GLSL built-ins that are hidden from the parser. +TIntermSymbol *ReferenceBuiltInVariable(const TString &name, + const TSymbolTable &symbolTable, + int shaderVersion); + +TIntermTyped *CreateBuiltInFunctionCallNode(const TString &name, + TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp index 7b588ca5a3..6c25c6c35a 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp @@ -4,10 +4,15 @@ // found in the LICENSE file. // -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + #include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode_util.h" #include "compiler/translator/SymbolTable.h" +namespace sh +{ + void TIntermSymbol::traverse(TIntermTraverser *it) { it->traverseSymbol(this); @@ -23,6 +28,11 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it) it->traverseConstantUnion(this); } +void TIntermSwizzle::traverse(TIntermTraverser *it) +{ + it->traverseSwizzle(this); +} + void TIntermBinary::traverse(TIntermTraverser *it) { it->traverseBinary(this); @@ -33,9 +43,14 @@ void TIntermUnary::traverse(TIntermTraverser *it) it->traverseUnary(this); } -void TIntermSelection::traverse(TIntermTraverser *it) +void TIntermTernary::traverse(TIntermTraverser *it) +{ + it->traverseTernary(this); +} + +void TIntermIfElse::traverse(TIntermTraverser *it) { - it->traverseSelection(this); + it->traverseIfElse(this); } void TIntermSwitch::traverse(TIntermTraverser *it) @@ -48,6 +63,31 @@ void TIntermCase::traverse(TIntermTraverser *it) it->traverseCase(this); } +void TIntermFunctionDefinition::traverse(TIntermTraverser *it) +{ + it->traverseFunctionDefinition(this); +} + +void TIntermBlock::traverse(TIntermTraverser *it) +{ + it->traverseBlock(this); +} + +void TIntermInvariantDeclaration::traverse(TIntermTraverser *it) +{ + it->traverseInvariantDeclaration(this); +} + +void TIntermDeclaration::traverse(TIntermTraverser *it) +{ + it->traverseDeclaration(this); +} + +void TIntermFunctionPrototype::traverse(TIntermTraverser *it) +{ + it->traverseFunctionPrototype(this); +} + void TIntermAggregate::traverse(TIntermTraverser *it) { it->traverseAggregate(this); @@ -63,7 +103,35 @@ void TIntermBranch::traverse(TIntermTraverser *it) it->traverseBranch(this); } -void TIntermTraverser::pushParentBlock(TIntermAggregate *node) +TIntermTraverser::TIntermTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable) + : preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + mDepth(-1), + mMaxDepth(0), + mInGlobalScope(true), + mSymbolTable(symbolTable), + mTemporaryId(nullptr) +{ +} + +TIntermTraverser::~TIntermTraverser() +{ +} + +const TIntermBlock *TIntermTraverser::getParentBlock() const +{ + if (!mParentBlockStack.empty()) + { + return mParentBlockStack.back().node; + } + return nullptr; +} + +void TIntermTraverser::pushParentBlock(TIntermBlock *node) { mParentBlockStack.push_back(ParentBlock(node, 0)); } @@ -89,23 +157,32 @@ void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &inse const TIntermSequence &insertionsAfter) { ASSERT(!mParentBlockStack.empty()); - NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos, - insertionsBefore, insertionsAfter); + ParentBlock &parentBlock = mParentBlockStack.back(); + if (mPath.back() == parentBlock.node) + { + ASSERT(mParentBlockStack.size() >= 2u); + // The current node is a block node, so the parent block is not the topmost one in the block + // stack, but the one below that. + parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u); + } + NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore, + insertionsAfter); mInsertions.push_back(insert); } -TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier) +void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) { - // 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(); + TIntermSequence insertions; + insertions.push_back(statement); + insertStatementsInParentBlock(insertions); +} - TIntermSymbol *node = new TIntermSymbol(0, symbolName, type); - node->setInternal(true); - node->getTypePointer()->setQualifier(qualifier); - return node; +TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier) +{ + ASSERT(mTemporaryId != nullptr); + // nextTemporaryId() needs to be called when the code wants to start using another temporary + // symbol. + return CreateTempSymbolNode(*mTemporaryId, type, qualifier); } TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type) @@ -113,27 +190,22 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type) return createTempSymbol(type, EvqTemporary); } -TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type) +TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type) { - TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration); - tempDeclaration->getSequence()->push_back(createTempSymbol(type)); + ASSERT(mTemporaryId != nullptr); + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + tempDeclaration->appendDeclarator(CreateTempSymbolNode(*mTemporaryId, type, EvqTemporary)); return tempDeclaration; } -TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier) +TIntermDeclaration *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; + ASSERT(mTemporaryId != nullptr); + return CreateTempInitDeclarationNode(*mTemporaryId, initializer, qualifier); } -TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer) +TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer) { return createTempInitDeclaration(initializer, EvqTemporary); } @@ -142,39 +214,38 @@ 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()); + TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode); return assignment; } -void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex) +void TIntermTraverser::nextTemporaryId() { - mTemporaryIndex = temporaryIndex; -} - -void TIntermTraverser::nextTemporaryIndex() -{ - ASSERT(mTemporaryIndex != nullptr); - ++(*mTemporaryIndex); + ASSERT(mSymbolTable); + if (!mTemporaryId) + { + mTemporaryId = new TSymbolUniqueId(mSymbolTable); + return; + } + *mTemporaryId = TSymbolUniqueId(mSymbolTable); } -void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence) +void TLValueTrackingTraverser::addToFunctionMap(const TSymbolUniqueId &id, + TIntermSequence *paramSequence) { - mFunctionMap[name] = paramSequence; + mFunctionMap[id.get()] = paramSequence; } bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const { - ASSERT(callNode->getOp() == EOpFunctionCall); - return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end()); + ASSERT(callNode->getOp() == EOpCallFunctionInAST); + return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getId().get()) != + mFunctionMap.end()); } TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode) { ASSERT(isInFunctionMap(callNode)); - return mFunctionMap[callNode->getNameObj()]; + return mFunctionMap[callNode->getFunctionSymbolInfo()->getId().get()]; } void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter) @@ -203,19 +274,41 @@ bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const // void TIntermTraverser::traverseSymbol(TIntermSymbol *node) { + ScopedNodeInTraversalPath addToPath(this, node); visitSymbol(node); } void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node) { + ScopedNodeInTraversalPath addToPath(this, node); visitConstantUnion(node); } +void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + if (preVisit) + visit = visitSwizzle(PreVisit, node); + + if (visit) + { + node->getOperand()->traverse(this); + } + + if (visit && postVisit) + visitSwizzle(PostVisit, node); +} + // // Traverse a binary node. // void TIntermTraverser::traverseBinary(TIntermBinary *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; // @@ -229,8 +322,6 @@ void TIntermTraverser::traverseBinary(TIntermBinary *node) // if (visit) { - incrementDepth(node); - if (node->getLeft()) node->getLeft()->traverse(this); @@ -239,8 +330,6 @@ void TIntermTraverser::traverseBinary(TIntermBinary *node) if (visit && node->getRight()) node->getRight()->traverse(this); - - decrementDepth(); } // @@ -253,6 +342,8 @@ void TIntermTraverser::traverseBinary(TIntermBinary *node) void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; // @@ -266,8 +357,6 @@ void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) // if (visit) { - incrementDepth(node); - // Some binary operations like indexing can be inside an expression which must be an // l-value. bool parentOperatorRequiresLValue = operatorRequiresLValue(); @@ -302,8 +391,6 @@ void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) setOperatorRequiresLValue(parentOperatorRequiresLValue); setInFunctionCallOutParameter(parentInFunctionCallOutParameter); - - decrementDepth(); } // @@ -319,6 +406,8 @@ void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) // void TIntermTraverser::traverseUnary(TIntermUnary *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) @@ -326,11 +415,7 @@ void TIntermTraverser::traverseUnary(TIntermUnary *node) if (visit) { - incrementDepth(node); - node->getOperand()->traverse(this); - - decrementDepth(); } if (visit && postVisit) @@ -339,6 +424,8 @@ void TIntermTraverser::traverseUnary(TIntermUnary *node) void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) @@ -346,8 +433,6 @@ void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) if (visit) { - incrementDepth(node); - ASSERT(!operatorRequiresLValue()); switch (node->getOp()) { @@ -364,153 +449,362 @@ void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) 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 TIntermTraverser::traverseAggregate(TIntermAggregate *node) +// Traverse a function definition node. +void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node) { - bool visit = true; + ScopedNodeInTraversalPath addToPath(this, node); - TIntermSequence *sequence = node->getSequence(); + bool visit = true; if (preVisit) - visit = visitAggregate(PreVisit, node); + visit = visitFunctionDefinition(PreVisit, node); if (visit) { - incrementDepth(node); + mInGlobalScope = false; + + node->getFunctionPrototype()->traverse(this); + if (inVisit) + visit = visitFunctionDefinition(InVisit, node); + node->getBody()->traverse(this); + + mInGlobalScope = true; + } - if (node->getOp() == EOpSequence) - pushParentBlock(node); + if (visit && postVisit) + visitFunctionDefinition(PostVisit, node); +} +// Traverse a block node. +void TIntermTraverser::traverseBlock(TIntermBlock *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + pushParentBlock(node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = visitBlock(PreVisit, node); + + if (visit) + { for (auto *child : *sequence) { child->traverse(this); if (visit && inVisit) { if (child != sequence->back()) - visit = visitAggregate(InVisit, node); + visit = visitBlock(InVisit, node); } - if (node->getOp() == EOpSequence) - incrementParentBlockPos(); + incrementParentBlockPos(); } + } + + if (visit && postVisit) + visitBlock(PostVisit, node); - if (node->getOp() == EOpSequence) - popParentBlock(); + popParentBlock(); +} - decrementDepth(); +void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + if (preVisit) + { + visit = visitInvariantDeclaration(PreVisit, node); + } + + if (visit) + { + node->getSymbol()->traverse(this); + if (postVisit) + { + visitInvariantDeclaration(PostVisit, node); + } + } +} + +// Traverse a declaration node. +void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = visitDeclaration(PreVisit, node); + + if (visit) + { + for (auto *child : *sequence) + { + child->traverse(this); + if (visit && inVisit) + { + if (child != sequence->back()) + visit = visitDeclaration(InVisit, node); + } + } } if (visit && postVisit) - visitAggregate(PostVisit, node); + visitDeclaration(PostVisit, node); } -void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) +void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; TIntermSequence *sequence = node->getSequence(); - switch (node->getOp()) + + if (preVisit) + visit = visitFunctionPrototype(PreVisit, node); + + if (visit) { - case EOpFunction: + for (auto *child : *sequence) { - TIntermAggregate *params = sequence->front()->getAsAggregate(); - ASSERT(params != nullptr); - ASSERT(params->getOp() == EOpParameters); - addToFunctionMap(node->getNameObj(), params->getSequence()); - break; + child->traverse(this); + if (visit && inVisit) + { + if (child != sequence->back()) + visit = visitFunctionPrototype(InVisit, node); + } } - case EOpPrototype: - addToFunctionMap(node->getNameObj(), sequence); - break; - default: - break; } + if (visit && postVisit) + visitFunctionPrototype(PostVisit, node); +} + +// Traverse an aggregate node. Same comments in binary node apply here. +void TIntermTraverser::traverseAggregate(TIntermAggregate *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + if (preVisit) visit = visitAggregate(PreVisit, node); if (visit) { - bool inFunctionMap = false; - if (node->getOp() == EOpFunctionCall) + for (auto *child : *sequence) { - inFunctionMap = isInFunctionMap(node); - if (!inFunctionMap) + child->traverse(this); + if (visit && inVisit) { - // The function is not user-defined - it is likely built-in texture function. - // Assume that those do not have out parameters. - setInFunctionCallOutParameter(false); + if (child != sequence->back()) + visit = visitAggregate(InVisit, node); } } + } - incrementDepth(node); + if (visit && postVisit) + visitAggregate(PostVisit, node); +} - if (inFunctionMap) +bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a, + const NodeInsertMultipleEntry &b) +{ + if (a.parent != b.parent) + { + return a.parent > b.parent; + } + return a.position > b.position; +} + +void TIntermTraverser::updateTree() +{ + // Sort the insertions so that insertion position is decreasing. This way multiple insertions to + // the same parent node are handled correctly. + std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion); + for (size_t ii = 0; ii < mInsertions.size(); ++ii) + { + // We can't know here what the intended ordering of two insertions to the same position is, + // so it is not supported. + ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position || + mInsertions[ii].parent != mInsertions[ii - 1].parent); + const NodeInsertMultipleEntry &insertion = mInsertions[ii]; + ASSERT(insertion.parent); + if (!insertion.insertionsAfter.empty()) { - TIntermSequence *params = getFunctionParameters(node); - TIntermSequence::iterator paramIter = params->begin(); - for (auto *child : *sequence) + bool inserted = insertion.parent->insertChildNodes(insertion.position + 1, + insertion.insertionsAfter); + ASSERT(inserted); + } + if (!insertion.insertionsBefore.empty()) + { + bool inserted = + insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore); + ASSERT(inserted); + } + } + for (size_t ii = 0; ii < mReplacements.size(); ++ii) + { + const NodeUpdateEntry &replacement = mReplacements[ii]; + ASSERT(replacement.parent); + bool replaced = + replacement.parent->replaceChildNode(replacement.original, replacement.replacement); + ASSERT(replaced); + + if (!replacement.originalBecomesChildOfReplacement) + { + // In AST traversing, a parent is visited before its children. + // 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) { - ASSERT(paramIter != params->end()); - TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier(); - setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut); + 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); + } - child->traverse(this); - if (visit && inVisit) + clearReplacementQueue(); +} + +void TIntermTraverser::clearReplacementQueue() +{ + mReplacements.clear(); + mMultiReplacements.clear(); + mInsertions.clear(); +} + +void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus) +{ + queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus); +} + +void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus) +{ + bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD); + mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild)); +} + +TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable, + int shaderVersion) + : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable), + mOperatorRequiresLValue(false), + mInFunctionCallOutParameter(false), + mShaderVersion(shaderVersion) +{ + ASSERT(symbolTable); +} + +void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node) +{ + TIntermSequence *sequence = node->getSequence(); + addToFunctionMap(node->getFunctionSymbolInfo()->getId(), sequence); + + TIntermTraverser::traverseFunctionPrototype(node); +} + +void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = visitAggregate(PreVisit, node); + + if (visit) + { + if (node->getOp() == EOpCallFunctionInAST) + { + if (isInFunctionMap(node)) + { + TIntermSequence *params = getFunctionParameters(node); + TIntermSequence::iterator paramIter = params->begin(); + for (auto *child : *sequence) { - if (child != sequence->back()) - visit = visitAggregate(InVisit, node); + ASSERT(paramIter != params->end()); + TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier(); + setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut); + + child->traverse(this); + if (visit && inVisit) + { + if (child != sequence->back()) + visit = visitAggregate(InVisit, node); + } + + ++paramIter; + } + } + else + { + // The node might not be in the function map in case we're in the middle of + // transforming the AST, and have inserted function call nodes without inserting the + // function definitions yet. + setInFunctionCallOutParameter(false); + for (auto *child : *sequence) + { + child->traverse(this); + if (visit && inVisit) + { + if (child != sequence->back()) + visit = visitAggregate(InVisit, node); + } } - - ++paramIter; } setInFunctionCallOutParameter(false); } else { - 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()) + if (!node->isFunctionCall() && !node->isConstructor()) { - // 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()); - } + builtInFunc = static_cast( + mSymbolTable->findBuiltIn(node->getSymbolTableMangledName(), mShaderVersion)); } size_t paramIndex = 0; for (auto *child : *sequence) { + // This assumes that raw functions called with + // EOpCallInternalRawFunction don't have out parameters. TQualifier qualifier = EvqIn; if (builtInFunc != nullptr) qualifier = builtInFunc->getParam(paramIndex).type->getQualifier(); @@ -523,19 +817,11 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) visit = visitAggregate(InVisit, node); } - if (node->getOp() == EOpSequence) - incrementParentBlockPos(); - ++paramIndex; } setInFunctionCallOutParameter(false); - - if (node->getOp() == EOpSequence) - popParentBlock(); } - - decrementDepth(); } if (visit && postVisit) @@ -543,28 +829,51 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) } // -// Traverse a selection node. Same comments in binary node apply here. +// Traverse a ternary node. Same comments in binary node apply here. // -void TIntermTraverser::traverseSelection(TIntermSelection *node) +void TIntermTraverser::traverseTernary(TIntermTernary *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) - visit = visitSelection(PreVisit, node); + visit = visitTernary(PreVisit, node); + + if (visit) + { + node->getCondition()->traverse(this); + if (node->getTrueExpression()) + node->getTrueExpression()->traverse(this); + if (node->getFalseExpression()) + node->getFalseExpression()->traverse(this); + } + + if (visit && postVisit) + visitTernary(PostVisit, node); +} + +// Traverse an if-else node. Same comments in binary node apply here. +void TIntermTraverser::traverseIfElse(TIntermIfElse *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + if (preVisit) + visit = visitIfElse(PreVisit, node); if (visit) { - incrementDepth(node); node->getCondition()->traverse(this); if (node->getTrueBlock()) node->getTrueBlock()->traverse(this); if (node->getFalseBlock()) node->getFalseBlock()->traverse(this); - decrementDepth(); } if (visit && postVisit) - visitSelection(PostVisit, node); + visitIfElse(PostVisit, node); } // @@ -572,6 +881,8 @@ void TIntermTraverser::traverseSelection(TIntermSelection *node) // void TIntermTraverser::traverseSwitch(TIntermSwitch *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) @@ -579,13 +890,11 @@ void TIntermTraverser::traverseSwitch(TIntermSwitch *node) if (visit) { - incrementDepth(node); node->getInit()->traverse(this); if (inVisit) visit = visitSwitch(InVisit, node); if (visit && node->getStatementList()) node->getStatementList()->traverse(this); - decrementDepth(); } if (visit && postVisit) @@ -597,13 +906,17 @@ void TIntermTraverser::traverseSwitch(TIntermSwitch *node) // void TIntermTraverser::traverseCase(TIntermCase *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) visit = visitCase(PreVisit, node); if (visit && node->getCondition()) + { node->getCondition()->traverse(this); + } if (visit && postVisit) visitCase(PostVisit, node); @@ -614,6 +927,8 @@ void TIntermTraverser::traverseCase(TIntermCase *node) // void TIntermTraverser::traverseLoop(TIntermLoop *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) @@ -621,8 +936,6 @@ void TIntermTraverser::traverseLoop(TIntermLoop *node) if (visit) { - incrementDepth(node); - if (node->getInit()) node->getInit()->traverse(this); @@ -634,8 +947,6 @@ void TIntermTraverser::traverseLoop(TIntermLoop *node) if (node->getExpression()) node->getExpression()->traverse(this); - - decrementDepth(); } if (visit && postVisit) @@ -647,6 +958,8 @@ void TIntermTraverser::traverseLoop(TIntermLoop *node) // void TIntermTraverser::traverseBranch(TIntermBranch *node) { + ScopedNodeInTraversalPath addToPath(this, node); + bool visit = true; if (preVisit) @@ -654,9 +967,7 @@ void TIntermTraverser::traverseBranch(TIntermBranch *node) if (visit && node->getExpression()) { - incrementDepth(node); node->getExpression()->traverse(this); - decrementDepth(); } if (visit && postVisit) @@ -665,5 +976,8 @@ void TIntermTraverser::traverseBranch(TIntermBranch *node) void TIntermTraverser::traverseRaw(TIntermRaw *node) { + ScopedNodeInTraversalPath addToPath(this, node); visitRaw(node); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.h b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.h new file mode 100644 index 0000000000..f0300b586b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.h @@ -0,0 +1,355 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IntermTraverse.h : base classes for AST traversers that walk the AST and +// also have the ability to transform it by replacing nodes. + +#ifndef COMPILER_TRANSLATOR_INTERMTRAVERSE_H_ +#define COMPILER_TRANSLATOR_INTERMTRAVERSE_H_ + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +class TSymbolTable; +class TSymbolUniqueId; + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +// 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 to 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. This is complex to maintain and so should only be done in special cases. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +class TIntermTraverser : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TIntermTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable = nullptr); + virtual ~TIntermTraverser(); + + virtual void visitSymbol(TIntermSymbol *node) {} + virtual void visitRaw(TIntermRaw *node) {} + virtual void visitConstantUnion(TIntermConstantUnion *node) {} + virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; } + virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; } + virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; } + virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; } + virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; } + virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; } + virtual bool visitCase(Visit visit, TIntermCase *node) { return true; } + virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) + { + return true; + } + virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) + { + return true; + } + virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; } + virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; } + virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) + { + return true; + } + virtual bool visitDeclaration(Visit visit, TIntermDeclaration *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 traverseSwizzle(TIntermSwizzle *node); + virtual void traverseBinary(TIntermBinary *node); + virtual void traverseUnary(TIntermUnary *node); + virtual void traverseTernary(TIntermTernary *node); + virtual void traverseIfElse(TIntermIfElse *node); + virtual void traverseSwitch(TIntermSwitch *node); + virtual void traverseCase(TIntermCase *node); + virtual void traverseFunctionPrototype(TIntermFunctionPrototype *node); + virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node); + virtual void traverseAggregate(TIntermAggregate *node); + virtual void traverseBlock(TIntermBlock *node); + virtual void traverseInvariantDeclaration(TIntermInvariantDeclaration *node); + virtual void traverseDeclaration(TIntermDeclaration *node); + virtual void traverseLoop(TIntermLoop *node); + virtual void traverseBranch(TIntermBranch *node); + + int getMaxDepth() const { return mMaxDepth; } + + // 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(); + + protected: + // Should only be called from traverse*() functions + void incrementDepth(TIntermNode *current) + { + mDepth++; + mMaxDepth = std::max(mMaxDepth, mDepth); + mPath.push_back(current); + } + + // Should only be called from traverse*() functions + void decrementDepth() + { + mDepth--; + mPath.pop_back(); + } + + // RAII helper for incrementDepth/decrementDepth + class ScopedNodeInTraversalPath + { + public: + ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current) + : mTraverser(traverser) + { + mTraverser->incrementDepth(current); + } + ~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); } + + private: + TIntermTraverser *mTraverser; + }; + + TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; } + + // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode() + TIntermNode *getAncestorNode(unsigned int n) + { + if (mPath.size() > n + 1u) + { + return mPath[mPath.size() - n - 2u]; + } + return nullptr; + } + + const TIntermBlock *getParentBlock() const; + + void pushParentBlock(TIntermBlock *node); + void incrementParentBlockPos(); + void popParentBlock(); + + // To replace a single node with multiple nodes in the parent aggregate. May be used with blocks + // but also with other nodes like declarations. + struct NodeReplaceWithMultipleEntry + { + NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent, + TIntermNode *_original, + TIntermSequence _replacements) + : parent(_parent), original(_original), replacements(_replacements) + { + } + + TIntermAggregateBase *parent; + TIntermNode *original; + TIntermSequence replacements; + }; + + // Helper to insert statements in the parent block 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 if called from block nodes. + // Note that two insertions to the same position in the same block are 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 insert a single statement. + void insertStatementInParentBlock(TIntermNode *statement); + + // 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. + TIntermDeclaration *createTempDeclaration(const TType &type); + // Create a node that initializes the current temporary symbol with initializer. The symbol will + // have the given qualifier. + TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier); + // Create a node that initializes the current temporary symbol with initializer. + TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer); + // Create a node that assigns rightNode to the current temporary symbol. + TIntermBinary *createTempAssignment(TIntermTyped *rightNode); + // Increment temporary symbol index. + void nextTemporaryId(); + + enum class OriginalNode + { + BECOMES_CHILD, + IS_DROPPED + }; + + void clearReplacementQueue(); + + // Replace the node currently being visited with replacement. + void queueReplacement(TIntermNode *replacement, OriginalNode originalStatus); + // Explicitly specify a node to replace with replacement. + void queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus); + + const bool preVisit; + const bool inVisit; + const bool postVisit; + + int mDepth; + int mMaxDepth; + + bool mInGlobalScope; + + // During traversing, save all the changes that need to happen into + // mReplacements/mMultiReplacements, then do them by calling updateTree(). + // Multi replacements are processed after single replacements. + std::vector mMultiReplacements; + + TSymbolTable *mSymbolTable; + + private: + // To insert multiple nodes into the parent block. + struct NodeInsertMultipleEntry + { + NodeInsertMultipleEntry(TIntermBlock *_parent, + TIntermSequence::size_type _position, + TIntermSequence _insertionsBefore, + TIntermSequence _insertionsAfter) + : parent(_parent), + position(_position), + insertionsBefore(_insertionsBefore), + insertionsAfter(_insertionsAfter) + { + } + + TIntermBlock *parent; + TIntermSequence::size_type position; + TIntermSequence insertionsBefore; + TIntermSequence insertionsAfter; + }; + + static bool CompareInsertion(const NodeInsertMultipleEntry &a, + const NodeInsertMultipleEntry &b); + + // To replace a single node with another on the parent node + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement, + bool _originalBecomesChildOfReplacement) + : parent(_parent), + original(_original), + replacement(_replacement), + originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) + { + } + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + bool originalBecomesChildOfReplacement; + }; + + struct ParentBlock + { + ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn) + : node(nodeIn), pos(posIn) + { + } + + TIntermBlock *node; + TIntermSequence::size_type pos; + }; + + std::vector mInsertions; + std::vector mReplacements; + + // All the nodes from root to the current node during traversing. + TVector mPath; + + // All the code blocks from the root to the current node's parent during traversal. + std::vector mParentBlockStack; + + TSymbolUniqueId *mTemporaryId; +}; + +// 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, + TSymbolTable *symbolTable, + int shaderVersion); + virtual ~TLValueTrackingTraverser() {} + + void traverseBinary(TIntermBinary *node) final; + void traverseUnary(TIntermUnary *node) final; + void traverseFunctionPrototype(TIntermFunctionPrototype *node) final; + void traverseAggregate(TIntermAggregate *node) final; + + protected: + bool isLValueRequiredHere() const + { + return mOperatorRequiresLValue || mInFunctionCallOutParameter; + } + + 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 TSymbolUniqueId &id, TIntermSequence *paramSequence); + + // Return true if the prototype or definition of the function being called has been encountered + // during traversal. + bool isInFunctionMap(const TIntermAggregate *callNode) const; + + // 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; + + // Map from function symbol id values to their parameter sequences + TMap mFunctionMap; + + const int mShaderVersion; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INTERMTRAVERSE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp deleted file mode 100644 index 0adb7212b7..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// -// Build the intermediate representation. -// - -#include -#include -#include - -#include "compiler/translator/Intermediate.h" -#include "compiler/translator/SymbolTable.h" - -//////////////////////////////////////////////////////////////////////////// -// -// First set of functions are to help build the intermediate representation. -// These functions are not member functions of the nodes. -// They are called from parser productions. -// -///////////////////////////////////////////////////////////////////////////// - -// -// Add a terminal node for an identifier in an expression. -// -// Returns the added node. -// -TIntermSymbol *TIntermediate::addSymbol( - int id, const TString &name, const TType &type, const TSourceLoc &line) -{ - TIntermSymbol *node = new TIntermSymbol(id, name, type); - node->setLine(line); - - return node; -} - -// -// Connect two nodes with a new parent that does a binary operation on the nodes. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addBinaryMath( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) -{ - // - // Need a new node holding things together then. Make - // one and promote it to the right type. - // - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - - node->setLeft(left); - node->setRight(right); - if (!node->promote(mInfoSink)) - return NULL; - - // See if we can fold constants. - TIntermTyped *foldedNode = node->fold(mInfoSink); - if (foldedNode) - return foldedNode; - - return node; -} - -// -// Connect two nodes through an assignment. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addAssign( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) -{ - if (left->getType().getStruct() || right->getType().getStruct()) - { - if (left->getType() != right->getType()) - { - return NULL; - } - } - - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - - node->setLeft(left); - node->setRight(right); - if (!node->promote(mInfoSink)) - return NULL; - - return node; -} - -// -// Connect two nodes through an index operator, where the left node is the base -// of an array or struct, and the right node is a direct or indirect offset. -// -// Returns the added node. -// The caller should set the type of the returned node. -// -TIntermTyped *TIntermediate::addIndex( - TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line) -{ - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - node->setLeft(base); - node->setRight(index); - - // caller should set the type - - return node; -} - -// -// Add one node as the parent of another that it operates on. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addUnaryMath( - TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType) -{ - // - // Make a new node for the operator. - // - TIntermUnary *node = new TIntermUnary(op); - node->setLine(line); - node->setOperand(child); - node->promote(funcReturnType); - - TIntermTyped *foldedNode = node->fold(mInfoSink); - if (foldedNode) - return foldedNode; - - return node; -} - -// -// This is the safe way to change the operator on an aggregate, as it -// does lots of error checking and fixing. Especially for establishing -// a function call's operation on it's set of parameters. Sequences -// of instructions are also aggregates, but they just direnctly set -// their operator to EOpSequence. -// -// Returns an aggregate node, which could be the one passed in if -// it was already an aggregate but no operator was set. -// -TIntermAggregate *TIntermediate::setAggregateOperator( - TIntermNode *node, TOperator op, const TSourceLoc &line) -{ - TIntermAggregate *aggNode; - - // - // Make sure we have an aggregate. If not turn it into one. - // - if (node) - { - aggNode = node->getAsAggregate(); - if (aggNode == NULL || aggNode->getOp() != EOpNull) - { - // - // Make an aggregate containing this node. - // - aggNode = new TIntermAggregate(); - aggNode->getSequence()->push_back(node); - } - } - else - { - aggNode = new TIntermAggregate(); - } - - // - // Set the operator. - // - aggNode->setOp(op); - aggNode->setLine(line); - - return aggNode; -} - -// -// Safe way to combine two nodes into an aggregate. Works with null pointers, -// a node that's not a aggregate yet, etc. -// -// Returns the resulting aggregate, unless 0 was passed in for -// both existing nodes. -// -TIntermAggregate *TIntermediate::growAggregate( - TIntermNode *left, TIntermNode *right, const TSourceLoc &line) -{ - if (left == NULL && right == NULL) - return NULL; - - TIntermAggregate *aggNode = NULL; - if (left) - aggNode = left->getAsAggregate(); - if (!aggNode || aggNode->getOp() != EOpNull) - { - aggNode = new TIntermAggregate; - if (left) - aggNode->getSequence()->push_back(left); - } - - if (right) - aggNode->getSequence()->push_back(right); - - aggNode->setLine(line); - - return aggNode; -} - -// -// Turn an existing node into an aggregate. -// -// Returns an aggregate, unless NULL was passed in for the existing node. -// -TIntermAggregate *TIntermediate::makeAggregate( - TIntermNode *node, const TSourceLoc &line) -{ - if (node == NULL) - return NULL; - - TIntermAggregate *aggNode = new TIntermAggregate; - aggNode->getSequence()->push_back(node); - - aggNode->setLine(line); - - 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 -// nodePair. -// -// Returns the selection node created. -// -TIntermNode *TIntermediate::addSelection( - TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line) -{ - // - // For compile time constant selections, prune the code and - // test now. - // - - if (cond->getAsConstantUnion()) - { - if (cond->getAsConstantUnion()->getBConst(0) == true) - { - return nodePair.node1 ? setAggregateOperator( - nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; - } - else - { - return nodePair.node2 ? setAggregateOperator( - nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; - } - } - - TIntermSelection *node = new TIntermSelection( - cond, ensureSequence(nodePair.node1), ensureSequence(nodePair.node2)); - node->setLine(line); - - return node; -} - -TIntermTyped *TIntermediate::addComma(TIntermTyped *left, - TIntermTyped *right, - const TSourceLoc &line, - int shaderVersion) -{ - 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) - { - resultQualifier = EvqTemporary; - } - - TIntermTyped *commaNode = nullptr; - if (!left->hasSideEffects()) - { - commaNode = right; - } - else - { - commaNode = growAggregate(left, right, line); - commaNode->getAsAggregate()->setOp(EOpComma); - commaNode->setType(right->getType()); - } - commaNode->getTypePointer()->setQualifier(resultQualifier); - return commaNode; -} - -// -// For "?:" test nodes. There are three children; a condition, -// a true path, and a false path. The two paths are specified -// as separate parameters. -// -// 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) -{ - TQualifier resultQualifier = EvqTemporary; - if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst && - falseBlock->getQualifier() == EvqConst) - { - resultQualifier = EvqConst; - } - // 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(resultQualifier); - node->setLine(line); - - return node; -} - -TIntermSwitch *TIntermediate::addSwitch( - TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line) -{ - TIntermSwitch *node = new TIntermSwitch(init, statementList); - node->setLine(line); - - return node; -} - -TIntermCase *TIntermediate::addCase( - TIntermTyped *condition, const TSourceLoc &line) -{ - TIntermCase *node = new TIntermCase(condition); - node->setLine(line); - - return node; -} - -// -// Constant terminal nodes. Has a union that contains bool, float or int constants -// -// Returns the constant union node created. -// - -TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion, - const TType &type, - const TSourceLoc &line) -{ - TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type); - node->setLine(line); - - return node; -} - -TIntermTyped *TIntermediate::addSwizzle( - TVectorFields &fields, const TSourceLoc &line) -{ - - TIntermAggregate *node = new TIntermAggregate(EOpSequence); - - node->setLine(line); - TIntermConstantUnion *constIntNode; - TIntermSequence *sequenceVector = node->getSequence(); - TConstantUnion *unionArray; - - for (int i = 0; i < fields.num; i++) - { - unionArray = new TConstantUnion[1]; - unionArray->setIConst(fields.offsets[i]); - constIntNode = addConstantUnion( - unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); - sequenceVector->push_back(constIntNode); - } - - return node; -} - -// -// Create loop nodes. -// -TIntermNode *TIntermediate::addLoop( - TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, - TIntermNode *body, const TSourceLoc &line) -{ - TIntermNode *node = new TIntermLoop(type, init, cond, expr, ensureSequence(body)); - node->setLine(line); - - return node; -} - -// -// Add branches. -// -TIntermBranch* TIntermediate::addBranch( - TOperator branchOp, const TSourceLoc &line) -{ - return addBranch(branchOp, 0, line); -} - -TIntermBranch* TIntermediate::addBranch( - TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line) -{ - TIntermBranch *node = new TIntermBranch(branchOp, expression); - node->setLine(line); - - return node; -} - -// -// This is to be executed once the final root is put on top by the parsing -// process. -// -TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) -{ - if (root == nullptr) - return nullptr; - - // - // Finish off the top level sequence, if any - // - TIntermAggregate *aggRoot = root->getAsAggregate(); - 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 nullptr; -} diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.h b/src/3rdparty/angle/src/compiler/translator/Intermediate.h deleted file mode 100644 index f723fc7648..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.h +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_ -#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ - -#include "compiler/translator/IntermNode.h" - -struct TVectorFields -{ - int offsets[4]; - int num; -}; - -// -// Set of helper functions to help parse and build the tree. -// -class TInfoSink; -class TIntermediate -{ - public: - POOL_ALLOCATOR_NEW_DELETE(); - TIntermediate(TInfoSink &i) - : mInfoSink(i) { } - - TIntermSymbol *addSymbol( - int id, const TString &, const TType &, const TSourceLoc &); - TIntermTyped *addBinaryMath( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addAssign( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addIndex( - TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &); - TIntermTyped *addUnaryMath( - TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType); - TIntermAggregate *growAggregate( - TIntermNode *left, TIntermNode *right, const TSourceLoc &); - TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &); - TIntermAggregate *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 &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 &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 &); - TIntermAggregate *postProcess(TIntermNode *root); - - static void outputTree(TIntermNode *, TInfoSinkBase &); - - TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate); - - private: - void operator=(TIntermediate &); // prevent assignments - - TInfoSink & mInfoSink; -}; - -#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.cpp b/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.cpp new file mode 100644 index 0000000000..aaad4f3c68 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2017 The ANGLE Project 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/IsASTDepthBelowLimit.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Traverse the tree and compute max depth. Takes a maximum depth limit to prevent stack overflow. +class MaxDepthTraverser : public TIntermTraverser +{ + public: + MaxDepthTraverser(int depthLimit) : TIntermTraverser(true, true, false), mDepthLimit(depthLimit) + { + } + + bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); } + bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); } + bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); } + bool visitSwizzle(Visit, TIntermSwizzle *) override { return depthCheck(); } + bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); } + bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); } + bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); } + bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); } + bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); } + + protected: + bool depthCheck() const { return mMaxDepth < mDepthLimit; } + + int mDepthLimit; +}; + +} // anonymous namespace + +bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth) +{ + MaxDepthTraverser traverser(maxDepth + 1); + root->traverse(&traverser); + + return traverser.getMaxDepth() <= maxDepth; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.h b/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.h new file mode 100644 index 0000000000..ef2f02c974 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/IsASTDepthBelowLimit.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// IsASTDepthBelowLimit: Check whether AST depth is below a specific limit. + +#ifndef COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ +#define COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ + +namespace sh +{ + +class TIntermNode; + +bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp b/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp deleted file mode 100644 index d931a18a23..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/LoopInfo.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/LoopInfo.h" - -namespace -{ - -int EvaluateIntConstant(TIntermConstantUnion *node) -{ - ASSERT(node && node->getUnionArrayPointer()); - return node->getIConst(0); -} - -int GetLoopIntIncrement(TIntermLoop *node) -{ - TIntermNode *expr = node->getExpression(); - // for expression has one of the following forms: - // loop_index++ - // loop_index-- - // loop_index += constant_expression - // loop_index -= constant_expression - // ++loop_index - // --loop_index - // The last two forms are not specified in the spec, but I am assuming - // its an oversight. - TIntermUnary *unOp = expr->getAsUnaryNode(); - TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); - - TOperator op = EOpNull; - TIntermConstantUnion *incrementNode = NULL; - if (unOp) - { - op = unOp->getOp(); - } - else if (binOp) - { - op = binOp->getOp(); - ASSERT(binOp->getRight()); - incrementNode = binOp->getRight()->getAsConstantUnion(); - ASSERT(incrementNode); - } - - int increment = 0; - // The operator is one of: ++ -- += -=. - switch (op) - { - case EOpPostIncrement: - case EOpPreIncrement: - ASSERT(unOp && !binOp); - increment = 1; - break; - case EOpPostDecrement: - case EOpPreDecrement: - ASSERT(unOp && !binOp); - increment = -1; - break; - case EOpAddAssign: - ASSERT(!unOp && binOp); - increment = EvaluateIntConstant(incrementNode); - break; - case EOpSubAssign: - ASSERT(!unOp && binOp); - increment = - EvaluateIntConstant(incrementNode); - break; - default: - UNREACHABLE(); - } - - return increment; -} - -} // namespace anonymous - -TLoopIndexInfo::TLoopIndexInfo() - : mId(-1), - mType(EbtVoid), - mInitValue(0), - mStopValue(0), - mIncrementValue(0), - mOp(EOpNull), - mCurrentValue(0) -{ -} - -void TLoopIndexInfo::fillInfo(TIntermLoop *node) -{ - if (node == NULL) - return; - - // Here we assume all the operations are valid, because the loop node is - // already validated in ValidateLimitations. - TIntermSequence *declSeq = - node->getInit()->getAsAggregate()->getSequence(); - TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); - TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); - - mId = symbol->getId(); - mType = symbol->getBasicType(); - - if (mType == EbtInt) - { - TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); - mInitValue = EvaluateIntConstant(initNode); - mCurrentValue = mInitValue; - mIncrementValue = GetLoopIntIncrement(node); - - TIntermBinary* binOp = node->getCondition()->getAsBinaryNode(); - mStopValue = EvaluateIntConstant( - binOp->getRight()->getAsConstantUnion()); - mOp = binOp->getOp(); - } -} - -bool TLoopIndexInfo::satisfiesLoopCondition() const -{ - // Relational operator is one of: > >= < <= == or !=. - switch (mOp) - { - case EOpEqual: - return (mCurrentValue == mStopValue); - case EOpNotEqual: - return (mCurrentValue != mStopValue); - case EOpLessThan: - return (mCurrentValue < mStopValue); - case EOpGreaterThan: - return (mCurrentValue > mStopValue); - case EOpLessThanEqual: - return (mCurrentValue <= mStopValue); - case EOpGreaterThanEqual: - return (mCurrentValue >= mStopValue); - default: - UNREACHABLE(); - return false; - } -} - -TLoopInfo::TLoopInfo() - : loop(NULL) -{ -} - -TLoopInfo::TLoopInfo(TIntermLoop *node) - : loop(node) -{ - index.fillInfo(node); -} - -TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol) -{ - if (!symbol) - return NULL; - for (iterator iter = begin(); iter != end(); ++iter) - { - if (iter->index.getId() == symbol->getId()) - return iter->loop; - } - return NULL; -} - -TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol) -{ - if (!symbol) - return NULL; - for (iterator iter = begin(); iter != end(); ++iter) - { - if (iter->index.getId() == symbol->getId()) - return &(iter->index); - } - return NULL; -} - -void TLoopStack::step() -{ - ASSERT(!empty()); - rbegin()->index.step(); -} - -bool TLoopStack::satisfiesLoopCondition() -{ - ASSERT(!empty()); - return rbegin()->index.satisfiesLoopCondition(); -} - -bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol) -{ - TIntermLoop *loop = findLoop(symbol); - return loop && loop->getUnrollFlag(); -} - -int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol) -{ - TLoopIndexInfo *info = getIndexInfo(symbol); - ASSERT(info); - return info->getCurrentValue(); -} - -void TLoopStack::push(TIntermLoop *loop) -{ - TLoopInfo info(loop); - push_back(info); -} - -void TLoopStack::pop() -{ - pop_back(); -} - diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h deleted file mode 100644 index ec73fd0fa5..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_LOOPINFO_H_ -#define COMPILER_TRANSLATOR_LOOPINFO_H_ - -#include "compiler/translator/IntermNode.h" - -class TLoopIndexInfo -{ - public: - TLoopIndexInfo(); - - // If type is EbtInt, fill all fields of the structure with info - // extracted from a loop node. - // If type is not EbtInt, only fill id and type. - void fillInfo(TIntermLoop *node); - - int getId() const { return mId; } - void setId(int id) { mId = id; } - TBasicType getType() const { return mType; } - void setType(TBasicType type) { mType = type; } - int getCurrentValue() const { return mCurrentValue; } - - void step() { mCurrentValue += mIncrementValue; } - - // Check if the current value satisfies the loop condition. - bool satisfiesLoopCondition() const; - - private: - int mId; - TBasicType mType; // Either EbtInt or EbtFloat - - // Below fields are only valid if the index's type is int. - int mInitValue; - int mStopValue; - int mIncrementValue; - TOperator mOp; - int mCurrentValue; -}; - -struct TLoopInfo -{ - TLoopIndexInfo index; - TIntermLoop *loop; - - TLoopInfo(); - TLoopInfo(TIntermLoop *node); -}; - -class TLoopStack : public TVector -{ - public: - // Search loop stack for a loop whose index matches the input symbol. - TIntermLoop *findLoop(TIntermSymbol *symbol); - - // Find the loop index info in the loop stack by the input symbol. - TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol); - - // Update the currentValue for the next loop iteration. - void step(); - - // Return false if loop condition is no longer satisfied. - bool satisfiesLoopCondition(); - - // Check if the symbol is the index of a loop that's unrolled. - bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol); - - // Return the current value of a given loop index symbol. - int getLoopIndexValue(TIntermSymbol *symbol); - - void push(TIntermLoop *info); - void pop(); -}; - -#endif // COMPILER_TRANSLATOR_LOOPINFO_H_ - diff --git a/src/3rdparty/angle/src/compiler/translator/MMap.h b/src/3rdparty/angle/src/compiler/translator/MMap.h deleted file mode 100644 index fca843992b..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/MMap.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_MMAP_H_ -#define COMPILER_TRANSLATOR_MMAP_H_ - -// -// Encapsulate memory mapped files -// - -class TMMap { -public: - TMMap(const char* fileName) : - fSize(-1), // -1 is the error value returned by GetFileSize() - fp(NULL), - fBuff(0) // 0 is the error value returned by MapViewOfFile() - { - if ((fp = fopen(fileName, "r")) == NULL) - return; - char c = getc(fp); - fSize = 0; - while (c != EOF) { - fSize++; - c = getc(fp); - } - if (c == EOF) - fSize++; - rewind(fp); - fBuff = (char*)malloc(sizeof(char) * fSize); - int count = 0; - c = getc(fp); - while (c != EOF) { - fBuff[count++] = c; - c = getc(fp); - } - fBuff[count++] = c; - } - - char* getData() { return fBuff; } - int getSize() { return fSize; } - - ~TMMap() { - if (fp != NULL) - fclose(fp); - } - -private: - int fSize; // size of file to map in - FILE *fp; - char* fBuff; // the actual data; -}; - -#endif // COMPILER_TRANSLATOR_MMAP_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h index b13b1baabb..af86b8bde4 100644 --- a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h +++ b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h @@ -9,7 +9,7 @@ #ifndef COMPILER_TRANSLATOR_NODESEARCH_H_ #define COMPILER_TRANSLATOR_NODESEARCH_H_ -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" namespace sh { @@ -18,10 +18,7 @@ template class NodeSearchTraverser : public TIntermTraverser { public: - NodeSearchTraverser() - : TIntermTraverser(true, false, false), - mFound(false) - {} + NodeSearchTraverser() : TIntermTraverser(true, false, false), mFound(false) {} bool found() const { return mFound; } @@ -43,17 +40,17 @@ class FindDiscard : public NodeSearchTraverser { switch (node->getFlowOp()) { - case EOpKill: - mFound = true; - break; + case EOpKill: + mFound = true; + break; - default: break; + default: + break; } return !mFound; } }; - } -#endif // COMPILER_TRANSLATOR_NODESEARCH_H_ +#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 20e47f290e..7a2156611a 100644 --- a/src/3rdparty/angle/src/compiler/translator/Operator.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Operator.cpp @@ -10,192 +10,376 @@ const char *GetOperatorString(TOperator op) { switch (op) { - // Note: ops from EOpNull to EOpPrototype can't be handled here. - - case EOpNegative: return "-"; - case EOpPositive: return "+"; - case EOpLogicalNot: return "!"; - case EOpVectorLogicalNot: return "not"; - case EOpBitwiseNot: return "~"; - - case EOpPostIncrement: return "++"; - case EOpPostDecrement: return "--"; - case EOpPreIncrement: return "++"; - case EOpPreDecrement: return "--"; - - case EOpAdd: return "+"; - case EOpSub: return "-"; - case EOpMul: return "*"; - case EOpDiv: return "/"; - case EOpIMod: return "%"; - case EOpEqual: return "=="; - case EOpNotEqual: return "!="; - case EOpVectorEqual: return "equal"; - case EOpVectorNotEqual: return "notEqual"; - case EOpLessThan: return "<"; - case EOpGreaterThan: return ">"; - case EOpLessThanEqual: return "<="; - case EOpGreaterThanEqual: return ">="; - case EOpComma: return ","; - - // Fall-through. - case EOpVectorTimesScalar: - case EOpVectorTimesMatrix: - case EOpMatrixTimesVector: - case EOpMatrixTimesScalar: return "*"; - - case EOpLogicalOr: return "||"; - case EOpLogicalXor: return "^^"; - case EOpLogicalAnd: return "&&"; - - case EOpBitShiftLeft: return "<<"; - case EOpBitShiftRight: return ">>"; - - case EOpBitwiseAnd: return "&"; - case EOpBitwiseXor: return "^"; - case EOpBitwiseOr: return "|"; - - // Fall-through. - case EOpIndexDirect: - case EOpIndexIndirect: return "[]"; - - case EOpIndexDirectStruct: - case EOpIndexDirectInterfaceBlock: return "."; - - case EOpVectorSwizzle: return "."; - - case EOpRadians: return "radians"; - case EOpDegrees: return "degrees"; - case EOpSin: return "sin"; - case EOpCos: return "cos"; - case EOpTan: return "tan"; - case EOpAsin: return "asin"; - case EOpAcos: return "acos"; - case EOpAtan: return "atan"; - - case EOpSinh: return "sinh"; - case EOpCosh: return "cosh"; - case EOpTanh: return "tanh"; - case EOpAsinh: return "asinh"; - case EOpAcosh: return "acosh"; - case EOpAtanh: return "atanh"; - - case EOpPow: return "pow"; - case EOpExp: return "exp"; - case EOpLog: return "log"; - case EOpExp2: return "exp2"; - case EOpLog2: return "log2"; - case EOpSqrt: return "sqrt"; - case EOpInverseSqrt: return "inversesqrt"; - - case EOpAbs: return "abs"; - case EOpSign: return "sign"; - case EOpFloor: return "floor"; - case EOpTrunc: return "trunc"; - case EOpRound: return "round"; - case EOpRoundEven: return "roundEven"; - case EOpCeil: return "ceil"; - case EOpFract: return "fract"; - case EOpMod: return "mod"; - case EOpModf: return "modf"; - case EOpMin: return "min"; - case EOpMax: return "max"; - case EOpClamp: return "clamp"; - case EOpMix: return "mix"; - case EOpStep: return "step"; - case EOpSmoothStep: return "smoothstep"; - case EOpIsNan: return "isnan"; - case EOpIsInf: return "isinf"; - - case EOpFloatBitsToInt: return "floatBitsToInt"; - case EOpFloatBitsToUint: return "floatBitsToUint"; - case EOpIntBitsToFloat: return "intBitsToFloat"; - case EOpUintBitsToFloat: return "uintBitsToFloat"; - - case EOpPackSnorm2x16: return "packSnorm2x16"; - case EOpPackUnorm2x16: return "packUnorm2x16"; - case EOpPackHalf2x16: return "packHalf2x16"; - case EOpUnpackSnorm2x16: return "unpackSnorm2x16"; - case EOpUnpackUnorm2x16: return "unpackUnorm2x16"; - case EOpUnpackHalf2x16: return "unpackHalf2x16"; - - case EOpLength: return "length"; - case EOpDistance: return "distance"; - case EOpDot: return "dot"; - case EOpCross: return "cross"; - case EOpNormalize: return "normalize"; - case EOpFaceForward: return "faceforward"; - case EOpReflect: return "reflect"; - case EOpRefract: return "refract"; - - case EOpDFdx: return "dFdx"; - case EOpDFdy: return "dFdy"; - case EOpFwidth: return "fwidth"; - - case EOpMatrixTimesMatrix: return "*"; - - case EOpOuterProduct: return "outerProduct"; - case EOpTranspose: return "transpose"; - case EOpDeterminant: return "determinant"; - case EOpInverse: return "inverse"; - - case EOpAny: return "any"; - case EOpAll: return "all"; - - case EOpKill: return "kill"; - case EOpReturn: return "return"; - case EOpBreak: return "break"; - case EOpContinue: return "continue"; - - case EOpConstructInt: return "int"; - case EOpConstructUInt: return "uint"; - case EOpConstructBool: return "bool"; - case EOpConstructFloat: return "float"; - case EOpConstructVec2: return "vec2"; - case EOpConstructVec3: return "vec3"; - case EOpConstructVec4: return "vec4"; - case EOpConstructBVec2: return "bvec2"; - case EOpConstructBVec3: return "bvec3"; - case EOpConstructBVec4: return "bvec4"; - case EOpConstructIVec2: return "ivec2"; - case EOpConstructIVec3: return "ivec3"; - case EOpConstructIVec4: return "ivec4"; - case EOpConstructUVec2: return "uvec2"; - case EOpConstructUVec3: return "uvec3"; - case EOpConstructUVec4: return "uvec4"; - case EOpConstructMat2: return "mat2"; - case 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 - - case EOpAssign: return "="; - case EOpInitialize: return "="; - case EOpAddAssign: return "+="; - case EOpSubAssign: return "-="; - - // Fall-through. - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: return "*="; - - case EOpDivAssign: return "/="; - case EOpIModAssign: return "%="; - case EOpBitShiftLeftAssign: return "<<="; - case EOpBitShiftRightAssign: return ">>="; - case EOpBitwiseAndAssign: return "&="; - case EOpBitwiseXorAssign: return "^="; - case EOpBitwiseOrAssign: return "|="; - - default: break; + // Note: EOpNull and EOpCall* can't be handled here. + + case EOpNegative: + return "-"; + case EOpPositive: + return "+"; + case EOpLogicalNot: + return "!"; + case EOpBitwiseNot: + return "~"; + + case EOpPostIncrement: + return "++"; + case EOpPostDecrement: + return "--"; + case EOpPreIncrement: + return "++"; + case EOpPreDecrement: + return "--"; + + case EOpArrayLength: + return ".length()"; + + case EOpAdd: + return "+"; + case EOpSub: + return "-"; + case EOpMul: + return "*"; + case EOpDiv: + return "/"; + case EOpIMod: + return "%"; + + case EOpEqual: + return "=="; + case EOpNotEqual: + return "!="; + case EOpLessThan: + return "<"; + case EOpGreaterThan: + return ">"; + case EOpLessThanEqual: + return "<="; + case EOpGreaterThanEqual: + return ">="; + + case EOpEqualComponentWise: + return "equal"; + case EOpNotEqualComponentWise: + return "notEqual"; + case EOpLessThanComponentWise: + return "lessThan"; + case EOpGreaterThanComponentWise: + return "greaterThan"; + case EOpLessThanEqualComponentWise: + return "lessThanEqual"; + case EOpGreaterThanEqualComponentWise: + return "greaterThanEqual"; + + case EOpComma: + return ","; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + return "*"; + + case EOpLogicalOr: + return "||"; + case EOpLogicalXor: + return "^^"; + case EOpLogicalAnd: + return "&&"; + + case EOpBitShiftLeft: + return "<<"; + case EOpBitShiftRight: + return ">>"; + + case EOpBitwiseAnd: + return "&"; + case EOpBitwiseXor: + return "^"; + case EOpBitwiseOr: + return "|"; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: + return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + return "."; + + case EOpRadians: + return "radians"; + case EOpDegrees: + return "degrees"; + case EOpSin: + return "sin"; + case EOpCos: + return "cos"; + case EOpTan: + return "tan"; + case EOpAsin: + return "asin"; + case EOpAcos: + return "acos"; + case EOpAtan: + return "atan"; + + case EOpSinh: + return "sinh"; + case EOpCosh: + return "cosh"; + case EOpTanh: + return "tanh"; + case EOpAsinh: + return "asinh"; + case EOpAcosh: + return "acosh"; + case EOpAtanh: + return "atanh"; + + case EOpPow: + return "pow"; + case EOpExp: + return "exp"; + case EOpLog: + return "log"; + case EOpExp2: + return "exp2"; + case EOpLog2: + return "log2"; + case EOpSqrt: + return "sqrt"; + case EOpInverseSqrt: + return "inversesqrt"; + + case EOpAbs: + return "abs"; + case EOpSign: + return "sign"; + case EOpFloor: + return "floor"; + case EOpTrunc: + return "trunc"; + case EOpRound: + return "round"; + case EOpRoundEven: + return "roundEven"; + case EOpCeil: + return "ceil"; + case EOpFract: + return "fract"; + case EOpMod: + return "mod"; + case EOpModf: + return "modf"; + case EOpMin: + return "min"; + case EOpMax: + return "max"; + case EOpClamp: + return "clamp"; + case EOpMix: + return "mix"; + case EOpStep: + return "step"; + case EOpSmoothStep: + return "smoothstep"; + case EOpIsNan: + return "isnan"; + case EOpIsInf: + return "isinf"; + + case EOpFloatBitsToInt: + return "floatBitsToInt"; + case EOpFloatBitsToUint: + return "floatBitsToUint"; + case EOpIntBitsToFloat: + return "intBitsToFloat"; + case EOpUintBitsToFloat: + return "uintBitsToFloat"; + + case EOpFrexp: + return "frexp"; + case EOpLdexp: + return "ldexp"; + + case EOpPackSnorm2x16: + return "packSnorm2x16"; + case EOpPackUnorm2x16: + return "packUnorm2x16"; + case EOpPackHalf2x16: + return "packHalf2x16"; + case EOpUnpackSnorm2x16: + return "unpackSnorm2x16"; + case EOpUnpackUnorm2x16: + return "unpackUnorm2x16"; + case EOpUnpackHalf2x16: + return "unpackHalf2x16"; + + case EOpPackUnorm4x8: + return "packUnorm4x8"; + case EOpPackSnorm4x8: + return "packSnorm4x8"; + case EOpUnpackUnorm4x8: + return "unpackUnorm4x8"; + case EOpUnpackSnorm4x8: + return "unpackSnorm4x8"; + + case EOpLength: + return "length"; + case EOpDistance: + return "distance"; + case EOpDot: + return "dot"; + case EOpCross: + return "cross"; + case EOpNormalize: + return "normalize"; + case EOpFaceforward: + return "faceforward"; + case EOpReflect: + return "reflect"; + case EOpRefract: + return "refract"; + + case EOpDFdx: + return "dFdx"; + case EOpDFdy: + return "dFdy"; + case EOpFwidth: + return "fwidth"; + + case EOpMulMatrixComponentWise: + return "matrixCompMult"; + case EOpOuterProduct: + return "outerProduct"; + case EOpTranspose: + return "transpose"; + case EOpDeterminant: + return "determinant"; + case EOpInverse: + return "inverse"; + + case EOpAny: + return "any"; + case EOpAll: + return "all"; + case EOpLogicalNotComponentWise: + return "not"; + + case EOpBitfieldExtract: + return "bitfieldExtract"; + case EOpBitfieldInsert: + return "bitfieldInsert"; + case EOpBitfieldReverse: + return "bitfieldReverse"; + case EOpBitCount: + return "bitCount"; + case EOpFindLSB: + return "findLSB"; + case EOpFindMSB: + return "findMSB"; + case EOpUaddCarry: + return "uaddCarry"; + case EOpUsubBorrow: + return "usubBorrow"; + case EOpUmulExtended: + return "umulExtended"; + case EOpImulExtended: + return "imulExtended"; + + case EOpKill: + return "kill"; + case EOpReturn: + return "return"; + case EOpBreak: + return "break"; + case EOpContinue: + return "continue"; + + case EOpAssign: + return "="; + case EOpInitialize: + return "="; + case EOpAddAssign: + return "+="; + case EOpSubAssign: + return "-="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + return "*="; + + case EOpDivAssign: + return "/="; + case EOpIModAssign: + return "%="; + case EOpBitShiftLeftAssign: + return "<<="; + case EOpBitShiftRightAssign: + return ">>="; + case EOpBitwiseAndAssign: + return "&="; + case EOpBitwiseXorAssign: + return "^="; + case EOpBitwiseOrAssign: + return "|="; + case EOpBarrier: + return "barrier"; + case EOpMemoryBarrier: + return "memoryBarrier"; + case EOpMemoryBarrierAtomicCounter: + return "memoryBarrierAtomicCounter"; + case EOpMemoryBarrierBuffer: + return "memoryBarrierBuffer"; + case EOpMemoryBarrierImage: + return "memoryBarrierImage"; + case EOpMemoryBarrierShared: + return "memoryBarrierShared"; + case EOpGroupMemoryBarrier: + return "groupMemoryBarrier"; + + case EOpEmitVertex: + return "EmitVertex"; + case EOpEndPrimitive: + return "EndPrimitive"; + default: + break; } return ""; } +bool IsAssignment(TOperator op) +{ + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + return true; + default: + return false; + } +} \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/Operator.h b/src/3rdparty/angle/src/compiler/translator/Operator.h index b0efb8f48b..72f3dbf3f6 100644 --- a/src/3rdparty/angle/src/compiler/translator/Operator.h +++ b/src/3rdparty/angle/src/compiler/translator/Operator.h @@ -12,15 +12,21 @@ // enum TOperator { - EOpNull, // if in a node, should only mean a node is still being built - EOpSequence, // denotes a list of statements, or parameters, etc. - EOpFunctionCall, - EOpFunction, // For function definition - EOpParameters, // an aggregate listing the parameters to a function + EOpNull, // if in a node, should only mean a node is still being built - EOpDeclaration, - EOpInvariantDeclaration, // Specialized declarations for attributing invariance - EOpPrototype, + // Call a function defined in the AST. This might be a user-defined function or a function + // inserted by an AST transformation. + EOpCallFunctionInAST, + + // Call an internal helper function with a raw implementation - the implementation can't be + // subject to AST transformations. Raw functions have a few constraints to keep them compatible + // with AST traversers: + // * They should not return arrays. + // * They should not have out parameters. + EOpCallInternalRawFunction, + + // Call a built-in function like a texture or image function. + EOpCallBuiltInFunction, // // Unary operators @@ -29,7 +35,6 @@ enum TOperator EOpNegative, EOpPositive, EOpLogicalNot, - EOpVectorLogicalNot, EOpBitwiseNot, EOpPostIncrement, @@ -37,8 +42,11 @@ enum TOperator EOpPreIncrement, EOpPreDecrement, + EOpArrayLength, + // - // binary operations + // binary operations (ones with special GLSL syntax are used in TIntermBinary nodes, others in + // TIntermAggregate nodes) // EOpAdd, @@ -46,20 +54,28 @@ enum TOperator EOpMul, EOpDiv, EOpIMod, + EOpEqual, EOpNotEqual, - EOpVectorEqual, - EOpVectorNotEqual, EOpLessThan, EOpGreaterThan, EOpLessThanEqual, EOpGreaterThanEqual, + + EOpEqualComponentWise, + EOpNotEqualComponentWise, + EOpLessThanComponentWise, + EOpLessThanEqualComponentWise, + EOpGreaterThanComponentWise, + EOpGreaterThanEqualComponentWise, + EOpComma, EOpVectorTimesScalar, EOpVectorTimesMatrix, EOpMatrixTimesVector, EOpMatrixTimesScalar, + EOpMatrixTimesMatrix, EOpLogicalOr, EOpLogicalXor, @@ -77,10 +93,8 @@ enum TOperator EOpIndexDirectStruct, EOpIndexDirectInterfaceBlock, - EOpVectorSwizzle, - // - // Built-in functions potentially mapped to operators + // Built-in functions mapped to operators (either unary or with multiple parameters) // EOpRadians, @@ -131,6 +145,9 @@ enum TOperator EOpIntBitsToFloat, EOpUintBitsToFloat, + EOpFrexp, + EOpLdexp, + EOpPackSnorm2x16, EOpPackUnorm2x16, EOpPackHalf2x16, @@ -138,21 +155,25 @@ enum TOperator EOpUnpackUnorm2x16, EOpUnpackHalf2x16, + EOpPackUnorm4x8, + EOpPackSnorm4x8, + EOpUnpackUnorm4x8, + EOpUnpackSnorm4x8, + EOpLength, EOpDistance, EOpDot, EOpCross, EOpNormalize, - EOpFaceForward, + EOpFaceforward, EOpReflect, EOpRefract, - EOpDFdx, // Fragment only, OES_standard_derivatives extension - EOpDFdy, // Fragment only, OES_standard_derivatives extension - EOpFwidth, // Fragment only, OES_standard_derivatives extension - - EOpMatrixTimesMatrix, + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + EOpMulMatrixComponentWise, EOpOuterProduct, EOpTranspose, EOpDeterminant, @@ -160,46 +181,33 @@ enum TOperator EOpAny, EOpAll, + EOpLogicalNotComponentWise, + + EOpBitfieldExtract, + EOpBitfieldInsert, + EOpBitfieldReverse, + EOpBitCount, + EOpFindLSB, + EOpFindMSB, + EOpUaddCarry, + EOpUsubBorrow, + EOpUmulExtended, + EOpImulExtended, // // Branch // - EOpKill, // Fragment only + EOpKill, // Fragment only EOpReturn, EOpBreak, EOpContinue, // - // Constructors + // Constructor // - EOpConstructInt, - EOpConstructUInt, - EOpConstructBool, - EOpConstructFloat, - EOpConstructVec2, - EOpConstructVec3, - EOpConstructVec4, - EOpConstructBVec2, - EOpConstructBVec3, - EOpConstructBVec4, - EOpConstructIVec2, - EOpConstructIVec3, - EOpConstructIVec4, - EOpConstructUVec2, - EOpConstructUVec3, - EOpConstructUVec4, - EOpConstructMat2, - EOpConstructMat2x3, - EOpConstructMat2x4, - EOpConstructMat3x2, - EOpConstructMat3, - EOpConstructMat3x4, - EOpConstructMat4x2, - EOpConstructMat4x3, - EOpConstructMat4, - EOpConstructStruct, + EOpConstruct, // // moves @@ -222,10 +230,26 @@ enum TOperator EOpBitShiftRightAssign, EOpBitwiseAndAssign, EOpBitwiseXorAssign, - EOpBitwiseOrAssign + EOpBitwiseOrAssign, + + // barriers + EOpBarrier, + EOpMemoryBarrier, + EOpMemoryBarrierAtomicCounter, + EOpMemoryBarrierBuffer, + EOpMemoryBarrierImage, + EOpMemoryBarrierShared, + EOpGroupMemoryBarrier, + + // Geometry only + EOpEmitVertex, + EOpEndPrimitive }; // Returns the string corresponding to the operator in GLSL -const char* GetOperatorString(TOperator op); +const char *GetOperatorString(TOperator op); + +// Say whether or not a binary or unary operation changes the value of a variable. +bool IsAssignment(TOperator op); #endif // COMPILER_TRANSLATOR_OPERATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp index 77e0a8fb37..50626c91c0 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp @@ -6,20 +6,27 @@ #include "compiler/translator/OutputESSL.h" +namespace sh +{ + TOutputESSL::TOutputESSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap &nameMap, - TSymbolTable &symbolTable, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - bool forceHighp) + bool forceHighp, + ShCompileOptions compileOptions) : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, + shaderType, shaderVersion, - SH_ESSL_OUTPUT), + SH_ESSL_OUTPUT, + compileOptions), mForceHighp(forceHighp) { } @@ -29,10 +36,12 @@ bool TOutputESSL::writeVariablePrecision(TPrecision precision) if (precision == EbpUndefined) return false; - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); if (mForceHighp) out << getPrecisionString(EbpHigh); else out << getPrecisionString(precision); return true; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h index c5a963499e..e0c7bf2ae6 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h @@ -9,22 +9,29 @@ #include "compiler/translator/OutputGLSLBase.h" +namespace sh +{ + class TOutputESSL : public TOutputGLSLBase { -public: - TOutputESSL(TInfoSinkBase& objSink, + public: + TOutputESSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - bool forceHighp); + bool forceHighp, + ShCompileOptions compileOptions); -protected: - bool writeVariablePrecision(TPrecision precision) override; + protected: + bool writeVariablePrecision(TPrecision precision) override; -private: + private: bool mForceHighp; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp index 431425020a..1bad05dab9 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp @@ -6,20 +6,29 @@ #include "compiler/translator/OutputGLSL.h" -TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink, +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +TOutputGLSL::TOutputGLSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - ShShaderOutput output) + ShShaderOutput output, + ShCompileOptions compileOptions) : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, + shaderType, shaderVersion, - output) + output, + compileOptions) { } @@ -30,18 +39,18 @@ bool TOutputGLSL::writeVariablePrecision(TPrecision) void TOutputGLSL::visitSymbol(TIntermSymbol *node) { - TInfoSinkBase& out = objSink(); + TInfoSinkBase &out = objSink(); const TString &symbol = node->getSymbol(); if (symbol == "gl_FragDepthEXT") { out << "gl_FragDepth"; } - else if (symbol == "gl_FragColor" && IsGLSL130OrNewer(getShaderOutput())) + else if (symbol == "gl_FragColor" && sh::IsGLSL130OrNewer(getShaderOutput())) { out << "webgl_FragColor"; } - else if (symbol == "gl_FragData" && IsGLSL130OrNewer(getShaderOutput())) + else if (symbol == "gl_FragData" && sh::IsGLSL130OrNewer(getShaderOutput())) { out << "webgl_FragData"; } @@ -59,44 +68,43 @@ void TOutputGLSL::visitSymbol(TIntermSymbol *node) } } -TString TOutputGLSL::translateTextureFunction(TString &name) +TString TOutputGLSL::translateTextureFunction(const TString &name) { - static const char *simpleRename[] = { - "texture2DLodEXT", "texture2DLod", - "texture2DProjLodEXT", "texture2DProjLod", - "textureCubeLodEXT", "textureCubeLod", - "texture2DGradEXT", "texture2DGradARB", - "texture2DProjGradEXT", "texture2DProjGradARB", - "textureCubeGradEXT", "textureCubeGradARB", - NULL, NULL - }; + static const char *simpleRename[] = {"texture2DLodEXT", + "texture2DLod", + "texture2DProjLodEXT", + "texture2DProjLod", + "textureCubeLodEXT", + "textureCubeLod", + "texture2DGradEXT", + "texture2DGradARB", + "texture2DProjGradEXT", + "texture2DProjGradARB", + "textureCubeGradEXT", + "textureCubeGradARB", + nullptr, + nullptr}; static const char *legacyToCoreRename[] = { - "texture2D", "texture", - "texture2DProj", "textureProj", - "texture2DLod", "textureLod", - "texture2DProjLod", "textureProjLod", - "texture2DRect", "texture", - "textureCube", "texture", + "texture2D", "texture", "texture2DProj", "textureProj", "texture2DLod", "textureLod", + "texture2DProjLod", "textureProjLod", "texture2DRect", "texture", "textureCube", "texture", "textureCubeLod", "textureLod", // Extensions - "texture2DLodEXT", "textureLod", - "texture2DProjLodEXT", "textureProjLod", - "textureCubeLodEXT", "textureLod", - "texture2DGradEXT", "textureGrad", - "texture2DProjGradEXT", "textureProjGrad", - "textureCubeGradEXT", "textureGrad", - NULL, NULL - }; - const char **mapping = (IsGLSL130OrNewer(getShaderOutput())) ? - legacyToCoreRename : simpleRename; + "texture2DLodEXT", "textureLod", "texture2DProjLodEXT", "textureProjLod", + "textureCubeLodEXT", "textureLod", "texture2DGradEXT", "textureGrad", + "texture2DProjGradEXT", "textureProjGrad", "textureCubeGradEXT", "textureGrad", nullptr, + nullptr}; + const char **mapping = + (sh::IsGLSL130OrNewer(getShaderOutput())) ? legacyToCoreRename : simpleRename; - for (int i = 0; mapping[i] != NULL; i += 2) + for (int i = 0; mapping[i] != nullptr; i += 2) { if (name == mapping[i]) { - return mapping[i+1]; + return mapping[i + 1]; } } return name; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h index 9b1aca4eab..c80abec1a6 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h @@ -9,21 +9,28 @@ #include "compiler/translator/OutputGLSLBase.h" +namespace sh +{ + class TOutputGLSL : public TOutputGLSLBase { public: - TOutputGLSL(TInfoSinkBase& objSink, + TOutputGLSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - ShShaderOutput output); + ShShaderOutput output, + ShCompileOptions compileOptions); protected: bool writeVariablePrecision(TPrecision) override; void visitSymbol(TIntermSymbol *node) override; - TString translateTextureFunction(TString &name) override; + TString translateTextureFunction(const TString &name) override; }; +} // namespace sh + #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 f048b050b7..edaf2ebebf 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -6,32 +6,33 @@ #include "compiler/translator/OutputGLSLBase.h" +#include "angle_gl.h" #include "common/debug.h" +#include "common/mathutil.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/util.h" #include -namespace +namespace sh { -TString arrayBrackets(const TType &type) + +namespace { - ASSERT(type.isArray()); - TInfoSinkBase out; - out << "[" << type.getArraySize() << "]"; - return TString(out.c_str()); -} bool isSingleStatement(TIntermNode *node) { - if (const TIntermAggregate *aggregate = node->getAsAggregate()) + if (node->getAsFunctionDefinition()) + { + return false; + } + else if (node->getAsBlock()) { - return (aggregate->getOp() != EOpFunction) && - (aggregate->getOp() != EOpSequence); + return false; } - else if (const TIntermSelection *selection = node->getAsSelectionNode()) + else if (node->getAsIfElseNode()) { - // Ternary operators are usually part of an assignment operator. - // This handles those rare cases in which they are all by themselves. - return selection->usesTernaryOperator(); + return false; } else if (node->getAsLoopNode()) { @@ -48,29 +49,79 @@ bool isSingleStatement(TIntermNode *node) return true; } +class CommaSeparatedListItemPrefixGenerator +{ + public: + CommaSeparatedListItemPrefixGenerator() : mFirst(true) {} + private: + bool mFirst; + + friend TInfoSinkBase &operator<<(TInfoSinkBase &out, + CommaSeparatedListItemPrefixGenerator &gen); +}; + +TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen) +{ + if (gen.mFirst) + { + gen.mFirst = false; + } + else + { + out << ", "; + } + return out; +} + } // namespace TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap &nameMap, - TSymbolTable &symbolTable, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - ShShaderOutput output) - : TIntermTraverser(true, true, true), + ShShaderOutput output, + ShCompileOptions compileOptions) + : TIntermTraverser(true, true, true, symbolTable), mObjSink(objSink), - mDeclaringVariables(false), + mDeclaringVariable(false), mClampingStrategy(clampingStrategy), mHashFunction(hashFunction), mNameMap(nameMap), - mSymbolTable(symbolTable), + mShaderType(shaderType), mShaderVersion(shaderVersion), - mOutput(output) + mOutput(output), + mCompileOptions(compileOptions) +{ +} + +void TOutputGLSLBase::writeInvariantQualifier(const TType &type) { + if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions)) + { + TInfoSinkBase &out = objSink(); + out << "invariant "; + } } -void TOutputGLSLBase::writeTriplet( - Visit visit, const char *preStr, const char *inStr, const char *postStr) +void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f) +{ + if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300) + { + out << "uintBitsToFloat(" << gl::bitCast(f) << "u)"; + } + else + { + out << std::min(FLT_MAX, std::max(-FLT_MAX, f)); + } +} + +void TOutputGLSLBase::writeTriplet(Visit visit, + const char *preStr, + const char *inStr, + const char *postStr) { TInfoSinkBase &out = objSink(); if (visit == PreVisit && preStr) @@ -81,69 +132,181 @@ void TOutputGLSLBase::writeTriplet( out << postStr; } -void TOutputGLSLBase::writeBuiltInFunctionTriplet( - Visit visit, const char *preStr, bool useEmulatedFunction) +void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit, + TOperator op, + bool useEmulatedFunction) { - TString preString = useEmulatedFunction ? - BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr; - writeTriplet(visit, preString.c_str(), ", ", ")"); + TInfoSinkBase &out = objSink(); + if (visit == PreVisit) + { + const char *opStr(GetOperatorString(op)); + if (useEmulatedFunction) + { + BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr); + } + else + { + out << opStr; + } + out << "("; + } + else + { + writeTriplet(visit, nullptr, ", ", ")"); + } } -void TOutputGLSLBase::writeLayoutQualifier(const TType &type) +void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable) { - if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) + const TType &type = variable->getType(); + + if (!NeedsToWriteLayoutQualifier(type)) + { + return; + } + + TInfoSinkBase &out = objSink(); + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + out << "layout("; + + CommaSeparatedListItemPrefixGenerator listItemPrefix; + + if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || + IsVarying(type.getQualifier())) { - const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); if (layoutQualifier.location >= 0) { - TInfoSinkBase &out = objSink(); - out << "layout(location = " << layoutQualifier.location << ") "; + out << listItemPrefix << "location = " << layoutQualifier.location; + } + } + + if (type.getQualifier() == EvqFragmentOut) + { + if (layoutQualifier.yuv == true) + { + out << listItemPrefix << "yuv"; + } + } + + if (IsOpaqueType(type.getBasicType())) + { + if (layoutQualifier.binding >= 0) + { + out << listItemPrefix << "binding = " << layoutQualifier.binding; + } + } + + if (IsImage(type.getBasicType())) + { + if (layoutQualifier.imageInternalFormat != EiifUnspecified) + { + ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform); + out << listItemPrefix + << getImageInternalFormatString(layoutQualifier.imageInternalFormat); } } + + if (IsAtomicCounter(type.getBasicType())) + { + out << listItemPrefix << "offset = " << layoutQualifier.offset; + } + + out << ") "; +} + +const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier) +{ + if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 && + (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0) + { + switch (qualifier) + { + // The return string is consistent with sh::getQualifierString() from + // BaseTypes.h minus the "centroid" keyword. + case EvqCentroid: + return ""; + case EvqCentroidIn: + return "smooth in"; + case EvqCentroidOut: + return "smooth out"; + default: + break; + } + } + if (sh::IsGLSL130OrNewer(mOutput)) + { + switch (qualifier) + { + case EvqAttribute: + return "in"; + case EvqVaryingIn: + return "in"; + case EvqVaryingOut: + return "out"; + default: + break; + } + } + return sh::getQualifierString(qualifier); } void TOutputGLSLBase::writeVariableType(const TType &type) { - TInfoSinkBase &out = objSink(); + TQualifier qualifier = type.getQualifier(); + TInfoSinkBase &out = objSink(); if (type.isInvariant()) { - out << "invariant "; + writeInvariantQualifier(type); } if (type.getBasicType() == EbtInterfaceBlock) { TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); declareInterfaceBlockLayout(interfaceBlock); } - TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { - if (IsGLSL130OrNewer(mOutput)) + const char *qualifierString = mapQualifierToString(qualifier); + if (qualifierString && qualifierString[0] != '\0') { - switch (qualifier) - { - case EvqAttribute: - out << "in "; - break; - case EvqVaryingIn: - out << "in "; - break; - case EvqVaryingOut: - out << "out "; - break; - default: - out << type.getQualifierString() << " "; - break; - } - } - else - { - out << type.getQualifierString() << " "; + out << qualifierString << " "; } } + + const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier(); + if (memoryQualifier.readonly) + { + ASSERT(IsImage(type.getBasicType())); + out << "readonly "; + } + + if (memoryQualifier.writeonly) + { + ASSERT(IsImage(type.getBasicType())); + out << "writeonly "; + } + + if (memoryQualifier.coherent) + { + ASSERT(IsImage(type.getBasicType())); + out << "coherent "; + } + + if (memoryQualifier.restrictQualifier) + { + ASSERT(IsImage(type.getBasicType())); + out << "restrict "; + } + + if (memoryQualifier.volatileQualifier) + { + ASSERT(IsImage(type.getBasicType())); + out << "volatile "; + } + // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) { - TStructure *structure = type.getStruct(); + const TStructure *structure = type.getStruct(); declareStruct(structure); @@ -168,20 +331,18 @@ void TOutputGLSLBase::writeVariableType(const TType &type) void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args) { TInfoSinkBase &out = objSink(); - for (TIntermSequence::const_iterator iter = args.begin(); - iter != args.end(); ++iter) + for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter) { const TIntermSymbol *arg = (*iter)->getAsSymbolNode(); - ASSERT(arg != NULL); + ASSERT(arg != nullptr); const TType &type = arg->getType(); writeVariableType(type); - const TString &name = arg->getSymbol(); - if (!name.empty()) - out << " " << hashName(name); + if (!arg->getName().getString().empty()) + out << " " << hashName(arg->getName()); if (type.isArray()) - out << arrayBrackets(type); + out << ArrayString(type); // Put a comma if this is not the last argument. if (iter != args.end() - 1) @@ -189,21 +350,21 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args) } } -const TConstantUnion *TOutputGLSLBase::writeConstantUnion( - const TType &type, const TConstantUnion *pConstUnion) +const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type, + const TConstantUnion *pConstUnion) { TInfoSinkBase &out = objSink(); if (type.getBasicType() == EbtStruct) { const TStructure *structure = type.getStruct(); - out << hashName(structure->name()) << "("; + out << hashName(TName(structure->name())) << "("; const TFieldList &fields = structure->fields(); for (size_t i = 0; i < fields.size(); ++i) { const TType *fieldType = fields[i]->type(); - ASSERT(fieldType != NULL); + ASSERT(fieldType != nullptr); pConstUnion = writeConstantUnion(*fieldType, pConstUnion); if (i != fields.size() - 1) out << ", "; @@ -212,7 +373,7 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion( } else { - size_t size = type.getObjectSize(); + size_t size = type.getObjectSize(); bool writeType = size > 1; if (writeType) out << getTypeName(type) << "("; @@ -220,19 +381,23 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion( { switch (pConstUnion->getType()) { - case EbtFloat: - out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); - break; - case EbtInt: - out << pConstUnion->getIConst(); - break; - case EbtUInt: - out << pConstUnion->getUConst() << "u"; - break; - case EbtBool: - out << pConstUnion->getBConst(); - break; - default: UNREACHABLE(); + case EbtFloat: + writeFloat(out, pConstUnion->getFConst()); + break; + case EbtInt: + out << pConstUnion->getIConst(); + break; + case EbtUInt: + out << pConstUnion->getUConst() << "u"; + break; + case EbtBool: + out << pConstUnion->getBConst(); + break; + case EbtYuvCscStandardEXT: + out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst()); + break; + default: + UNREACHABLE(); } if (i != size - 1) out << ", "; @@ -243,20 +408,20 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion( return pConstUnion; } -void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType) +void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type) { TInfoSinkBase &out = objSink(); if (visit == PreVisit) { if (type.isArray()) { - out << constructorBaseType; - out << arrayBrackets(type); + out << getTypeName(type); + out << ArrayString(type); out << "("; } else { - out << constructorBaseType << "("; + out << getTypeName(type) << "("; } } else @@ -268,13 +433,10 @@ void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, co void TOutputGLSLBase::visitSymbol(TIntermSymbol *node) { TInfoSinkBase &out = objSink(); - if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node)) - out << mLoopUnrollStack.getLoopIndexValue(node); - else - out << hashVariableName(node->getSymbol()); + out << hashVariableName(node->getName()); - if (mDeclaringVariables && node->getType().isArray()) - out << arrayBrackets(node->getType()); + if (mDeclaringVariable && node->getType().isArray()) + out << ArrayString(node->getType()); } void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) @@ -282,241 +444,246 @@ void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) writeConstantUnion(node->getType(), node->getUnionArrayPointer()); } +bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = objSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; TInfoSinkBase &out = objSink(); switch (node->getOp()) { - case EOpInitialize: - if (visit == InVisit) - { - out << " = "; - // RHS of initialize is not being declared. - mDeclaringVariables = false; - } - break; - case EOpAssign: - writeTriplet(visit, "(", " = ", ")"); - break; - case EOpAddAssign: - writeTriplet(visit, "(", " += ", ")"); - break; - case EOpSubAssign: - writeTriplet(visit, "(", " -= ", ")"); - break; - case EOpDivAssign: - writeTriplet(visit, "(", " /= ", ")"); - break; - case EOpIModAssign: - writeTriplet(visit, "(", " %= ", ")"); - break; - // Notice the fall-through. - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - writeTriplet(visit, "(", " *= ", ")"); - break; - case EOpBitShiftLeftAssign: - writeTriplet(visit, "(", " <<= ", ")"); - break; - case EOpBitShiftRightAssign: - writeTriplet(visit, "(", " >>= ", ")"); - break; - case EOpBitwiseAndAssign: - writeTriplet(visit, "(", " &= ", ")"); - break; - case EOpBitwiseXorAssign: - writeTriplet(visit, "(", " ^= ", ")"); - break; - case EOpBitwiseOrAssign: - writeTriplet(visit, "(", " |= ", ")"); - break; - - case EOpIndexDirect: - writeTriplet(visit, NULL, "[", "]"); - break; - case EOpIndexIndirect: - if (node->getAddIndexClamp()) - { + case EOpComma: + writeTriplet(visit, "(", ", ", ")"); + break; + case EOpInitialize: if (visit == InVisit) { - if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) - out << "[int(clamp(float("; - else - out << "[webgl_int_clamp("; + out << " = "; + // RHS of initialize is not being declared. + mDeclaringVariable = false; } - else if (visit == PostVisit) - { - int maxSize; - TIntermTyped *left = node->getLeft(); - TType leftType = left->getType(); + break; + case EOpAssign: + writeTriplet(visit, "(", " = ", ")"); + break; + case EOpAddAssign: + writeTriplet(visit, "(", " += ", ")"); + break; + case EOpSubAssign: + writeTriplet(visit, "(", " -= ", ")"); + break; + case EOpDivAssign: + writeTriplet(visit, "(", " /= ", ")"); + break; + case EOpIModAssign: + writeTriplet(visit, "(", " %= ", ")"); + break; + // Notice the fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + writeTriplet(visit, "(", " *= ", ")"); + break; + case EOpBitShiftLeftAssign: + writeTriplet(visit, "(", " <<= ", ")"); + break; + case EOpBitShiftRightAssign: + writeTriplet(visit, "(", " >>= ", ")"); + break; + case EOpBitwiseAndAssign: + writeTriplet(visit, "(", " &= ", ")"); + break; + case EOpBitwiseXorAssign: + writeTriplet(visit, "(", " ^= ", ")"); + break; + case EOpBitwiseOrAssign: + writeTriplet(visit, "(", " |= ", ")"); + break; - if (left->isArray()) + case EOpIndexDirect: + writeTriplet(visit, nullptr, "[", "]"); + break; + case EOpIndexIndirect: + if (node->getAddIndexClamp()) + { + if (visit == InVisit) { - // The shader will fail validation if the array length is not > 0. - maxSize = leftType.getArraySize() - 1; + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "[int(clamp(float("; + else + out << "[webgl_int_clamp("; } - else + else if (visit == PostVisit) { - maxSize = leftType.getNominalSize() - 1; + TIntermTyped *left = node->getLeft(); + TType leftType = left->getType(); + + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "), 0.0, float("; + else + out << ", 0, "; + + if (leftType.isUnsizedArray()) + { + // For runtime-sized arrays in ESSL 3.10 we need to call the length method + // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note + // that a runtime-sized array expression is guaranteed not to have side + // effects, so it's fine to add the expression to the output twice. + ASSERT(mShaderVersion >= 310); + ASSERT(!left->hasSideEffects()); + left->traverse(this); + out << ".length() - 1"; + } + else + { + int maxSize; + if (leftType.isArray()) + { + maxSize = static_cast(leftType.getOutermostArraySize()) - 1; + } + else + { + maxSize = leftType.getNominalSize() - 1; + } + out << maxSize; + } + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << ")))]"; + else + out << ")]"; } - - if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) - out << "), 0.0, float(" << maxSize << ")))]"; - else - out << ", 0, " << maxSize << ")]"; } - } - else - { - writeTriplet(visit, NULL, "[", "]"); - } - break; - case EOpIndexDirectStruct: - if (visit == InVisit) - { - // Here we are writing out "foo.bar", where "foo" is struct - // and "bar" is field. In AST, it is represented as a binary - // node, where left child represents "foo" and right child "bar". - // The node itself represents ".". The struct field "bar" is - // actually stored as an index into TStructure::fields. - out << "."; - const TStructure *structure = node->getLeft()->getType().getStruct(); - const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); - const TField *field = structure->fields()[index->getIConst(0)]; - - TString fieldName = field->name(); - if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion)) - fieldName = hashName(fieldName); - - out << fieldName; - 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) - { - out << "."; - TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); - TIntermSequence *sequence = rightChild->getSequence(); - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit) + else + { + writeTriplet(visit, nullptr, "[", "]"); + } + break; + case EOpIndexDirectStruct: + if (visit == InVisit) { - TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); - ASSERT(element->getBasicType() == EbtInt); - ASSERT(element->getNominalSize() == 1); - const TConstantUnion& data = element->getUnionArrayPointer()[0]; - ASSERT(data.getType() == EbtInt); - switch (data.getIConst()) + // Here we are writing out "foo.bar", where "foo" is struct + // and "bar" is field. In AST, it is represented as a binary + // node, where left child represents "foo" and right child "bar". + // The node itself represents ".". The struct field "bar" is + // actually stored as an index into TStructure::fields. + out << "."; + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + + TString fieldName = field->name(); + if (!mSymbolTable->findBuiltIn(structure->name(), mShaderVersion)) + fieldName = hashName(TName(fieldName)); + + out << fieldName; + 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(); + if (!mSymbolTable->findBuiltIn(interfaceBlock->name(), mShaderVersion)) { - case 0: - out << "x"; - break; - case 1: - out << "y"; - break; - case 2: - out << "z"; - break; - case 3: - out << "w"; - break; - default: - UNREACHABLE(); + fieldName = hashName(TName(fieldName)); } + else + { + ASSERT(interfaceBlock->name() == "gl_PerVertex"); + } + + out << fieldName; + visitChildren = false; } - visitChildren = false; - } - break; - - case EOpAdd: - writeTriplet(visit, "(", " + ", ")"); - break; - case EOpSub: - writeTriplet(visit, "(", " - ", ")"); - break; - case EOpMul: - writeTriplet(visit, "(", " * ", ")"); - break; - case EOpDiv: - writeTriplet(visit, "(", " / ", ")"); - break; - case EOpIMod: - writeTriplet(visit, "(", " % ", ")"); - break; - case EOpBitShiftLeft: - writeTriplet(visit, "(", " << ", ")"); - break; - case EOpBitShiftRight: - writeTriplet(visit, "(", " >> ", ")"); - break; - case EOpBitwiseAnd: - writeTriplet(visit, "(", " & ", ")"); - break; - case EOpBitwiseXor: - writeTriplet(visit, "(", " ^ ", ")"); - break; - case EOpBitwiseOr: - writeTriplet(visit, "(", " | ", ")"); - break; - - case EOpEqual: - writeTriplet(visit, "(", " == ", ")"); - break; - case EOpNotEqual: - writeTriplet(visit, "(", " != ", ")"); - break; - case EOpLessThan: - writeTriplet(visit, "(", " < ", ")"); - break; - case EOpGreaterThan: - writeTriplet(visit, "(", " > ", ")"); - break; - case EOpLessThanEqual: - writeTriplet(visit, "(", " <= ", ")"); - break; - case EOpGreaterThanEqual: - writeTriplet(visit, "(", " >= ", ")"); - break; - - // Notice the fall-through. - case EOpVectorTimesScalar: - case EOpVectorTimesMatrix: - case EOpMatrixTimesVector: - case EOpMatrixTimesScalar: - case EOpMatrixTimesMatrix: - writeTriplet(visit, "(", " * ", ")"); - break; - - case EOpLogicalOr: - writeTriplet(visit, "(", " || ", ")"); - break; - case EOpLogicalXor: - writeTriplet(visit, "(", " ^^ ", ")"); - break; - case EOpLogicalAnd: - writeTriplet(visit, "(", " && ", ")"); - break; - default: - UNREACHABLE(); + break; + + case EOpAdd: + writeTriplet(visit, "(", " + ", ")"); + break; + case EOpSub: + writeTriplet(visit, "(", " - ", ")"); + break; + case EOpMul: + writeTriplet(visit, "(", " * ", ")"); + break; + case EOpDiv: + writeTriplet(visit, "(", " / ", ")"); + break; + case EOpIMod: + writeTriplet(visit, "(", " % ", ")"); + break; + case EOpBitShiftLeft: + writeTriplet(visit, "(", " << ", ")"); + break; + case EOpBitShiftRight: + writeTriplet(visit, "(", " >> ", ")"); + break; + case EOpBitwiseAnd: + writeTriplet(visit, "(", " & ", ")"); + break; + case EOpBitwiseXor: + writeTriplet(visit, "(", " ^ ", ")"); + break; + case EOpBitwiseOr: + writeTriplet(visit, "(", " | ", ")"); + break; + + case EOpEqual: + writeTriplet(visit, "(", " == ", ")"); + break; + case EOpNotEqual: + writeTriplet(visit, "(", " != ", ")"); + break; + case EOpLessThan: + writeTriplet(visit, "(", " < ", ")"); + break; + case EOpGreaterThan: + writeTriplet(visit, "(", " > ", ")"); + break; + case EOpLessThanEqual: + writeTriplet(visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqual: + writeTriplet(visit, "(", " >= ", ")"); + break; + + // Notice the fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + writeTriplet(visit, "(", " * ", ")"); + break; + + case EOpLogicalOr: + writeTriplet(visit, "(", " || ", ")"); + break; + case EOpLogicalXor: + writeTriplet(visit, "(", " ^^ ", ")"); + break; + case EOpLogicalAnd: + writeTriplet(visit, "(", " && ", ")"); + break; + default: + UNREACHABLE(); } return visitChildren; @@ -529,237 +696,148 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) switch (node->getOp()) { - case EOpNegative: preString = "(-"; break; - case EOpPositive: preString = "(+"; break; - case EOpVectorLogicalNot: preString = "not("; break; - case EOpLogicalNot: preString = "(!"; break; - case EOpBitwiseNot: preString = "(~"; break; - - case EOpPostIncrement: preString = "("; postString = "++)"; break; - case EOpPostDecrement: preString = "("; postString = "--)"; break; - case EOpPreIncrement: preString = "(++"; break; - case EOpPreDecrement: preString = "(--"; break; - - case EOpRadians: - preString = "radians("; - break; - case EOpDegrees: - preString = "degrees("; - break; - case EOpSin: - preString = "sin("; - break; - case EOpCos: - preString = "cos("; - break; - case EOpTan: - preString = "tan("; - break; - case EOpAsin: - preString = "asin("; - break; - case EOpAcos: - preString = "acos("; - break; - case EOpAtan: - preString = "atan("; - break; - - case EOpSinh: - preString = "sinh("; - break; - case EOpCosh: - preString = "cosh("; - break; - case EOpTanh: - preString = "tanh("; - break; - case EOpAsinh: - preString = "asinh("; - break; - case EOpAcosh: - preString = "acosh("; - break; - case EOpAtanh: - preString = "atanh("; - break; - - case EOpExp: - preString = "exp("; - break; - case EOpLog: - preString = "log("; - break; - case EOpExp2: - preString = "exp2("; - break; - case EOpLog2: - preString = "log2("; - break; - case EOpSqrt: - preString = "sqrt("; - break; - case EOpInverseSqrt: - preString = "inversesqrt("; - break; - - case EOpAbs: - preString = "abs("; - break; - case EOpSign: - preString = "sign("; - break; - case EOpFloor: - preString = "floor("; - break; - case EOpTrunc: - preString = "trunc("; - break; - case EOpRound: - preString = "round("; - break; - case EOpRoundEven: - preString = "roundEven("; - break; - case EOpCeil: - preString = "ceil("; - break; - case EOpFract: - preString = "fract("; - break; - case EOpIsNan: - preString = "isnan("; - break; - case EOpIsInf: - preString = "isinf("; - break; - - case EOpFloatBitsToInt: - preString = "floatBitsToInt("; - break; - case EOpFloatBitsToUint: - preString = "floatBitsToUint("; - break; - case EOpIntBitsToFloat: - preString = "intBitsToFloat("; - break; - case EOpUintBitsToFloat: - preString = "uintBitsToFloat("; - break; - - case EOpPackSnorm2x16: - preString = "packSnorm2x16("; - break; - case EOpPackUnorm2x16: - preString = "packUnorm2x16("; - break; - case EOpPackHalf2x16: - preString = "packHalf2x16("; - break; - case EOpUnpackSnorm2x16: - preString = "unpackSnorm2x16("; - break; - case EOpUnpackUnorm2x16: - preString = "unpackUnorm2x16("; - break; - case EOpUnpackHalf2x16: - preString = "unpackHalf2x16("; - break; - - case EOpLength: - preString = "length("; - break; - case EOpNormalize: - preString = "normalize("; - break; - - case EOpDFdx: - preString = "dFdx("; - break; - case EOpDFdy: - preString = "dFdy("; - break; - case EOpFwidth: - preString = "fwidth("; - break; - - case EOpTranspose: - preString = "transpose("; - break; - case EOpDeterminant: - preString = "determinant("; - break; - case EOpInverse: - preString = "inverse("; - break; - - case EOpAny: - preString = "any("; - break; - case EOpAll: - preString = "all("; - break; - - default: - UNREACHABLE(); + case EOpNegative: + preString = "(-"; + break; + case EOpPositive: + preString = "(+"; + break; + case EOpLogicalNot: + preString = "(!"; + break; + case EOpBitwiseNot: + preString = "(~"; + break; + + case EOpPostIncrement: + preString = "("; + postString = "++)"; + break; + case EOpPostDecrement: + preString = "("; + postString = "--)"; + break; + case EOpPreIncrement: + preString = "(++"; + break; + case EOpPreDecrement: + preString = "(--"; + break; + case EOpArrayLength: + preString = "(("; + postString = ").length())"; + break; + + case EOpRadians: + case EOpDegrees: + case EOpSin: + case EOpCos: + case EOpTan: + case EOpAsin: + case EOpAcos: + case EOpAtan: + case EOpSinh: + case EOpCosh: + case EOpTanh: + case EOpAsinh: + case EOpAcosh: + case EOpAtanh: + case EOpExp: + case EOpLog: + case EOpExp2: + case EOpLog2: + case EOpSqrt: + case EOpInverseSqrt: + case EOpAbs: + case EOpSign: + case EOpFloor: + case EOpTrunc: + case EOpRound: + case EOpRoundEven: + case EOpCeil: + case EOpFract: + case EOpIsNan: + case EOpIsInf: + case EOpFloatBitsToInt: + case EOpFloatBitsToUint: + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + case EOpUnpackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + case EOpLength: + case EOpNormalize: + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + case EOpTranspose: + case EOpDeterminant: + case EOpInverse: + case EOpAny: + case EOpAll: + case EOpLogicalNotComponentWise: + case EOpBitfieldReverse: + case EOpBitCount: + case EOpFindLSB: + case EOpFindMSB: + writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction()); + return true; + default: + UNREACHABLE(); } - if (visit == PreVisit && node->getUseEmulatedFunction()) - preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); - writeTriplet(visit, preString.c_str(), NULL, postString.c_str()); + writeTriplet(visit, preString.c_str(), nullptr, postString.c_str()); return true; } -bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) +bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node) { TInfoSinkBase &out = objSink(); + // Notice two brackets at the beginning and end. The outer ones + // encapsulate the whole ternary expression. This preserves the + // order of precedence when ternary expressions are used in a + // compound expression, i.e., c = 2 * (a < b ? 1 : 2). + out << "(("; + node->getCondition()->traverse(this); + out << ") ? ("; + node->getTrueExpression()->traverse(this); + out << ") : ("; + node->getFalseExpression()->traverse(this); + out << "))"; + return false; +} - if (node->usesTernaryOperator()) - { - // Notice two brackets at the beginning and end. The outer ones - // encapsulate the whole ternary expression. This preserves the - // order of precedence when ternary expressions are used in a - // compound expression, i.e., c = 2 * (a < b ? 1 : 2). - out << "(("; - node->getCondition()->traverse(this); - out << ") ? ("; - node->getTrueBlock()->traverse(this); - out << ") : ("; - node->getFalseBlock()->traverse(this); - out << "))"; - } - else - { - out << "if ("; - node->getCondition()->traverse(this); - out << ")\n"; +bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = objSink(); - incrementDepth(node); - visitCodeBlock(node->getTrueBlock()); + out << "if ("; + node->getCondition()->traverse(this); + out << ")\n"; - if (node->getFalseBlock()) - { - out << "else\n"; - visitCodeBlock(node->getFalseBlock()); - } - decrementDepth(); + visitCodeBlock(node->getTrueBlock()); + + if (node->getFalseBlock()) + { + out << "else\n"; + visitCodeBlock(node->getFalseBlock()); } return false; } bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node) { - if (node->getStatementList()) - { - writeTriplet(visit, "switch (", ") ", nullptr); - // The curly braces get written when visiting the statementList aggregate - } - else - { - // No statementList, so it won't output curly braces - writeTriplet(visit, "switch (", ") {", "}\n"); - } + ASSERT(node->getStatementList()); + writeTriplet(visit, "switch (", ") ", nullptr); + // The curly braces get written when visiting the statementList aggregate return true; } @@ -778,369 +856,208 @@ bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node) } } -bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) +bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node) { - bool visitChildren = true; TInfoSinkBase &out = objSink(); - bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction()); - switch (node->getOp()) + // Scope the blocks except when at the global scope. + if (mDepth > 0) { - case EOpSequence: - // Scope the sequences except when at the global scope. - if (mDepth > 0) - { - out << "{\n"; - } + out << "{\n"; + } - incrementDepth(node); - for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); - iter != node->getSequence()->end(); ++iter) - { - TIntermNode *curNode = *iter; - ASSERT(curNode != NULL); - curNode->traverse(this); + for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); + iter != node->getSequence()->end(); ++iter) + { + TIntermNode *curNode = *iter; + ASSERT(curNode != nullptr); + curNode->traverse(this); - if (isSingleStatement(curNode)) - out << ";\n"; - } - decrementDepth(); + if (isSingleStatement(curNode)) + out << ";\n"; + } - // Scope the sequences except when at the global scope. - if (mDepth > 0) - { - out << "}\n"; - } - visitChildren = false; - break; - case EOpPrototype: - // Function declaration. - ASSERT(visit == PreVisit); - { - const TType &type = node->getType(); - writeVariableType(type); - if (type.isArray()) - out << arrayBrackets(type); - } + // Scope the blocks except when at the global scope. + if (mDepth > 0) + { + out << "}\n"; + } + return false; +} - out << " " << hashFunctionNameIfNeeded(node->getNameObj()); +bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + TIntermFunctionPrototype *prototype = node->getFunctionPrototype(); + prototype->traverse(this); + visitCodeBlock(node->getBody()); - out << "("; - writeFunctionParameters(*(node->getSequence())); - out << ")"; + // Fully processed; no need to visit children. + return false; +} - visitChildren = false; - break; - case EOpFunction: { - // Function definition. - ASSERT(visit == PreVisit); - { - const TType &type = node->getType(); - writeVariableType(type); - if (type.isArray()) - out << arrayBrackets(type); - } +bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + TInfoSinkBase &out = objSink(); + ASSERT(visit == PreVisit); + const TIntermSymbol *symbol = node->getSymbol(); + out << "invariant " << hashVariableName(symbol->getName()); + return false; +} + +bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) +{ + TInfoSinkBase &out = objSink(); + ASSERT(visit == PreVisit); - out << " " << hashFunctionNameIfNeeded(node->getNameObj()); + const TType &type = node->getType(); + writeVariableType(type); + if (type.isArray()) + out << ArrayString(type); + + out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo()); + + out << "("; + writeFunctionParameters(*(node->getSequence())); + out << ")"; + + return false; +} + +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) +{ + bool visitChildren = true; + TInfoSinkBase &out = objSink(); + switch (node->getOp()) + { + case EOpCallFunctionInAST: + case EOpCallInternalRawFunction: + case EOpCallBuiltInFunction: + // Function call. + if (visit == PreVisit) + { + if (node->getOp() == EOpCallBuiltInFunction) + { + out << translateTextureFunction(node->getFunctionSymbolInfo()->getName()); + } + else + { + out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo()); + } + out << "("; + } + else if (visit == InVisit) + out << ", "; + else + out << ")"; + break; + case EOpConstruct: + writeConstructorTriplet(visit, node->getType()); + break; - incrementDepth(node); - // Function definition node contains one or two children nodes - // representing function parameters and function body. The latter - // is not present in case of empty function bodies. + case EOpEqualComponentWise: + case EOpNotEqualComponentWise: + case EOpLessThanComponentWise: + case EOpGreaterThanComponentWise: + case EOpLessThanEqualComponentWise: + case EOpGreaterThanEqualComponentWise: + case EOpMod: + case EOpModf: + case EOpPow: + case EOpAtan: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothStep: + case EOpFrexp: + case EOpLdexp: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceforward: + case EOpReflect: + case EOpRefract: + case EOpMulMatrixComponentWise: + case EOpOuterProduct: + case EOpBitfieldExtract: + case EOpBitfieldInsert: + case EOpUaddCarry: + case EOpUsubBorrow: + case EOpUmulExtended: + case EOpImulExtended: + case EOpBarrier: + case EOpMemoryBarrier: + case EOpMemoryBarrierAtomicCounter: + case EOpMemoryBarrierBuffer: + case EOpMemoryBarrierImage: + case EOpMemoryBarrierShared: + case EOpGroupMemoryBarrier: + case EOpEmitVertex: + case EOpEndPrimitive: + writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction()); + break; + default: + UNREACHABLE(); + } + return visitChildren; +} + +bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + TInfoSinkBase &out = objSink(); + + // Variable declaration. + if (visit == PreVisit) + { const TIntermSequence &sequence = *(node->getSequence()); - ASSERT((sequence.size() == 1) || (sequence.size() == 2)); - TIntermSequence::const_iterator seqIter = sequence.begin(); - - // Traverse function parameters. - TIntermAggregate *params = (*seqIter)->getAsAggregate(); - ASSERT(params != NULL); - ASSERT(params->getOp() == EOpParameters); - params->traverse(this); - - // Traverse function body. - TIntermAggregate *body = ++seqIter != sequence.end() ? - (*seqIter)->getAsAggregate() : NULL; - visitCodeBlock(body); - decrementDepth(); - - // Fully processed; no need to visit children. - visitChildren = false; - break; - } - case EOpFunctionCall: - // Function call. - if (visit == PreVisit) - out << hashFunctionNameIfNeeded(node->getNameObj()) << "("; - else if (visit == InVisit) - out << ", "; - else - out << ")"; - break; - case EOpParameters: - // Function parameters. - ASSERT(visit == PreVisit); - out << "("; - writeFunctionParameters(*(node->getSequence())); - out << ")"; - visitChildren = false; - break; - case EOpDeclaration: - // Variable declaration. - if (visit == PreVisit) + TIntermTyped *variable = sequence.front()->getAsTyped(); + writeLayoutQualifier(variable); + writeVariableType(variable->getType()); + if (variable->getAsSymbolNode() == nullptr || + !variable->getAsSymbolNode()->getSymbol().empty()) { - const TIntermSequence &sequence = *(node->getSequence()); - const TIntermTyped *variable = sequence.front()->getAsTyped(); - writeLayoutQualifier(variable->getType()); - writeVariableType(variable->getType()); out << " "; - mDeclaringVariables = true; - } - else if (visit == InVisit) - { - out << ", "; - mDeclaringVariables = true; - } - else - { - mDeclaringVariables = false; - } - break; - case EOpInvariantDeclaration: - // Invariant declaration. - ASSERT(visit == PreVisit); - { - const TIntermSequence *sequence = node->getSequence(); - ASSERT(sequence && sequence->size() == 1); - const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode(); - ASSERT(symbol); - out << "invariant " << hashVariableName(symbol->getSymbol()); - } - visitChildren = false; - break; - case EOpConstructFloat: - writeConstructorTriplet(visit, node->getType(), "float"); - break; - case EOpConstructVec2: - writeConstructorTriplet(visit, node->getType(), "vec2"); - break; - case EOpConstructVec3: - writeConstructorTriplet(visit, node->getType(), "vec3"); - break; - case EOpConstructVec4: - writeConstructorTriplet(visit, node->getType(), "vec4"); - break; - case EOpConstructBool: - writeConstructorTriplet(visit, node->getType(), "bool"); - break; - case EOpConstructBVec2: - writeConstructorTriplet(visit, node->getType(), "bvec2"); - break; - case EOpConstructBVec3: - writeConstructorTriplet(visit, node->getType(), "bvec3"); - break; - case EOpConstructBVec4: - writeConstructorTriplet(visit, node->getType(), "bvec4"); - break; - case EOpConstructInt: - writeConstructorTriplet(visit, node->getType(), "int"); - break; - case EOpConstructIVec2: - writeConstructorTriplet(visit, node->getType(), "ivec2"); - break; - case EOpConstructIVec3: - writeConstructorTriplet(visit, node->getType(), "ivec3"); - break; - case EOpConstructIVec4: - 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: - 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: - 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: - writeConstructorTriplet(visit, node->getType(), "mat4"); - break; - case EOpConstructStruct: - { - const TType &type = node->getType(); - ASSERT(type.getBasicType() == EbtStruct); - TString constructorName = hashName(type.getStruct()->name()); - writeConstructorTriplet(visit, node->getType(), constructorName.c_str()); - break; } - - case EOpOuterProduct: - writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction); - break; - - case EOpLessThan: - writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); - break; - case EOpGreaterThan: - writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction); - break; - case EOpLessThanEqual: - writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction); - break; - case EOpGreaterThanEqual: - writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction); - break; - case EOpVectorEqual: - writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction); - break; - case EOpVectorNotEqual: - writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction); - break; - case EOpComma: - writeTriplet(visit, "(", ", ", ")"); - break; - - case EOpMod: - writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); - break; - case EOpModf: - writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction); - break; - case EOpPow: - writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); - break; - case EOpAtan: - writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction); - break; - case EOpMin: - writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction); - break; - case EOpMax: - writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction); - break; - case EOpClamp: - writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction); - break; - case EOpMix: - writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction); - break; - case EOpStep: - writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction); - break; - case EOpSmoothStep: - writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction); - break; - case EOpDistance: - writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction); - break; - case EOpDot: - writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction); - break; - case EOpCross: - writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction); - break; - case EOpFaceForward: - writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction); - break; - case EOpReflect: - writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction); - break; - case EOpRefract: - writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction); - break; - case EOpMul: - writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction); - break; - - default: + mDeclaringVariable = true; + } + else if (visit == InVisit) + { UNREACHABLE(); } - return visitChildren; + else + { + mDeclaringVariable = false; + } + return true; } bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) { TInfoSinkBase &out = objSink(); - incrementDepth(node); - TLoopType loopType = node->getType(); - // Only for loops can be unrolled - ASSERT(!node->getUnrollFlag() || loopType == ELoopFor); - if (loopType == ELoopFor) // for loop { - if (!node->getUnrollFlag()) - { - out << "for ("; - if (node->getInit()) - node->getInit()->traverse(this); - out << "; "; + out << "for ("; + if (node->getInit()) + node->getInit()->traverse(this); + out << "; "; - if (node->getCondition()) - node->getCondition()->traverse(this); - out << "; "; + if (node->getCondition()) + node->getCondition()->traverse(this); + out << "; "; - if (node->getExpression()) - node->getExpression()->traverse(this); - out << ")\n"; + if (node->getExpression()) + node->getExpression()->traverse(this); + out << ")\n"; - visitCodeBlock(node->getBody()); - } - else - { - // Need to put a one-iteration loop here to handle break. - TIntermSequence *declSeq = - node->getInit()->getAsAggregate()->getSequence(); - TIntermSymbol *indexSymbol = - (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); - TString name = hashVariableName(indexSymbol->getSymbol()); - out << "for (int " << name << " = 0; " - << name << " < 1; " - << "++" << name << ")\n"; - - out << "{\n"; - mLoopUnrollStack.push(node); - while (mLoopUnrollStack.satisfiesLoopCondition()) - { - visitCodeBlock(node->getBody()); - mLoopUnrollStack.step(); - } - mLoopUnrollStack.pop(); - out << "}\n"; - } + visitCodeBlock(node->getBody()); } else if (loopType == ELoopWhile) // while loop { out << "while ("; - ASSERT(node->getCondition() != NULL); + ASSERT(node->getCondition() != nullptr); node->getCondition()->traverse(this); out << ")\n"; @@ -1154,13 +1071,11 @@ bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) visitCodeBlock(node->getBody()); out << "while ("; - ASSERT(node->getCondition() != NULL); + ASSERT(node->getCondition() != nullptr); node->getCondition()->traverse(this); out << ");\n"; } - decrementDepth(); - // No need to visit children. They have been already processed in // this function. return false; @@ -1170,29 +1085,29 @@ bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node) { switch (node->getFlowOp()) { - case EOpKill: - writeTriplet(visit, "discard", NULL, NULL); - break; - case EOpBreak: - writeTriplet(visit, "break", NULL, NULL); - break; - case EOpContinue: - writeTriplet(visit, "continue", NULL, NULL); - break; - case EOpReturn: - writeTriplet(visit, "return ", NULL, NULL); - break; - default: - UNREACHABLE(); + case EOpKill: + writeTriplet(visit, "discard", nullptr, nullptr); + break; + case EOpBreak: + writeTriplet(visit, "break", nullptr, nullptr); + break; + case EOpContinue: + writeTriplet(visit, "continue", nullptr, nullptr); + break; + case EOpReturn: + writeTriplet(visit, "return ", nullptr, nullptr); + break; + default: + UNREACHABLE(); } return true; } -void TOutputGLSLBase::visitCodeBlock(TIntermNode *node) +void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node) { TInfoSinkBase &out = objSink(); - if (node != NULL) + if (node != nullptr) { node->traverse(this); // Single statements not part of a sequence need to be terminated @@ -1208,76 +1123,41 @@ void TOutputGLSLBase::visitCodeBlock(TIntermNode *node) TString TOutputGLSLBase::getTypeName(const TType &type) { - TInfoSinkBase out; - if (type.isMatrix()) - { - out << "mat"; - out << type.getNominalSize(); - if (type.getSecondarySize() != type.getNominalSize()) - { - out << "x" << type.getSecondarySize(); - } - } - else if (type.isVector()) - { - switch (type.getBasicType()) - { - case EbtFloat: - out << "vec"; - break; - case EbtInt: - out << "ivec"; - break; - case EbtBool: - out << "bvec"; - break; - case EbtUInt: - out << "uvec"; - break; - default: - UNREACHABLE(); - } - out << type.getNominalSize(); - } - else - { - if (type.getBasicType() == EbtStruct) - out << hashName(type.getStruct()->name()); - else - out << type.getBasicString(); - } - return TString(out.c_str()); + return GetTypeName(type, mHashFunction, &mNameMap); } -TString TOutputGLSLBase::hashName(const TString &name) +TString TOutputGLSLBase::hashName(const TName &name) { - if (mHashFunction == NULL || name.empty()) - return name; - NameMap::const_iterator it = mNameMap.find(name.c_str()); - if (it != mNameMap.end()) - return it->second.c_str(); - TString hashedName = TIntermTraverser::hash(name, mHashFunction); - mNameMap[name.c_str()] = hashedName.c_str(); - return hashedName; + return HashName(name, mHashFunction, &mNameMap); } -TString TOutputGLSLBase::hashVariableName(const TString &name) +TString TOutputGLSLBase::hashVariableName(const TName &name) { - if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL) - return name; + if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr || + name.getString().substr(0, 3) == "gl_") + { + if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM && + name.getString() == "gl_ViewID_OVR") + { + TName uniformName(TString("ViewID_OVR")); + uniformName.setInternal(true); + return hashName(uniformName); + } + return name.getString(); + } return hashName(name); } -TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName) +TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info) { - TString mangledStr = mangledName.getString(); - TString name = TFunction::unmangleName(mangledStr); - if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main") - return translateTextureFunction(name); - if (mangledName.isInternal()) - return name; + if (info.isMain()) + { + return info.getName(); + } else - return hashName(name); + { + return hashName(info.getNameObj()); + } } bool TOutputGLSLBase::structDeclared(const TStructure *structure) const @@ -1295,16 +1175,16 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure) { TInfoSinkBase &out = objSink(); - out << "struct " << hashName(structure->name()) << "{\n"; + out << "struct " << hashName(TName(structure->name())) << "{\n"; const TFieldList &fields = structure->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()); + out << getTypeName(*field->type()) << " " << hashName(TName(field->name())); if (field->type()->isArray()) - out << arrayBrackets(*field->type()); + out << ArrayString(*field->type()); out << ";\n"; } out << "}"; @@ -1332,6 +1212,10 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa out << "std140"; break; + case EbsStd430: + out << "std430"; + break; + default: UNREACHABLE(); break; @@ -1339,6 +1223,12 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa out << ", "; + if (interfaceBlock->blockBinding() > 0) + { + out << "binding = " << interfaceBlock->blockBinding(); + out << ", "; + } + switch (interfaceBlock->matrixPacking()) { case EmpUnspecified: @@ -1363,17 +1253,105 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc { TInfoSinkBase &out = objSink(); - out << hashName(interfaceBlock->name()) << "{\n"; + out << hashName(TName(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()); + out << getTypeName(*field->type()) << " " << hashName(TName(field->name())); if (field->type()->isArray()) - out << arrayBrackets(*field->type()); + out << ArrayString(*field->type()); out << ";\n"; } out << "}"; } + +void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, + sh::TLayoutPrimitiveType inputPrimitive, + int invocations, + sh::TLayoutPrimitiveType outputPrimitive, + int maxVertices) +{ + // Omit 'invocations = 1' + if (inputPrimitive != EptUndefined || invocations > 1) + { + out << "layout ("; + + if (inputPrimitive != EptUndefined) + { + out << getGeometryShaderPrimitiveTypeString(inputPrimitive); + } + + if (invocations > 1) + { + if (inputPrimitive != EptUndefined) + { + out << ", "; + } + out << "invocations = " << invocations; + } + out << ") in;\n"; + } + + if (outputPrimitive != EptUndefined || maxVertices != -1) + { + out << "layout ("; + + if (outputPrimitive != EptUndefined) + { + out << getGeometryShaderPrimitiveTypeString(outputPrimitive); + } + + if (maxVertices != -1) + { + if (outputPrimitive != EptUndefined) + { + out << ", "; + } + out << "max_vertices = " << maxVertices; + } + out << ") out;\n"; + } +} + +// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever +// variables with specified layout qualifiers are copied. Additional checks are needed against the +// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted. +// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove +// NeedsToWriteLayoutQualifier. +bool NeedsToWriteLayoutQualifier(const TType &type) +{ + if (type.getBasicType() == EbtInterfaceBlock) + { + return false; + } + + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + + if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || + IsVarying(type.getQualifier())) && + layoutQualifier.location >= 0) + { + return true; + } + + if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true) + { + return true; + } + + if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1) + { + return true; + } + + if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified) + { + return true; + } + return false; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h index 2ae82d15b2..592a310be4 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h @@ -9,9 +9,12 @@ #include -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/LoopInfo.h" -#include "compiler/translator/ParseContext.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ class TOutputGLSLBase : public TIntermTraverser { @@ -20,48 +23,58 @@ class TOutputGLSLBase : public TIntermTraverser ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap &nameMap, - TSymbolTable& symbolTable, + TSymbolTable *symbolTable, + sh::GLenum shaderType, int shaderVersion, - ShShaderOutput output); + ShShaderOutput output, + ShCompileOptions compileOptions); + + ShShaderOutput getShaderOutput() const { return mOutput; } - ShShaderOutput getShaderOutput() const - { - return mOutput; - } + // Return the original name if hash function pointer is NULL; + // otherwise return the hashed name. Has special handling for internal names, which are not + // hashed. + TString hashName(const TName &name); protected: TInfoSinkBase &objSink() { return mObjSink; } + void writeFloat(TInfoSinkBase &out, float f); void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr); - void writeLayoutQualifier(const TType &type); + virtual void writeLayoutQualifier(TIntermTyped *variable); + void writeInvariantQualifier(const TType &type); void writeVariableType(const TType &type); virtual bool writeVariablePrecision(TPrecision precision) = 0; void writeFunctionParameters(const TIntermSequence &args); const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion); - void writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType); + void writeConstructorTriplet(Visit visit, const TType &type); TString getTypeName(const TType &type); void visitSymbol(TIntermSymbol *node) override; void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; bool visitBinary(Visit visit, TIntermBinary *node) override; bool visitUnary(Visit visit, TIntermUnary *node) override; - bool visitSelection(Visit visit, TIntermSelection *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; bool visitSwitch(Visit visit, TIntermSwitch *node) override; bool visitCase(Visit visit, TIntermCase *node) override; + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; bool visitLoop(Visit visit, TIntermLoop *node) override; bool visitBranch(Visit visit, TIntermBranch *node) override; - void visitCodeBlock(TIntermNode *node); + void visitCodeBlock(TIntermBlock *node); - // Return the original name if hash function pointer is NULL; - // otherwise return the hashed name. - 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 and with unmangling. - TString hashFunctionNameIfNeeded(const TName &mangledName); + TString hashVariableName(const TName &name); + // Same as hashName(), but without hashing internal functions or "main". + TString hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info); // Used to translate function names for differences between ESSL and GLSL - virtual TString translateTextureFunction(TString &name) { return name; } + virtual TString translateTextureFunction(const TString &name) { return name; } private: bool structDeclared(const TStructure *structure) const; @@ -70,17 +83,16 @@ class TOutputGLSLBase : public TIntermTraverser void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock); void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock); - void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction); + void writeBuiltInFunctionTriplet(Visit visit, TOperator op, bool useEmulatedFunction); + + const char *mapQualifierToString(TQualifier qialifier); TInfoSinkBase &mObjSink; - bool mDeclaringVariables; + bool mDeclaringVariable; // This set contains all the ids of the structs from every scope. std::set mDeclaredStructs; - // Stack of loops that need to be unrolled. - TLoopStack mLoopUnrollStack; - ShArrayIndexClampingStrategy mClampingStrategy; // name hashing. @@ -88,11 +100,23 @@ class TOutputGLSLBase : public TIntermTraverser NameMap &mNameMap; - TSymbolTable &mSymbolTable; + sh::GLenum mShaderType; const int mShaderVersion; ShShaderOutput mOutput; + + ShCompileOptions mCompileOptions; }; +void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, + sh::TLayoutPrimitiveType inputPrimitive, + int invocations, + sh::TLayoutPrimitiveType outputPrimitive, + int maxVertices); + +bool NeedsToWriteLayoutQualifier(const TType &type); + +} // namespace sh + #endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp index 253b96696c..d5ff761430 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp @@ -15,33 +15,95 @@ #include "common/utilities.h" #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" -#include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/ImageFunctionHLSL.h" #include "compiler/translator/InfoSink.h" #include "compiler/translator/NodeSearch.h" #include "compiler/translator/RemoveSwitchFallThrough.h" #include "compiler/translator/SearchSymbol.h" #include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/TextureFunctionHLSL.h" #include "compiler/translator/TranslatorHLSL.h" #include "compiler/translator/UniformHLSL.h" #include "compiler/translator/UtilsHLSL.h" #include "compiler/translator/blocklayout.h" #include "compiler/translator/util.h" +namespace sh +{ + namespace { -bool IsSequence(TIntermNode *node) +TString ArrayHelperFunctionName(const char *prefix, const TType &type) +{ + TStringStream fnName; + fnName << prefix << "_"; + if (type.isArray()) + { + for (unsigned int arraySize : *type.getArraySizes()) + { + fnName << arraySize << "_"; + } + } + fnName << TypeString(type); + return fnName.str(); +} + +bool IsDeclarationWrittenOut(TIntermDeclaration *node) +{ + TIntermSequence *sequence = node->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); + ASSERT(sequence->size() == 1); + ASSERT(variable); + return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal || + variable->getQualifier() == EvqConst); +} + +bool IsInStd140InterfaceBlock(TIntermTyped *node) +{ + TIntermBinary *binaryNode = node->getAsBinaryNode(); + + if (binaryNode) + { + return IsInStd140InterfaceBlock(binaryNode->getLeft()); + } + + const TType &type = node->getType(); + + // determine if we are in the standard layout + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + if (interfaceBlock) + { + return (interfaceBlock->blockStorage() == EbsStd140); + } + + return false; +} + +} // anonymous namespace + +void OutputHLSL::writeFloat(TInfoSinkBase &out, float f) { - return node->getAsAggregate() != nullptr && node->getAsAggregate()->getOp() == EOpSequence; + // This is known not to work for NaN on all drivers but make the best effort to output NaNs + // regardless. + if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 && + mOutputType == SH_HLSL_4_1_OUTPUT) + { + out << "asfloat(" << gl::bitCast(f) << "u)"; + } + else + { + out << std::min(FLT_MAX, std::max(-FLT_MAX, f)); + } } -void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion) +void OutputHLSL::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())); + writeFloat(out, constUnion->getFConst()); break; case EbtInt: out << constUnion->getIConst(); @@ -57,14 +119,14 @@ void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUn } } -const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out, - const TConstantUnion *const constUnion, - const size_t size) +const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out, + const TConstantUnion *const constUnion, + const size_t size) { const TConstantUnion *constUnionIterated = constUnion; for (size_t i = 0; i < size; i++, constUnionIterated++) { - WriteSingleConstant(out, constUnionIterated); + writeSingleConstant(out, constUnionIterated); if (i != size - 1) { @@ -74,71 +136,17 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out, 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) - { - name += "Proj"; - } - - if (offset) - { - name += "Offset"; - } - - switch(method) - { - case IMPLICIT: break; - case BIAS: break; // Extra parameter makes the signature unique - case LOD: name += "Lod"; break; - case LOD0: name += "Lod0"; break; - case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique - case SIZE: name += "Size"; break; - case FETCH: name += "Fetch"; break; - case GRAD: name += "Grad"; break; - default: UNREACHABLE(); - } - - return name + "("; -} - -bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const -{ - if (sampler < rhs.sampler) return true; - if (sampler > rhs.sampler) return false; - - if (coords < rhs.coords) return true; - if (coords > rhs.coords) return false; - - if (!proj && rhs.proj) return true; - if (proj && !rhs.proj) return false; - - if (!offset && rhs.offset) return true; - if (offset && !rhs.offset) return false; - - if (method < rhs.method) return true; - if (method > rhs.method) return false; - - return false; -} - -OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, - const TExtensionBehavior &extensionBehavior, - const char *sourcePath, ShShaderOutput outputType, - int numRenderTargets, const std::vector &uniforms, - int compileOptions) - : TIntermTraverser(true, true, true), +OutputHLSL::OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + const std::vector &uniforms, + ShCompileOptions compileOptions, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics) + : TIntermTraverser(true, true, true, symbolTable), mShaderType(shaderType), mShaderVersion(shaderVersion), mExtensionBehavior(extensionBehavior), @@ -146,51 +154,66 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, mOutputType(outputType), mCompileOptions(compileOptions), mNumRenderTargets(numRenderTargets), - mCurrentFunctionMetadata(nullptr) + mCurrentFunctionMetadata(nullptr), + mPerfDiagnostics(perfDiagnostics) { mInsideFunction = false; - mUsesFragColor = false; - mUsesFragData = false; - mUsesDepthRange = false; - mUsesFragCoord = false; - mUsesPointCoord = false; - mUsesFrontFacing = false; - mUsesPointSize = false; - mUsesInstanceID = false; - mUsesFragDepth = false; - mUsesXor = false; - mUsesDiscardRewriting = false; - mUsesNestedBreak = false; + mUsesFragColor = false; + mUsesFragData = false; + mUsesDepthRange = false; + mUsesFragCoord = false; + mUsesPointCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesInstanceID = false; + mHasMultiviewExtensionEnabled = + IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview); + mUsesViewID = false; + mUsesVertexID = false; + mUsesFragDepth = false; + mUsesNumWorkGroups = false; + mUsesWorkGroupID = false; + mUsesLocalInvocationID = false; + mUsesGlobalInvocationID = false; + mUsesLocalInvocationIndex = false; + mUsesXor = false; + mUsesDiscardRewriting = false; + mUsesNestedBreak = false; mRequiresIEEEStrictCompiling = false; mUniqueIndex = 0; - mOutputLod0Function = false; + mOutputLod0Function = false; mInsideDiscontinuousLoop = false; - mNestedLoopDepth = 0; + mNestedLoopDepth = 0; - mExcessiveLoopIndex = NULL; + mExcessiveLoopIndex = nullptr; - mStructureHLSL = new StructureHLSL; - mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms); + mStructureHLSL = new StructureHLSL; + mUniformHLSL = new UniformHLSL(shaderType, mStructureHLSL, outputType, uniforms); + mTextureFunctionHLSL = new TextureFunctionHLSL; + mImageFunctionHLSL = new ImageFunctionHLSL; 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. + // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and + // dx_ViewAdjust. // In both cases total 3 uniform registers need to be reserved. mUniformHLSL->reserveUniformRegisters(3); } // Reserve registers for the default uniform block and driver constants - mUniformHLSL->reserveInterfaceBlockRegisters(2); + mUniformHLSL->reserveUniformBlockRegisters(2); } OutputHLSL::~OutputHLSL() { SafeDelete(mStructureHLSL); SafeDelete(mUniformHLSL); + SafeDelete(mTextureFunctionHLSL); + SafeDelete(mImageFunctionHLSL); for (auto &eqFunction : mStructEqualityFunctions) { SafeDelete(eqFunction); @@ -203,71 +226,48 @@ OutputHLSL::~OutputHLSL() void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) { - const std::vector &flaggedStructs = FlagStd140ValueStructs(treeRoot); - makeFlaggedStructMaps(flaggedStructs); - BuiltInFunctionEmulator builtInFunctionEmulator; InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator); - builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot); + if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0) + { + InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator, + mShaderVersion); + } + + 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); + CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr); ASSERT(success == CallDAG::INITDAG_SUCCESS); - UNUSED_ASSERTION_VARIABLE(success); mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag); + const std::vector std140Structs = FlagStd140Structs(treeRoot); + // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in + // the shader code. When we add shader storage blocks we might also consider an alternative + // solution, since the struct mapping won't work very well for shader storage blocks. + // Output the body and footer first to determine what has to go in the header mInfoSinkStack.push(&mBody); treeRoot->traverse(this); mInfoSinkStack.pop(); mInfoSinkStack.push(&mFooter); - if (!mDeferredGlobalInitializers.empty()) - { - writeDeferredGlobalInitializers(mFooter); - } mInfoSinkStack.pop(); mInfoSinkStack.push(&mHeader); - header(mHeader, &builtInFunctionEmulator); + header(mHeader, std140Structs, &builtInFunctionEmulator); mInfoSinkStack.pop(); objSink << mHeader.c_str(); objSink << mBody.c_str(); objSink << mFooter.c_str(); - builtInFunctionEmulator.Cleanup(); -} - -void OutputHLSL::makeFlaggedStructMaps(const std::vector &flaggedStructs) -{ - for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++) - { - TIntermTyped *flaggedNode = flaggedStructs[structIndex]; - - TInfoSinkBase structInfoSink; - mInfoSinkStack.push(&structInfoSink); - - // This will mark the necessary block elements as referenced - flaggedNode->traverse(this); - - TString structName(structInfoSink.c_str()); - mInfoSinkStack.pop(); - - mFlaggedStructOriginalNames[flaggedNode] = structName; - - for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.')) - { - structName.erase(pos, 1); - } - - mFlaggedStructMappedNames[flaggedNode] = "map" + structName; - } + builtInFunctionEmulator.cleanup(); } -const std::map &OutputHLSL::getInterfaceBlockRegisterMap() const +const std::map &OutputHLSL::getUniformBlockRegisterMap() const { - return mUniformHLSL->getInterfaceBlockRegisterMap(); + return mUniformHLSL->getUniformBlockRegisterMap(); } const std::map &OutputHLSL::getUniformRegisterMap() const @@ -275,95 +275,161 @@ const std::map &OutputHLSL::getUniformRegisterMap() c return mUniformHLSL->getUniformRegisterMap(); } -int OutputHLSL::vectorSize(const TType &type) const -{ - int elementSize = type.isMatrix() ? type.getCols() : 1; - int arraySize = type.isArray() ? type.getArraySize() : 1; - - return elementSize * arraySize; -} - -TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName) +TString OutputHLSL::structInitializerString(int indent, + const TType &type, + const TString &name) const { TString init; - TString preIndentString; - TString fullIndentString; + TString indentString; + for (int spaces = 0; spaces < indent; spaces++) + { + indentString += " "; + } - for (int spaces = 0; spaces < (indent * 4); spaces++) + if (type.isArray()) { - preIndentString += ' '; + init += indentString + "{\n"; + for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex) + { + TStringStream indexedString; + indexedString << name << "[" << arrayIndex << "]"; + TType elementType = type; + elementType.toArrayElementType(); + init += structInitializerString(indent + 1, elementType, indexedString.str()); + if (arrayIndex < type.getOutermostArraySize() - 1) + { + init += ","; + } + init += "\n"; + } + init += indentString + "}"; } + else if (type.getBasicType() == EbtStruct) + { + init += indentString + "{\n"; + const TStructure &structure = *type.getStruct(); + const TFieldList &fields = structure.fields(); + for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const TField &field = *fields[fieldIndex]; + const TString &fieldName = name + "." + Decorate(field.name()); + const TType &fieldType = *field.type(); - for (int spaces = 0; spaces < ((indent+1) * 4); spaces++) + init += structInitializerString(indent + 1, fieldType, fieldName); + if (fieldIndex < fields.size() - 1) + { + init += ","; + } + init += "\n"; + } + init += indentString + "}"; + } + else { - fullIndentString += ' '; + init += indentString + name; } - init += preIndentString + "{\n"; + return init; +} - const TFieldList &fields = structure.fields(); - for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) - { - const TField &field = *fields[fieldIndex]; - const TString &fieldName = rhsStructName + "." + Decorate(field.name()); - const TType &fieldType = *field.type(); +TString OutputHLSL::generateStructMapping(const std::vector &std140Structs) const +{ + TString mappedStructs; - if (fieldType.getStruct()) + for (auto &mappedStruct : std140Structs) + { + TInterfaceBlock *interfaceBlock = + mappedStruct.blockDeclarator->getType().getInterfaceBlock(); + const TString &interfaceBlockName = interfaceBlock->name(); + const TName &instanceName = mappedStruct.blockDeclarator->getName(); + if (mReferencedUniformBlocks.count(interfaceBlockName) == 0 && + (instanceName.getString() == "" || + mReferencedUniformBlocks.count(instanceName.getString()) == 0)) { - init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName); + continue; } - else + + unsigned int instanceCount = 1u; + bool isInstanceArray = mappedStruct.blockDeclarator->isArray(); + if (isInstanceArray) { - init += fullIndentString + fieldName + ",\n"; + instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize(); } - } - init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n"; + for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount; + ++instanceArrayIndex) + { + TString originalName; + TString mappedName("map"); - return init; + if (instanceName.getString() != "") + { + unsigned int instanceStringArrayIndex = GL_INVALID_INDEX; + if (isInstanceArray) + instanceStringArrayIndex = instanceArrayIndex; + TString instanceString = mUniformHLSL->uniformBlockInstanceString( + *interfaceBlock, instanceStringArrayIndex); + originalName += instanceString; + mappedName += instanceString; + originalName += "."; + mappedName += "_"; + } + + TString fieldName = Decorate(mappedStruct.field->name()); + originalName += fieldName; + mappedName += fieldName; + + TType *structType = mappedStruct.field->type(); + mappedStructs += + "static " + Decorate(structType->getStruct()->name()) + " " + mappedName; + + if (structType->isArray()) + { + mappedStructs += ArrayString(*mappedStruct.field->type()); + } + + mappedStructs += " =\n"; + mappedStructs += structInitializerString(0, *structType, originalName); + mappedStructs += ";\n"; + } + } + return mappedStructs; } -void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator) +void OutputHLSL::header(TInfoSinkBase &out, + const std::vector &std140Structs, + const BuiltInFunctionEmulator *builtInFunctionEmulator) const { TString varyings; TString attributes; - TString flaggedStructs; - - for (std::map::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++) - { - TIntermTyped *structNode = flaggedStructIt->first; - const TString &mappedName = flaggedStructIt->second; - const TStructure &structure = *structNode->getType().getStruct(); - const TString &originalName = mFlaggedStructOriginalNames[structNode]; + TString mappedStructs = generateStructMapping(std140Structs); - flaggedStructs += "static " + Decorate(structure.name()) + " " + mappedName + " =\n"; - flaggedStructs += structInitializerString(0, structure, originalName); - flaggedStructs += "\n"; - } - - for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++) + for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); + varying != mReferencedVaryings.end(); varying++) { - const TType &type = varying->second->getType(); + const TType &type = varying->second->getType(); const TString &name = varying->second->getSymbol(); // Program linking depends on this exact format - varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + " " + - Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n"; + varyings += "static " + InterpolationString(type.getQualifier()) + " " + TypeString(type) + + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n"; } - for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++) + for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); + attribute != mReferencedAttributes.end(); attribute++) { - const TType &type = attribute->second->getType(); + const TType &type = attribute->second->getType(); const TString &name = attribute->second->getSymbol(); - attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + " = " + initializer(type) + ";\n"; + attributes += "static " + TypeString(type) + " " + Decorate(name) + ArrayString(type) + + " = " + initializer(type) + ";\n"; } out << mStructureHLSL->structsHeader(); - mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms); - out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks); + mUniformHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable); + out << mUniformHLSL->uniformBlocksHeader(mReferencedUniformBlocks); if (!mEqualityFunctions.empty()) { @@ -415,22 +481,24 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built if (mShaderType == GL_FRAGMENT_SHADER) { - TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers"); - const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire)); + const bool usingMRTExtension = + IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers); out << "// Varyings\n"; - out << varyings; + out << varyings; out << "\n"; if (mShaderVersion >= 300) { - for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) + for (ReferencedSymbols::const_iterator outputVariableIt = + mReferencedOutputVariables.begin(); + outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) { const TString &variableName = outputVariableIt->first; - const TType &variableType = outputVariableIt->second->getType(); + const TType &variableType = outputVariableIt->second->getType(); - out << "static " + TypeString(variableType) + " out_" + variableName + ArrayString(variableType) + - " = " + initializer(variableType) + ";\n"; + out << "static " + TypeString(variableType) + " out_" + variableName + + ArrayString(variableType) + " = " + initializer(variableType) + ";\n"; } } else @@ -438,7 +506,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; out << "static float4 gl_Color[" << numColorValues << "] =\n" - "{\n"; + "{\n"; for (unsigned int i = 0; i < numColorValues; i++) { out << " float4(0, 0, 0, 0)"; @@ -512,6 +580,18 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built out << " float2 dx_ViewScale : packoffset(c3);\n"; } + if (mHasMultiviewExtensionEnabled) + { + // We have to add a value which we can use to keep track of which multi-view code + // path is to be selected in the GS. + out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + mUniformHLSL->samplerMetadataUniforms(out, "c4"); + } + out << "};\n"; } else @@ -536,15 +616,16 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built if (mUsesDepthRange) { - out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, " + "dx_DepthRange.y, dx_DepthRange.z};\n" "\n"; } - if (!flaggedStructs.empty()) + if (!mappedStructs.empty()) { - out << "// Std140 Structures accessed by value\n"; + out << "// Structures from std140 blocks with padding removed\n"; out << "\n"; - out << flaggedStructs; + out << mappedStructs; out << "\n"; } @@ -563,10 +644,10 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built out << "#define GL_USES_FRAG_DATA\n"; } } - else // Vertex shader + else if (mShaderType == GL_VERTEX_SHADER) { out << "// Attributes\n"; - out << attributes; + out << attributes; out << "\n" "static float4 gl_Position = float4(0, 0, 0, 0);\n"; @@ -580,9 +661,14 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built out << "static int gl_InstanceID;"; } + if (mUsesVertexID) + { + out << "static int gl_VertexID;"; + } + out << "\n" "// Varyings\n"; - out << varyings; + out << varyings; out << "\n"; if (mUsesDepthRange) @@ -599,7 +685,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) { out << "cbuffer DriverConstants : register(b1)\n" - "{\n"; + "{\n"; if (mUsesDepthRange) { @@ -614,6 +700,18 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built out << " float2 dx_ViewCoords : packoffset(c2);\n"; out << " float2 dx_ViewScale : packoffset(c3);\n"; + if (mHasMultiviewExtensionEnabled) + { + // We have to add a value which we can use to keep track of which multi-view code + // path is to be selected in the GS. + out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + mUniformHLSL->samplerMetadataUniforms(out, "c4"); + } + out << "};\n" "\n"; } @@ -631,769 +729,126 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built if (mUsesDepthRange) { - out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, " + "dx_DepthRange.y, dx_DepthRange.z};\n" "\n"; } - if (!flaggedStructs.empty()) + if (!mappedStructs.empty()) { - out << "// Std140 Structures accessed by value\n"; + out << "// Structures from std140 blocks with padding removed\n"; out << "\n"; - out << flaggedStructs; + out << mappedStructs; out << "\n"; } } - - for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++) + else // Compute shader { - // Return type - if (textureFunction->method == TextureFunction::SIZE) - { - switch(textureFunction->sampler) - { - case EbtSampler2D: out << "int2 "; break; - case EbtSampler3D: out << "int3 "; break; - case EbtSamplerCube: out << "int2 "; break; - case EbtSampler2DArray: out << "int3 "; break; - case EbtISampler2D: out << "int2 "; break; - case EbtISampler3D: out << "int3 "; break; - case EbtISamplerCube: out << "int2 "; break; - case EbtISampler2DArray: out << "int3 "; break; - case EbtUSampler2D: out << "int2 "; break; - case EbtUSampler3D: out << "int3 "; break; - case EbtUSamplerCube: out << "int2 "; break; - case EbtUSampler2DArray: out << "int3 "; break; - case EbtSampler2DShadow: out << "int2 "; break; - case EbtSamplerCubeShadow: out << "int2 "; break; - case EbtSampler2DArrayShadow: out << "int3 "; break; - default: UNREACHABLE(); - } - } - else // Sampling function - { - switch(textureFunction->sampler) - { - case EbtSampler2D: out << "float4 "; break; - case EbtSampler3D: out << "float4 "; break; - case EbtSamplerCube: out << "float4 "; break; - case EbtSampler2DArray: out << "float4 "; break; - case EbtISampler2D: out << "int4 "; break; - case EbtISampler3D: out << "int4 "; break; - case EbtISamplerCube: out << "int4 "; break; - case EbtISampler2DArray: out << "int4 "; break; - case EbtUSampler2D: out << "uint4 "; break; - case EbtUSampler3D: out << "uint4 "; break; - case EbtUSamplerCube: out << "uint4 "; break; - case EbtUSampler2DArray: out << "uint4 "; break; - case EbtSampler2DShadow: out << "float "; break; - case EbtSamplerCubeShadow: out << "float "; break; - case EbtSampler2DArrayShadow: out << "float "; break; - default: UNREACHABLE(); - } - } - - // Function name - out << textureFunction->name(); - - // Argument list - int hlslCoords = 4; - - if (mOutputType == SH_HLSL_3_0_OUTPUT) - { - switch(textureFunction->sampler) - { - case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break; - case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break; - default: UNREACHABLE(); - } + ASSERT(mShaderType == GL_COMPUTE_SHADER); - switch(textureFunction->method) - { - case TextureFunction::IMPLICIT: break; - case TextureFunction::BIAS: hlslCoords = 4; break; - case TextureFunction::LOD: hlslCoords = 4; break; - case TextureFunction::LOD0: hlslCoords = 4; break; - case TextureFunction::LOD0BIAS: hlslCoords = 4; break; - default: UNREACHABLE(); - } - } - else + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + if (mUsesNumWorkGroups) { - hlslCoords = HLSLTextureCoordsCount(textureFunction->sampler); - if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) - { - out << TextureString(textureFunction->sampler) << " x, " - << SamplerString(textureFunction->sampler) << " s"; - } - else - { - ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT); - out << "const uint samplerIndex"; - } + out << " uint3 gl_NumWorkGroups : packoffset(c0);\n"; } + ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT); + mUniformHLSL->samplerMetadataUniforms(out, "c1"); + out << "};\n"; - if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates - { - switch(textureFunction->coords) - { - case 2: out << ", int2 t"; break; - case 3: out << ", int3 t"; break; - default: UNREACHABLE(); - } - } - else // Floating-point coordinates (except textureSize) + // Follow built-in variables would be initialized in + // DynamicHLSL::generateComputeShaderLinkHLSL, if they + // are used in compute shader. + if (mUsesWorkGroupID) { - switch(textureFunction->coords) - { - case 1: out << ", int lod"; break; // textureSize() - case 2: out << ", float2 t"; break; - case 3: out << ", float3 t"; break; - case 4: out << ", float4 t"; break; - default: UNREACHABLE(); - } + out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n"; } - if (textureFunction->method == TextureFunction::GRAD) + if (mUsesLocalInvocationID) { - switch(textureFunction->sampler) - { - case EbtSampler2D: - case EbtISampler2D: - case EbtUSampler2D: - case EbtSampler2DArray: - case EbtISampler2DArray: - case EbtUSampler2DArray: - case EbtSampler2DShadow: - case EbtSampler2DArrayShadow: - out << ", float2 ddx, float2 ddy"; - break; - case EbtSampler3D: - case EbtISampler3D: - case EbtUSampler3D: - case EbtSamplerCube: - case EbtISamplerCube: - case EbtUSamplerCube: - case EbtSamplerCubeShadow: - out << ", float3 ddx, float3 ddy"; - break; - default: UNREACHABLE(); - } + out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n"; } - switch(textureFunction->method) + if (mUsesGlobalInvocationID) { - case TextureFunction::IMPLICIT: break; - case TextureFunction::BIAS: break; // Comes after the offset parameter - case TextureFunction::LOD: out << ", float lod"; break; - case TextureFunction::LOD0: break; - case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter - case TextureFunction::SIZE: break; - case TextureFunction::FETCH: out << ", int mip"; break; - case TextureFunction::GRAD: break; - default: UNREACHABLE(); + out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n"; } - if (textureFunction->offset) + if (mUsesLocalInvocationIndex) { - switch(textureFunction->sampler) - { - case EbtSampler2D: out << ", int2 offset"; break; - case EbtSampler3D: out << ", int3 offset"; break; - case EbtSampler2DArray: out << ", int2 offset"; break; - case EbtISampler2D: out << ", int2 offset"; break; - case EbtISampler3D: out << ", int3 offset"; break; - case EbtISampler2DArray: out << ", int2 offset"; break; - case EbtUSampler2D: out << ", int2 offset"; break; - case EbtUSampler3D: out << ", int3 offset"; break; - case EbtUSampler2DArray: out << ", int2 offset"; break; - case EbtSampler2DShadow: out << ", int2 offset"; break; - case EbtSampler2DArrayShadow: out << ", int2 offset"; break; - default: UNREACHABLE(); - } + out << "static uint gl_LocalInvocationIndex = uint(0);\n"; } + } - if (textureFunction->method == TextureFunction::BIAS || - textureFunction->method == TextureFunction::LOD0BIAS) - { - out << ", float bias"; - } + bool getDimensionsIgnoresBaseLevel = + (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0; + mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel); + mImageFunctionHLSL->imageFunctionHeader(out); - out << ")\n" - "{\n"; + if (mUsesFragCoord) + { + out << "#define GL_USES_FRAG_COORD\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 (mUsesPointCoord) + { + out << "#define GL_USES_POINT_COORD\n"; + } - if (textureFunction->method == TextureFunction::SIZE) - { - if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler)) - { - if (IsSamplerArray(textureFunction->sampler)) - { - out << " uint width; uint height; uint layers; uint numberOfLevels;\n" - << " " << textureReference - << ".GetDimensions(lod, width, height, layers, numberOfLevels);\n"; - } - else - { - out << " uint width; uint height; uint numberOfLevels;\n" - << " " << textureReference - << ".GetDimensions(lod, width, height, numberOfLevels);\n"; - } - } - else if (IsSampler3D(textureFunction->sampler)) - { - out << " uint width; uint height; uint depth; uint numberOfLevels;\n" - << " " << textureReference - << ".GetDimensions(lod, width, height, depth, numberOfLevels);\n"; - } - else UNREACHABLE(); + if (mUsesFrontFacing) + { + out << "#define GL_USES_FRONT_FACING\n"; + } - switch(textureFunction->sampler) - { - case EbtSampler2D: out << " return int2(width, height);"; break; - case EbtSampler3D: out << " return int3(width, height, depth);"; break; - case EbtSamplerCube: out << " return int2(width, height);"; break; - case EbtSampler2DArray: out << " return int3(width, height, layers);"; break; - case EbtISampler2D: out << " return int2(width, height);"; break; - case EbtISampler3D: out << " return int3(width, height, depth);"; break; - case EbtISamplerCube: out << " return int2(width, height);"; break; - case EbtISampler2DArray: out << " return int3(width, height, layers);"; break; - case EbtUSampler2D: out << " return int2(width, height);"; break; - case EbtUSampler3D: out << " return int3(width, height, depth);"; break; - case EbtUSamplerCube: out << " return int2(width, height);"; break; - case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break; - case EbtSampler2DShadow: out << " return int2(width, height);"; break; - case EbtSamplerCubeShadow: out << " return int2(width, height);"; break; - case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break; - default: UNREACHABLE(); - } - } - else - { - if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) - { - out << " float width; float height; float layers; float levels;\n"; + if (mUsesPointSize) + { + out << "#define GL_USES_POINT_SIZE\n"; + } - out << " uint mip = 0;\n"; + if (mHasMultiviewExtensionEnabled) + { + out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n"; + } - out << " " << textureReference - << ".GetDimensions(mip, width, height, layers, levels);\n"; + if (mUsesViewID) + { + out << "#define GL_USES_VIEW_ID\n"; + } - out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n"; - out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n"; - out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n"; - out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n"; + if (mUsesFragDepth) + { + out << "#define GL_USES_FRAG_DEPTH\n"; + } - // FACE_POSITIVE_X = 000b - // FACE_NEGATIVE_X = 001b - // FACE_POSITIVE_Y = 010b - // FACE_NEGATIVE_Y = 011b - // FACE_POSITIVE_Z = 100b - // FACE_NEGATIVE_Z = 101b - out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n"; + if (mUsesDepthRange) + { + out << "#define GL_USES_DEPTH_RANGE\n"; + } - out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n"; - out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n"; - out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n"; + if (mUsesNumWorkGroups) + { + out << "#define GL_USES_NUM_WORK_GROUPS\n"; + } - out << " t.x = (u * 0.5f / m) + 0.5f;\n"; - out << " t.y = (v * 0.5f / m) + 0.5f;\n"; + if (mUsesWorkGroupID) + { + out << "#define GL_USES_WORK_GROUP_ID\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) - { - if (IsSampler2D(textureFunction->sampler)) - { - if (IsSamplerArray(textureFunction->sampler)) - { - out << " float width; float height; float layers; float levels;\n"; + if (mUsesLocalInvocationID) + { + out << "#define GL_USES_LOCAL_INVOCATION_ID\n"; + } - if (textureFunction->method == TextureFunction::LOD0) - { - out << " uint mip = 0;\n"; - } - else if (textureFunction->method == TextureFunction::LOD0BIAS) - { - out << " uint mip = bias;\n"; - } - else - { + if (mUsesGlobalInvocationID) + { + out << "#define GL_USES_GLOBAL_INVOCATION_ID\n"; + } - out << " " << textureReference - << ".GetDimensions(0, width, height, layers, levels);\n"; - if (textureFunction->method == TextureFunction::IMPLICIT || - textureFunction->method == TextureFunction::BIAS) - { - 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"; - - if (textureFunction->method == TextureFunction::BIAS) - { - out << " lod += bias;\n"; - } - } - else if (textureFunction->method == TextureFunction::GRAD) - { - out << " float lod = log2(max(length(ddx), length(ddy)));\n"; - } - - out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; - } - - out << " " << textureReference - << ".GetDimensions(mip, width, height, layers, levels);\n"; - } - else - { - out << " float width; float height; float levels;\n"; - - if (textureFunction->method == TextureFunction::LOD0) - { - out << " uint mip = 0;\n"; - } - else if (textureFunction->method == TextureFunction::LOD0BIAS) - { - out << " uint mip = bias;\n"; - } - else - { - out << " " << textureReference - << ".GetDimensions(0, width, height, levels);\n"; - - if (textureFunction->method == TextureFunction::IMPLICIT || - textureFunction->method == TextureFunction::BIAS) - { - 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"; - - if (textureFunction->method == TextureFunction::BIAS) - { - out << " lod += bias;\n"; - } - } - else if (textureFunction->method == TextureFunction::GRAD) - { - out << " float lod = log2(max(length(ddx), length(ddy)));\n"; - } - - out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; - } - - out << " " << textureReference - << ".GetDimensions(mip, width, height, levels);\n"; - } - } - else if (IsSampler3D(textureFunction->sampler)) - { - out << " float width; float height; float depth; float levels;\n"; - - if (textureFunction->method == TextureFunction::LOD0) - { - out << " uint mip = 0;\n"; - } - else if (textureFunction->method == TextureFunction::LOD0BIAS) - { - out << " uint mip = bias;\n"; - } - else - { - out << " " << textureReference - << ".GetDimensions(0, width, height, depth, levels);\n"; - - if (textureFunction->method == TextureFunction::IMPLICIT || - textureFunction->method == TextureFunction::BIAS) - { - 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"; - - if (textureFunction->method == TextureFunction::BIAS) - { - out << " lod += bias;\n"; - } - } - else if (textureFunction->method == TextureFunction::GRAD) - { - out << " float lod = log2(max(length(ddx), length(ddy)));\n"; - } - - out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; - } - - out << " " << textureReference - << ".GetDimensions(mip, width, height, depth, levels);\n"; - } - else UNREACHABLE(); - } - - out << " return "; - - // HLSL intrinsic - if (mOutputType == SH_HLSL_3_0_OUTPUT) - { - switch(textureFunction->sampler) - { - case EbtSampler2D: out << "tex2D"; break; - case EbtSamplerCube: out << "texCUBE"; break; - default: UNREACHABLE(); - } - - switch(textureFunction->method) - { - 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_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) - { - if (textureFunction->method == TextureFunction::GRAD) - { - if (IsIntegerSampler(textureFunction->sampler)) - { - out << "" << textureReference << ".Load("; - } - else if (IsShadowSampler(textureFunction->sampler)) - { - out << "" << textureReference << ".SampleCmpLevelZero(" << samplerReference - << ", "; - } - else - { - out << "" << textureReference << ".SampleGrad(" << samplerReference << ", "; - } - } - else if (IsIntegerSampler(textureFunction->sampler) || - textureFunction->method == TextureFunction::FETCH) - { - out << "" << textureReference << ".Load("; - } - else if (IsShadowSampler(textureFunction->sampler)) - { - switch(textureFunction->method) - { - 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(); - } - } - else - { - switch(textureFunction->method) - { - 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(); - } - } - } - else UNREACHABLE(); - - // Integer sampling requires integer addresses - TString addressx = ""; - TString addressy = ""; - TString addressz = ""; - TString close = ""; - - if (IsIntegerSampler(textureFunction->sampler) || - textureFunction->method == TextureFunction::FETCH) - { - switch(hlslCoords) - { - case 2: out << "int3("; break; - case 3: out << "int4("; break; - default: UNREACHABLE(); - } - - // Convert from normalized floating-point to integer - if (textureFunction->method != TextureFunction::FETCH) - { - addressx = "int(floor(width * frac(("; - addressy = "int(floor(height * frac(("; - - if (IsSamplerArray(textureFunction->sampler)) - { - addressz = "int(max(0, min(layers - 1, floor(0.5 + "; - } - else if (IsSamplerCube(textureFunction->sampler)) - { - addressz = "(((("; - } - else - { - addressz = "int(floor(depth * frac(("; - } - - close = "))))"; - } - } - else - { - switch(hlslCoords) - { - case 2: out << "float2("; break; - case 3: out << "float3("; break; - case 4: out << "float4("; break; - default: UNREACHABLE(); - } - } - - TString proj = ""; // Only used for projected textures - - if (textureFunction->proj) - { - switch(textureFunction->coords) - { - case 3: proj = " / t.z"; break; - case 4: proj = " / t.w"; break; - default: UNREACHABLE(); - } - } - - out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close; - - if (mOutputType == SH_HLSL_3_0_OUTPUT) - { - if (hlslCoords >= 3) - { - if (textureFunction->coords < 3) - { - out << ", 0"; - } - else - { - out << ", t.z" + proj; - } - } - - if (hlslCoords == 4) - { - switch(textureFunction->method) - { - case TextureFunction::BIAS: out << ", bias"; break; - case TextureFunction::LOD: out << ", lod"; break; - case TextureFunction::LOD0: out << ", 0"; break; - case TextureFunction::LOD0BIAS: out << ", bias"; break; - default: UNREACHABLE(); - } - } - - out << "));\n"; - } - else if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) - { - if (hlslCoords >= 3) - { - if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) - { - out << ", face"; - } - else - { - out << ", " + addressz + ("t.z" + proj) + close; - } - } - - if (textureFunction->method == TextureFunction::GRAD) - { - if (IsIntegerSampler(textureFunction->sampler)) - { - out << ", mip)"; - } - else if (IsShadowSampler(textureFunction->sampler)) - { - // Compare value - if (textureFunction->proj) - { - // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: - // The resulting third component of P' in the shadow forms is used as Dref - out << "), t.z" << proj; - } - else - { - switch(textureFunction->coords) - { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); - } - } - } - else - { - out << "), ddx, ddy"; - } - } - else if (IsIntegerSampler(textureFunction->sampler) || - textureFunction->method == TextureFunction::FETCH) - { - out << ", mip)"; - } - else if (IsShadowSampler(textureFunction->sampler)) - { - // Compare value - if (textureFunction->proj) - { - // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: - // The resulting third component of P' in the shadow forms is used as Dref - out << "), t.z" << proj; - } - else - { - switch(textureFunction->coords) - { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); - } - } - } - else - { - switch(textureFunction->method) - { - case TextureFunction::IMPLICIT: out << ")"; break; - case TextureFunction::BIAS: out << "), bias"; break; - case TextureFunction::LOD: out << "), lod"; break; - case TextureFunction::LOD0: out << "), 0"; break; - case TextureFunction::LOD0BIAS: out << "), bias"; break; - default: UNREACHABLE(); - } - } - - if (textureFunction->offset) - { - out << ", offset"; - } - - out << ");"; - } - else UNREACHABLE(); - } - - out << "\n" - "}\n" - "\n"; - } - - if (mUsesFragCoord) - { - out << "#define GL_USES_FRAG_COORD\n"; - } - - if (mUsesPointCoord) - { - out << "#define GL_USES_POINT_COORD\n"; - } - - if (mUsesFrontFacing) - { - out << "#define GL_USES_FRONT_FACING\n"; - } - - if (mUsesPointSize) - { - out << "#define GL_USES_POINT_SIZE\n"; - } - - if (mUsesFragDepth) - { - out << "#define GL_USES_FRAG_DEPTH\n"; - } - - if (mUsesDepthRange) - { - out << "#define GL_USES_DEPTH_RANGE\n"; - } + if (mUsesLocalInvocationIndex) + { + out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n"; + } if (mUsesXor) { @@ -1404,7 +859,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built "\n"; } - builtInFunctionEmulator->OutputEmulatedFunctions(out); + builtInFunctionEmulator->outputEmulatedFunctions(out); } void OutputHLSL::visitSymbol(TIntermSymbol *node) @@ -1412,10 +867,9 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) TInfoSinkBase &out = getInfoSink(); // Handle accessing std140 structs by value - if (mFlaggedStructMappedNames.count(node) > 0) + if (IsInStd140InterfaceBlock(node) && node->getBasicType() == EbtStruct) { - out << mFlaggedStructMappedNames[node]; - return; + out << "map"; } TString name = node->getSymbol(); @@ -1427,25 +881,25 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) } else { + const TType &nodeType = node->getType(); TQualifier qualifier = node->getQualifier(); + ensureStructDefined(nodeType); + if (qualifier == EvqUniform) { - const TType &nodeType = node->getType(); const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock(); if (interfaceBlock) { - mReferencedInterfaceBlocks[interfaceBlock->name()] = node; + mReferencedUniformBlocks[interfaceBlock->name()] = node; } else { mReferencedUniforms[name] = node; } - ensureStructDefined(nodeType); - - out << DecorateUniform(name, nodeType); + out << DecorateVariableIfNeeded(node->getName()); } else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) { @@ -1456,6 +910,10 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) { mReferencedVaryings[name] = node; out << Decorate(name); + if (name == "ViewID_OVR") + { + mUsesViewID = true; + } } else if (qualifier == EvqFragmentOut) { @@ -1497,14 +955,44 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) mUsesInstanceID = true; out << name; } + else if (qualifier == EvqVertexID) + { + mUsesVertexID = true; + out << name; + } else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth") { mUsesFragDepth = true; out << "gl_Depth"; } + else if (qualifier == EvqNumWorkGroups) + { + mUsesNumWorkGroups = true; + out << name; + } + else if (qualifier == EvqWorkGroupID) + { + mUsesWorkGroupID = true; + out << name; + } + else if (qualifier == EvqLocalInvocationID) + { + mUsesLocalInvocationID = true; + out << name; + } + else if (qualifier == EvqGlobalInvocationID) + { + mUsesGlobalInvocationID = true; + out << name; + } + else if (qualifier == EvqLocalInvocationIndex) + { + mUsesLocalInvocationIndex = true; + out << name; + } else { - out << DecorateIfNeeded(node->getName()); + out << DecorateVariableIfNeeded(node->getName()); } } } @@ -1553,315 +1041,372 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo } } -bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out) { - TInfoSinkBase &out = getInfoSink(); - - // Handle accessing std140 structs by value - if (mFlaggedStructMappedNames.count(node) > 0) + if (type.isArray()) { - out << mFlaggedStructMappedNames[node]; - return false; + const TString &functionName = addArrayAssignmentFunction(type); + outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")"); + } + else + { + outputTriplet(out, visit, "(", " = ", ")"); } +} - switch (node->getOp()) +bool OutputHLSL::ancestorEvaluatesToSamplerInStruct() +{ + for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n) { - case EOpAssign: - if (node->getLeft()->isArray()) + TIntermNode *ancestor = getAncestorNode(n); + const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode(); + if (ancestorBinary == nullptr) + { + return false; + } + switch (ancestorBinary->getOp()) { - TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); - if (rightAgg != nullptr && rightAgg->isConstructor()) + case EOpIndexDirectStruct: { - const TString &functionName = addArrayConstructIntoFunction(node->getType()); - out << functionName << "("; - node->getLeft()->traverse(this); - TIntermSequence *seq = rightAgg->getSequence(); - for (auto &arrayElement : *seq) + const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = + ancestorBinary->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + if (IsSampler(field->type()->getBasicType())) { - out << ", "; - arrayElement->traverse(this); + return true; } - 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(out, visit, (functionName + "(").c_str(), ", ", ")"); - } - else - { - outputTriplet(out, visit, "(", " = ", ")"); - } - break; - case EOpInitialize: - if (visit == PreVisit) - { - // GLSL allows to write things like "float x = x;" where a new variable x is defined - // and the value of an existing variable x is assigned. HLSL uses C semantics (the - // new variable is created before the assignment is evaluated), so we need to convert - // this to "float t = x, x = t;". - - TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); - ASSERT(symbolNode); - TIntermTyped *expression = node->getRight(); - - // TODO (jmadill): do a 'deep' scan to know if an expression is statically const - if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst) - { - // For variables which are not constant, defer their real initialization until - // 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)); - } - else if (writeSameSymbolInitializer(out, symbolNode, expression)) - { - // Skip initializing the rest of the expression - return false; + break; } - else if (writeConstantInitialization(out, symbolNode, expression)) - { + case EOpIndexDirect: + break; + default: + // Returning a sampler from indirect indexing is not supported. return false; - } - } - else if (visit == InVisit) - { - out << " = "; - } - 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) - { - out << "("; - } - else if (visit == InVisit) - { - out << " = mul("; - node->getLeft()->traverse(this); - out << ", transpose("; - } - else - { - out << ")))"; - } - break; - case EOpMatrixTimesMatrixAssign: - if (visit == PreVisit) - { - out << "("; - } - else if (visit == InVisit) - { - out << " = transpose(mul(transpose("; - node->getLeft()->traverse(this); - out << "), transpose("; } - else + } + return false; +} + +bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = getInfoSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + +bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = getInfoSink(); + + switch (node->getOp()) + { + case EOpComma: + outputTriplet(out, visit, "(", ", ", ")"); + break; + case EOpAssign: + if (node->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); + } + outputAssign(visit, node->getType(), out); + break; + case EOpInitialize: + if (visit == PreVisit) + { + TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); + TIntermTyped *expression = node->getRight(); + + // Global initializers must be constant at this point. + ASSERT(symbolNode->getQualifier() != EvqGlobal || + canWriteAsHLSLLiteral(expression)); + + // GLSL allows to write things like "float x = x;" where a new variable x is defined + // and the value of an existing variable x is assigned. HLSL uses C semantics (the + // new variable is created before the assignment is evaluated), so we need to + // convert + // this to "float t = x, x = t;". + if (writeSameSymbolInitializer(out, symbolNode, expression)) + { + // 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(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) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", transpose("; + } + else + { + out << ")))"; + } + break; + case EOpMatrixTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = transpose(mul(transpose("; + node->getLeft()->traverse(this); + out << "), transpose("; + } + else + { + out << "))))"; + } + 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: { - out << "))))"; - } - 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(); + const TType &leftType = node->getLeft()->getType(); if (leftType.isInterfaceBlock()) { if (visit == PreVisit) { - TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock(); + TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock(); const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); - mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode(); - out << mUniformHLSL->interfaceBlockInstanceString(*interfaceBlock, arrayIndex); + mReferencedUniformBlocks[interfaceBlock->instanceName()] = + node->getLeft()->getAsSymbolNode(); + out << mUniformHLSL->uniformBlockInstanceString(*interfaceBlock, arrayIndex); return false; } } + else if (ancestorEvaluatesToSamplerInStruct()) + { + // All parts of an expression that access a sampler in a struct need to use _ as + // separator to access the sampler variable that has been moved out of the struct. + outputTriplet(out, visit, "", "_", ""); + } else { outputTriplet(out, visit, "", "[", "]"); } } break; - case EOpIndexIndirect: - // We do not currently support indirect references to interface blocks - ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); - outputTriplet(out, visit, "", "[", "]"); - break; - case EOpIndexDirectStruct: - if (visit == InVisit) + case EOpIndexIndirect: + // We do not currently support indirect references to interface blocks + ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); + outputTriplet(out, visit, "", "[", "]"); + break; + case EOpIndexDirectStruct: { - const TStructure* structure = node->getLeft()->getType().getStruct(); - const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); - const TField* field = structure->fields()[index->getIConst(0)]; - out << "." + DecorateField(field->name(), *structure); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; - return false; - } - break; - case EOpIndexDirectInterfaceBlock: - if (visit == InVisit) - { - const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); - const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); - const TField* field = interfaceBlock->fields()[index->getIConst(0)]; - out << "." + Decorate(field->name()); + // In cases where indexing returns a sampler, we need to access the sampler variable + // that has been moved out of the struct. + bool indexingReturnsSampler = IsSampler(field->type()->getBasicType()); + if (visit == PreVisit && indexingReturnsSampler) + { + // Samplers extracted from structs have "angle" prefix to avoid name conflicts. + // This prefix is only output at the beginning of the indexing expression, which + // may have multiple parts. + out << "angle"; + } + if (!indexingReturnsSampler) + { + // All parts of an expression that access a sampler in a struct need to use _ as + // separator to access the sampler variable that has been moved out of the struct. + indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct(); + } + if (visit == InVisit) + { + if (indexingReturnsSampler) + { + out << "_" + field->name(); + } + else + { + out << "." + DecorateField(field->name(), *structure); + } - return false; + return false; + } } break; - case EOpVectorSwizzle: - if (visit == InVisit) + case EOpIndexDirectInterfaceBlock: { - out << "."; - - TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); - - if (swizzle) + bool structInStd140Block = + node->getBasicType() == EbtStruct && IsInStd140InterfaceBlock(node->getLeft()); + if (visit == PreVisit && structInStd140Block) { - TIntermSequence *sequence = swizzle->getSequence(); - - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) + out << "map"; + } + if (visit == InVisit) + { + const TInterfaceBlock *interfaceBlock = + node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = interfaceBlock->fields()[index->getIConst(0)]; + if (structInStd140Block) { - TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); - - if (element) - { - int i = element->getIConst(0); - - switch (i) - { - case 0: out << "x"; break; - case 1: out << "y"; break; - case 2: out << "z"; break; - case 3: out << "w"; break; - default: UNREACHABLE(); - } - } - else UNREACHABLE(); + out << "_"; } - } - else UNREACHABLE(); + else + { + out << "."; + } + out << Decorate(field->name()); - return false; // Fully processed + return false; + } + break; } - 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(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: - // 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(out, visit, "xor(", ", ", ")"); - break; - case EOpLogicalAnd: - // 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(); + 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(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: + // 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(out, visit, "xor(", ", ", ")"); + break; + case EOpLogicalAnd: + // 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(); } return true; @@ -1879,9 +1424,6 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: outputTriplet(out, visit, "(+", "", ")"); break; - case EOpVectorLogicalNot: - outputTriplet(out, visit, "(!", "", ")"); - break; case EOpLogicalNot: outputTriplet(out, visit, "(!", "", ")"); break; @@ -1933,534 +1475,485 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpTanh: outputTriplet(out, visit, "tanh(", "", ")"); break; - case EOpAsinh: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "asinh("); - break; - case EOpAcosh: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "acosh("); - break; - case EOpAtanh: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "atanh("); - 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(out, visit, "roundEven("); - break; - case EOpCeil: - outputTriplet(out, visit, "ceil(", "", ")"); - break; - case EOpFract: - outputTriplet(out, visit, "frac(", "", ")"); - break; - case EOpIsNan: - outputTriplet(out, visit, "isnan(", "", ")"); - mRequiresIEEEStrictCompiling = true; - 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(out, visit, "packSnorm2x16("); - break; - case EOpPackUnorm2x16: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "packUnorm2x16("); - break; - case EOpPackHalf2x16: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "packHalf2x16("); - break; - case EOpUnpackSnorm2x16: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "unpackSnorm2x16("); - break; - case EOpUnpackUnorm2x16: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "unpackUnorm2x16("); - break; - case EOpUnpackHalf2x16: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "unpackHalf2x16("); - break; - case EOpLength: - outputTriplet(out, visit, "length(", "", ")"); - break; - case EOpNormalize: - outputTriplet(out, visit, "normalize(", "", ")"); - break; - case EOpDFdx: - if(mInsideDiscontinuousLoop || mOutputLod0Function) - { - outputTriplet(out, visit, "(", "", ", 0.0)"); - } - else - { - outputTriplet(out, visit, "ddx(", "", ")"); - } - break; - case EOpDFdy: - if(mInsideDiscontinuousLoop || mOutputLod0Function) - { - outputTriplet(out, visit, "(", "", ", 0.0)"); - } - else + case EOpAsinh: + case EOpAcosh: + case EOpAtanh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + 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(out, visit, node->getOp()); + break; + case EOpCeil: + outputTriplet(out, visit, "ceil(", "", ")"); + break; + case EOpFract: + outputTriplet(out, visit, "frac(", "", ")"); + break; + case EOpIsNan: + if (node->getUseEmulatedFunction()) + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + else + outputTriplet(out, visit, "isnan(", "", ")"); + mRequiresIEEEStrictCompiling = true; + 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: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + case EOpUnpackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpLength: + outputTriplet(out, visit, "length(", "", ")"); + break; + case EOpNormalize: + outputTriplet(out, visit, "normalize(", "", ")"); + break; + case EOpDFdx: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "ddx(", "", ")"); + } + break; + case EOpDFdy: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "ddy(", "", ")"); + } + break; + case EOpFwidth: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "fwidth(", "", ")"); + } + break; + case EOpTranspose: + outputTriplet(out, visit, "transpose(", "", ")"); + break; + case EOpDeterminant: + outputTriplet(out, visit, "determinant(transpose(", "", "))"); + break; + case EOpInverse: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + + case EOpAny: + outputTriplet(out, visit, "any(", "", ")"); + break; + case EOpAll: + outputTriplet(out, visit, "all(", "", ")"); + break; + case EOpLogicalNotComponentWise: + outputTriplet(out, visit, "(!", "", ")"); + break; + case EOpBitfieldReverse: + outputTriplet(out, visit, "reversebits(", "", ")"); + break; + case EOpBitCount: + outputTriplet(out, visit, "countbits(", "", ")"); + break; + case EOpFindLSB: + // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested + // in GLSLTest and results are consistent with GL. + outputTriplet(out, visit, "firstbitlow(", "", ")"); + break; + case EOpFindMSB: + // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is + // tested in GLSLTest and results are consistent with GL. + outputTriplet(out, visit, "firstbithigh(", "", ")"); + break; + default: + UNREACHABLE(); + } + + return true; +} + +TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node) +{ + if (node->getAsSymbolNode()) + { + return node->getAsSymbolNode()->getSymbol(); + } + TIntermBinary *nodeBinary = node->getAsBinaryNode(); + switch (nodeBinary->getOp()) + { + case EOpIndexDirect: { - outputTriplet(out, visit, "ddy(", "", ")"); + int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0); + + TInfoSinkBase prefixSink; + prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index; + return TString(prefixSink.c_str()); } - break; - case EOpFwidth: - if(mInsideDiscontinuousLoop || mOutputLod0Function) + case EOpIndexDirectStruct: { - outputTriplet(out, visit, "(", "", ", 0.0)"); + const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct(); + int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0); + const TField *field = s->fields()[index]; + + TInfoSinkBase prefixSink; + prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" + << field->name(); + return TString(prefixSink.c_str()); } - else + default: + UNREACHABLE(); + return TString(""); + } +} + +bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node) +{ + TInfoSinkBase &out = getInfoSink(); + + if (mInsideFunction) + { + outputLineDirective(out, node->getLine().first_line); + out << "{\n"; + } + + for (TIntermNode *statement : *node->getSequence()) + { + outputLineDirective(out, statement->getLine().first_line); + + statement->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. + // Also the output code is clearer if we don't output ; after statements where it is not + // needed: + // * if statements + // * switch statements + // * blocks + // * function definitions + // * loops (do-while loops output the semicolon in VisitLoop) + // * declarations that don't generate output. + if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr && + statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr && + statement->getAsSwitchNode() == nullptr && + statement->getAsFunctionDefinition() == nullptr && + (statement->getAsDeclarationNode() == nullptr || + IsDeclarationWrittenOut(statement->getAsDeclarationNode())) && + statement->getAsInvariantDeclarationNode() == nullptr) { - outputTriplet(out, visit, "fwidth(", "", ")"); + out << ";\n"; } - break; - case EOpTranspose: - outputTriplet(out, visit, "transpose(", "", ")"); - break; - case EOpDeterminant: - outputTriplet(out, visit, "determinant(transpose(", "", "))"); - break; - case EOpInverse: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "inverse("); - break; + } - case EOpAny: - outputTriplet(out, visit, "any(", "", ")"); - break; - case EOpAll: - outputTriplet(out, visit, "all(", "", ")"); - break; - default: UNREACHABLE(); + if (mInsideFunction) + { + outputLineDirective(out, node->getLine().last_line); + out << "}\n"; } - return true; + return false; } -bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) { TInfoSinkBase &out = getInfoSink(); - switch (node->getOp()) + ASSERT(mCurrentFunctionMetadata == nullptr); + + size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo()); + ASSERT(index != CallDAG::InvalidIndex); + mCurrentFunctionMetadata = &mASTMetadataList[index]; + + out << TypeString(node->getFunctionPrototype()->getType()) << " "; + + TIntermSequence *parameters = node->getFunctionPrototype()->getSequence(); + + if (node->getFunctionSymbolInfo()->isMain()) { - case EOpSequence: - { - if (mInsideFunction) - { - outputLineDirective(out, node->getLine().first_line); - out << "{\n"; - } + out << "gl_main("; + } + else + { + out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) + << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "("); + } - for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++) - { - outputLineDirective(out, (*sit)->getLine().first_line); + for (unsigned int i = 0; i < parameters->size(); i++) + { + TIntermSymbol *symbol = (*parameters)[i]->getAsSymbolNode(); - (*sit)->traverse(this); + if (symbol) + { + ensureStructDefined(symbol->getType()); - // 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. - // 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"; - } + out << argumentString(symbol); - if (mInsideFunction) + if (i < parameters->size() - 1) { - outputLineDirective(out, node->getLine().last_line); - out << "}\n"; + out << ", "; } - - return false; } - case EOpDeclaration: - if (visit == PreVisit) - { - TIntermSequence *sequence = node->getSequence(); - TIntermTyped *variable = (*sequence)[0]->getAsTyped(); - ASSERT(sequence->size() == 1); + else + UNREACHABLE(); + } - if (variable && - (variable->getQualifier() == EvqTemporary || - variable->getQualifier() == EvqGlobal || variable->getQualifier() == EvqConst)) - { - ensureStructDefined(variable->getType()); + out << ")\n"; - if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration - { - if (!mInsideFunction) - { - out << "static "; - } + mInsideFunction = true; + // The function body node will output braces. + node->getBody()->traverse(this); + mInsideFunction = false; - out << TypeString(variable->getType()) + " "; + mCurrentFunctionMetadata = nullptr; - TIntermSymbol *symbol = variable->getAsSymbolNode(); + bool needsLod0 = mASTMetadataList[index].mNeedsLod0; + if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) + { + ASSERT(!node->getFunctionSymbolInfo()->isMain()); + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } - 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 - { - // Already added to constructor map - } - else UNREACHABLE(); - } - else if (variable && IsVaryingOut(variable->getQualifier())) - { - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) - { - TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + return false; +} - if (symbol) - { - // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking - mReferencedVaryings[symbol->getSymbol()] = symbol; - } - else - { - (*sit)->traverse(this); - } - } - } +bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (visit == PreVisit) + { + TIntermSequence *sequence = node->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); + ASSERT(sequence->size() == 1); + ASSERT(variable); - return false; - } - else if (visit == InVisit) - { - out << ", "; - } - break; - case EOpInvariantDeclaration: - // Do not do any translation - return false; - case EOpPrototype: - if (visit == PreVisit) + if (IsDeclarationWrittenOut(node)) { - size_t index = mCallDag.findIndex(node); - // Skip the prototype if it is not implemented (and thus not used) - if (index == CallDAG::InvalidIndex) - { - return false; - } + TInfoSinkBase &out = getInfoSink(); + ensureStructDefined(variable->getType()); - TString name = DecorateFunctionIfNeeded(node->getNameObj()); - out << TypeString(node->getType()) << " " << name - << (mOutputLod0Function ? "Lod0(" : "("); + if (!variable->getAsSymbolNode() || + variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration + { + if (!mInsideFunction) + { + out << "static "; + } - TIntermSequence *arguments = node->getSequence(); + out << TypeString(variable->getType()) + " "; - for (unsigned int i = 0; i < arguments->size(); i++) - { - TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); + TIntermSymbol *symbol = variable->getAsSymbolNode(); if (symbol) { - out << argumentString(symbol); - - if (i < arguments->size() - 1) - { - out << ", "; - } + symbol->traverse(this); + out << ArrayString(symbol->getType()); + out << " = " + initializer(symbol->getType()); + } + else + { + variable->traverse(this); } - else UNREACHABLE(); } - - out << ");\n"; - - // Also prototype the Lod0 variant if needed - bool needsLod0 = mASTMetadataList[index].mNeedsLod0; - if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) + else if (variable->getAsSymbolNode() && + variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration { - mOutputLod0Function = true; - node->traverse(this); - mOutputLod0Function = false; + ASSERT(variable->getBasicType() == EbtStruct); + // ensureStructDefined has already been called. } - - return false; + else + UNREACHABLE(); } - break; - case EOpComma: - outputTriplet(out, visit, "(", ", ", ")"); - break; - case EOpFunction: + else if (IsVaryingOut(variable->getQualifier())) { - ASSERT(mCurrentFunctionMetadata == nullptr); - TString name = TFunction::unmangleName(node->getNameObj().getString()); - - size_t index = mCallDag.findIndex(node); - ASSERT(index != CallDAG::InvalidIndex); - mCurrentFunctionMetadata = &mASTMetadataList[index]; + TIntermSymbol *symbol = variable->getAsSymbolNode(); + ASSERT(symbol); // Varying declarations can't have initializers. - out << TypeString(node->getType()) << " "; - - if (name == "main") - { - out << "gl_main("; - } - else - { - out << DecorateFunctionIfNeeded(node->getNameObj()) - << (mOutputLod0Function ? "Lod0(" : "("); - } - - TIntermSequence *sequence = node->getSequence(); - TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence(); - - for (unsigned int i = 0; i < arguments->size(); i++) - { - TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); + // Vertex outputs which are declared but not written to should still be declared to + // allow successful linking. + mReferencedVaryings[symbol->getSymbol()] = symbol; + } + } + return false; +} - if (symbol) - { - ensureStructDefined(symbol->getType()); +bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + // Do not do any translation + return false; +} - out << argumentString(symbol); +bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) +{ + TInfoSinkBase &out = getInfoSink(); - if (i < arguments->size() - 1) - { - out << ", "; - } - } - else UNREACHABLE(); - } + ASSERT(visit == PreVisit); + size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo()); + // Skip the prototype if it is not implemented (and thus not used) + if (index == CallDAG::InvalidIndex) + { + return false; + } - out << ")\n"; + TIntermSequence *arguments = node->getSequence(); - if (sequence->size() > 1) - { - mInsideFunction = true; - TIntermNode *body = (*sequence)[1]; - // The function body node will output braces. - ASSERT(IsSequence(body)); - body->traverse(this); - mInsideFunction = false; - } - else - { - out << "{}\n"; - } + TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()); + out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments) + << (mOutputLod0Function ? "Lod0(" : "("); - mCurrentFunctionMetadata = nullptr; + for (unsigned int i = 0; i < arguments->size(); i++) + { + TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); + ASSERT(symbol != nullptr); - bool needsLod0 = mASTMetadataList[index].mNeedsLod0; - if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) - { - ASSERT(name != "main"); - mOutputLod0Function = true; - node->traverse(this); - mOutputLod0Function = false; - } + out << argumentString(symbol); - return false; - } - break; - case EOpFunctionCall: + if (i < arguments->size() - 1) { - TIntermSequence *arguments = node->getSequence(); - - bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; - if (node->isUserDefined()) - { - 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(); + out << ", "; + } + } - TextureFunction textureFunction; - textureFunction.sampler = samplerType; - textureFunction.coords = (*arguments)[1]->getAsTyped()->getNominalSize(); - textureFunction.method = TextureFunction::IMPLICIT; - textureFunction.proj = false; - textureFunction.offset = false; + out << ");\n"; - if (name == "texture2D" || name == "textureCube" || name == "texture") - { - textureFunction.method = TextureFunction::IMPLICIT; - } - else if (name == "texture2DProj" || name == "textureProj") - { - textureFunction.method = TextureFunction::IMPLICIT; - textureFunction.proj = true; - } - else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" || - name == "texture2DLodEXT" || name == "textureCubeLodEXT") - { - textureFunction.method = TextureFunction::LOD; - } - else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT") - { - textureFunction.method = TextureFunction::LOD; - textureFunction.proj = true; - } - else if (name == "textureSize") - { - textureFunction.method = TextureFunction::SIZE; - } - else if (name == "textureOffset") - { - textureFunction.method = TextureFunction::IMPLICIT; - textureFunction.offset = true; - } - else if (name == "textureProjOffset") - { - textureFunction.method = TextureFunction::IMPLICIT; - textureFunction.offset = true; - textureFunction.proj = true; - } - else if (name == "textureLodOffset") - { - textureFunction.method = TextureFunction::LOD; - textureFunction.offset = true; - } - else if (name == "textureProjLodOffset") - { - textureFunction.method = TextureFunction::LOD; - textureFunction.proj = true; - textureFunction.offset = true; - } - else if (name == "texelFetch") - { - textureFunction.method = TextureFunction::FETCH; - } - else if (name == "texelFetchOffset") - { - textureFunction.method = TextureFunction::FETCH; - textureFunction.offset = true; - } - else if (name == "textureGrad" || name == "texture2DGradEXT") - { - textureFunction.method = TextureFunction::GRAD; - } - else if (name == "textureGradOffset") - { - textureFunction.method = TextureFunction::GRAD; - textureFunction.offset = true; - } - else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT") - { - textureFunction.method = TextureFunction::GRAD; - textureFunction.proj = true; - } - else if (name == "textureProjGradOffset") - { - textureFunction.method = TextureFunction::GRAD; - textureFunction.proj = true; - textureFunction.offset = true; - } - else UNREACHABLE(); + // Also prototype the Lod0 variant if needed + bool needsLod0 = mASTMetadataList[index].mNeedsLod0; + if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } - if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument - { - unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments + return false; +} - if (textureFunction.offset) - { - mandatoryArgumentCount++; - } +bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + TInfoSinkBase &out = getInfoSink(); - bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional + switch (node->getOp()) + { + case EOpCallBuiltInFunction: + case EOpCallFunctionInAST: + case EOpCallInternalRawFunction: + { + TIntermSequence *arguments = node->getSequence(); - if (lod0 || mShaderType == GL_VERTEX_SHADER) - { - if (bias) - { - textureFunction.method = TextureFunction::LOD0BIAS; - } - else - { - textureFunction.method = TextureFunction::LOD0; - } - } - else if (bias) - { - textureFunction.method = TextureFunction::BIAS; - } + bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; + if (node->getOp() == EOpCallFunctionInAST) + { + if (node->isArray()) + { + UNIMPLEMENTED(); } + size_t index = mCallDag.findIndex(node->getFunctionSymbolInfo()); + ASSERT(index != CallDAG::InvalidIndex); + lod0 &= mASTMetadataList[index].mNeedsLod0; - mUsesTexture.insert(textureFunction); - - out << textureFunction.name(); + out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()); + out << DisambiguateFunctionName(node->getSequence()); + out << (lod0 ? "Lod0(" : "("); + } + else if (node->getOp() == EOpCallInternalRawFunction) + { + // This path is used for internal functions that don't have their definitions in the + // AST, such as precision emulation functions. + out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "("; + } + else if (node->getFunctionSymbolInfo()->isImageFunction()) + { + TString name = node->getFunctionSymbolInfo()->getName(); + TType type = (*arguments)[0]->getAsTyped()->getType(); + TString imageFunctionName = mImageFunctionHLSL->useImageFunction( + name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat, + type.getMemoryQualifier().readonly); + out << imageFunctionName << "("; + } + else + { + const TString &name = node->getFunctionSymbolInfo()->getName(); + TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType(); + int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument. + if (arguments->size() > 1) + { + coords = (*arguments)[1]->getAsTyped()->getNominalSize(); + } + TString textureFunctionName = mTextureFunctionHLSL->useTextureFunction( + name, samplerType, coords, arguments->size(), lod0, mShaderType); + out << textureFunctionName << "("; } for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++) { - if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && - IsSampler((*arg)->getAsTyped()->getBasicType())) + TIntermTyped *typedArg = (*arg)->getAsTyped(); + if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType())) { out << "texture_"; (*arg)->traverse(this); @@ -2469,6 +1962,29 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) (*arg)->traverse(this); + if (typedArg->getType().isStructureContainingSamplers()) + { + const TType &argType = typedArg->getType(); + TVector samplerSymbols; + TString structName = samplerNamePrefixFromStruct(typedArg); + argType.createSamplerSymbols("angle_" + structName, "", &samplerSymbols, + nullptr, mSymbolTable); + for (const TIntermSymbol *sampler : samplerSymbols) + { + if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << ", texture_" << sampler->getSymbol(); + out << ", sampler_" << sampler->getSymbol(); + } + else + { + // In case of HLSL 4.1+, this symbol is the sampler index, and in case + // of D3D9, it's the sampler variable. + out << ", " + sampler->getSymbol(); + } + } + } + if (arg < arguments->end() - 1) { out << ", "; @@ -2479,160 +1995,79 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) return false; } - 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()); + case EOpConstruct: + outputConstructor(out, visit, node); break; - case EOpConstructMat2x3: - outputConstructor(out, visit, node->getType(), "mat2x3", node->getSequence()); - break; - case EOpConstructMat2x4: - outputConstructor(out, visit, node->getType(), "mat2x4", node->getSequence()); + case EOpEqualComponentWise: + outputTriplet(out, visit, "(", " == ", ")"); break; - case EOpConstructMat3x2: - outputConstructor(out, visit, node->getType(), "mat3x2", node->getSequence()); + case EOpNotEqualComponentWise: + outputTriplet(out, visit, "(", " != ", ")"); break; - case EOpConstructMat3: - outputConstructor(out, visit, node->getType(), "mat3", node->getSequence()); + case EOpLessThanComponentWise: + outputTriplet(out, visit, "(", " < ", ")"); break; - case EOpConstructMat3x4: - outputConstructor(out, visit, node->getType(), "mat3x4", node->getSequence()); + case EOpGreaterThanComponentWise: + outputTriplet(out, visit, "(", " > ", ")"); break; - case EOpConstructMat4x2: - outputConstructor(out, visit, node->getType(), "mat4x2", node->getSequence()); + case EOpLessThanEqualComponentWise: + outputTriplet(out, visit, "(", " <= ", ")"); break; - case EOpConstructMat4x3: - outputConstructor(out, visit, node->getType(), "mat4x3", node->getSequence()); + case EOpGreaterThanEqualComponentWise: + outputTriplet(out, visit, "(", " >= ", ")"); break; - case EOpConstructMat4: - outputConstructor(out, visit, node->getType(), "mat4", node->getSequence()); + case EOpMod: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); break; - case EOpConstructStruct: - { - if (node->getType().isArray()) - { - UNIMPLEMENTED(); - } - const TString &structName = StructNameString(*node->getType().getStruct()); - mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence()); - outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")"); - } - break; - case EOpLessThan: - outputTriplet(out, visit, "(", " < ", ")"); + case EOpModf: + outputTriplet(out, visit, "modf(", ", ", ")"); break; - case EOpGreaterThan: - outputTriplet(out, visit, "(", " > ", ")"); + case EOpPow: + outputTriplet(out, visit, "pow(", ", ", ")"); break; - case EOpLessThanEqual: - outputTriplet(out, visit, "(", " <= ", ")"); + case EOpAtan: + ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); break; - case EOpGreaterThanEqual: - outputTriplet(out, visit, "(", " >= ", ")"); + case EOpMin: + outputTriplet(out, visit, "min(", ", ", ")"); break; - case EOpVectorEqual: - outputTriplet(out, visit, "(", " == ", ")"); + case EOpMax: + outputTriplet(out, visit, "max(", ", ", ")"); break; - case EOpVectorNotEqual: - outputTriplet(out, visit, "(", " != ", ")"); + case EOpClamp: + outputTriplet(out, visit, "clamp(", ", ", ")"); break; - case EOpMod: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "mod("); - 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(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: + 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)", + // 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("); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); } else { outputTriplet(out, visit, "lerp(", ", ", ")"); } + break; } - break; case EOpStep: outputTriplet(out, visit, "step(", ", ", ")"); break; case EOpSmoothStep: outputTriplet(out, visit, "smoothstep(", ", ", ")"); break; + case EOpFrexp: + case EOpLdexp: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; case EOpDistance: outputTriplet(out, visit, "distance(", ", ", ")"); break; @@ -2642,30 +2077,40 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpCross: outputTriplet(out, visit, "cross(", ", ", ")"); break; - case EOpFaceForward: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "faceforward("); - break; - case EOpReflect: - outputTriplet(out, visit, "reflect(", ", ", ")"); - break; - case EOpRefract: - outputTriplet(out, visit, "refract(", ", ", ")"); - break; - case EOpOuterProduct: - ASSERT(node->getUseEmulatedFunction()); - writeEmulatedFunctionTriplet(out, visit, "outerProduct("); - break; - case EOpMul: - outputTriplet(out, visit, "(", " * ", ")"); - break; - default: UNREACHABLE(); + case EOpFaceforward: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpReflect: + outputTriplet(out, visit, "reflect(", ", ", ")"); + break; + case EOpRefract: + outputTriplet(out, visit, "refract(", ", ", ")"); + break; + case EOpOuterProduct: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpMulMatrixComponentWise: + outputTriplet(out, visit, "(", " * ", ")"); + break; + case EOpBitfieldExtract: + case EOpBitfieldInsert: + case EOpUaddCarry: + case EOpUsubBorrow: + case EOpUmulExtended: + case EOpImulExtended: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + default: + UNREACHABLE(); } return true; } -void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) +void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node) { out << "if ("; @@ -2680,8 +2125,6 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) if (node->getTrueBlock()) { // The trueBlock child node will output braces. - ASSERT(IsSequence(node->getTrueBlock())); - node->getTrueBlock()->traverse(this); // Detect true discard @@ -2702,9 +2145,7 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) outputLineDirective(out, node->getFalseBlock()->getLine().first_line); - // Either this is "else if" or the falseBlock child node will output braces. - ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr); - + // The falseBlock child node will output braces. node->getFalseBlock()->traverse(this); outputLineDirective(out, node->getFalseBlock()->getLine().first_line); @@ -2720,18 +2161,19 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) } } -bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) +bool OutputHLSL::visitTernary(Visit, TIntermTernary *) { - TInfoSinkBase &out = getInfoSink(); + // Ternary ops should have been already converted to something else in the AST. HLSL ternary + // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator. + UNREACHABLE(); + return false; +} - ASSERT(!node->usesTernaryOperator()); +bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = getInfoSink(); - if (!mInsideFunction) - { - // This is part of unfolded global initialization. - mDeferredGlobalInitializers.push_back(node); - return false; - } + ASSERT(mInsideFunction); // D3D errors when there is a gradient operation in a loop in an unflattened if. if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node)) @@ -2739,7 +2181,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) out << "FLATTEN "; } - writeSelection(out, node); + writeIfElse(out, node); return false; } @@ -2748,17 +2190,13 @@ bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node) { TInfoSinkBase &out = getInfoSink(); - if (node->getStatementList()) - { - node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList())); - outputTriplet(out, visit, "switch (", ") ", ""); - // The curly braces get written when visiting the statementList aggregate - } - else + ASSERT(node->getStatementList()); + if (visit == PreVisit) { - // No statementList, so it won't output curly braces - outputTriplet(out, visit, "switch (", ") {", "}\n"); + node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics)); } + outputTriplet(out, visit, "switch (", ") ", ""); + // The curly braces get written when visiting the statementList block. return true; } @@ -2789,8 +2227,8 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) mNestedLoopDepth++; bool wasDiscontinuous = mInsideDiscontinuousLoop; - mInsideDiscontinuousLoop = mInsideDiscontinuousLoop || - mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0; + mInsideDiscontinuousLoop = + mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0; TInfoSinkBase &out = getInfoSink(); @@ -2843,7 +2281,6 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) if (node->getBody()) { // The loop body node will output braces. - ASSERT(IsSequence(node->getBody())); node->getBody()->traverse(this); } else @@ -2858,11 +2295,11 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) if (node->getType() == ELoopDoWhile) { outputLineDirective(out, node->getCondition()->getLine().first_line); - out << "while(\n"; + out << "while ("; node->getCondition()->traverse(this); - out << ");"; + out << ");\n"; } out << "}\n"; @@ -2875,89 +2312,47 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) { - TInfoSinkBase &out = getInfoSink(); - - switch (node->getFlowOp()) + if (visit == PreVisit) { - case EOpKill: - outputTriplet(out, visit, "discard;\n", "", ""); - break; - case EOpBreak: - if (visit == PreVisit) - { - if (mNestedLoopDepth > 1) - { - mUsesNestedBreak = true; - } - - if (mExcessiveLoopIndex) - { - out << "{Break"; - mExcessiveLoopIndex->traverse(this); - out << " = true; break;}\n"; - } - else - { - out << "break;\n"; - } - } - break; - case EOpContinue: - outputTriplet(out, visit, "continue;\n", "", ""); - break; - case EOpReturn: - if (visit == PreVisit) - { - if (node->getExpression()) - { - out << "return "; - } - else - { - out << "return;\n"; - } - } - else if (visit == PostVisit) - { - if (node->getExpression()) - { - out << ";\n"; - } - } - break; - default: UNREACHABLE(); - } + TInfoSinkBase &out = getInfoSink(); - return true; -} - -bool OutputHLSL::isSingleStatement(TIntermNode *node) -{ - TIntermAggregate *aggregate = node->getAsAggregate(); - - if (aggregate) - { - if (aggregate->getOp() == EOpSequence) - { - return false; - } - else if (aggregate->getOp() == EOpDeclaration) - { - // Declaring multiple comma-separated variables must be considered multiple statements - // because each individual declaration has side effects which are visible in the next. - return false; - } - else + switch (node->getFlowOp()) { - for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++) - { - if (!isSingleStatement(*sit)) + case EOpKill: + out << "discard"; + break; + case EOpBreak: + if (mNestedLoopDepth > 1) { - return false; + mUsesNestedBreak = true; } - } - return true; + if (mExcessiveLoopIndex) + { + out << "{Break"; + mExcessiveLoopIndex->traverse(this); + out << " = true; break;}\n"; + } + else + { + out << "break"; + } + break; + case EOpContinue: + out << "continue"; + break; + case EOpReturn: + if (node->getExpression()) + { + out << "return "; + } + else + { + out << "return"; + } + break; + default: + UNREACHABLE(); } } @@ -2965,28 +2360,29 @@ 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). +// (The D3D documentation says 255 iterations, but the compiler complains at anything more than +// 254). bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) { const int MAX_LOOP_ITERATIONS = 254; // Parse loops of the form: // for(int index = initial; index [comparator] limit; index += increment) - TIntermSymbol *index = NULL; + TIntermSymbol *index = nullptr; TOperator comparator = EOpNull; - int initial = 0; - int limit = 0; - int increment = 0; + int initial = 0; + int limit = 0; + int increment = 0; // Parse index name and intial value if (node->getInit()) { - TIntermAggregate *init = node->getInit()->getAsAggregate(); + TIntermDeclaration *init = node->getInit()->getAsDeclarationNode(); if (init) { TIntermSequence *sequence = init->getSequence(); - TIntermTyped *variable = (*sequence)[0]->getAsTyped(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); if (variable && variable->getQualifier() == EvqTemporary) { @@ -2994,14 +2390,14 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) if (assign->getOp() == EOpInitialize) { - TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); + TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion(); if (symbol && constant) { if (constant->getBasicType() == EbtInt && constant->isScalar()) { - index = symbol; + index = symbol; initial = constant->getIConst(0); } } @@ -3011,7 +2407,7 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) } // Parse comparator and limit value - if (index != NULL && node->getCondition()) + if (index != nullptr && node->getCondition()) { TIntermBinary *test = node->getCondition()->getAsBinaryNode(); @@ -3024,21 +2420,21 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) if (constant->getBasicType() == EbtInt && constant->isScalar()) { comparator = test->getOp(); - limit = constant->getIConst(0); + limit = constant->getIConst(0); } } } } // Parse increment - if (index != NULL && comparator != EOpNull && node->getExpression()) + if (index != nullptr && comparator != EOpNull && node->getExpression()) { TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); - TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); + TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); if (binaryTerminal) { - TOperator op = binaryTerminal->getOp(); + TOperator op = binaryTerminal->getOp(); TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion(); if (constant) @@ -3049,9 +2445,14 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) switch (op) { - case EOpAddAssign: increment = value; break; - case EOpSubAssign: increment = -value; break; - default: UNIMPLEMENTED(); + case EOpAddAssign: + increment = value; + break; + case EOpSubAssign: + increment = -value; + break; + default: + UNIMPLEMENTED(); } } } @@ -3062,16 +2463,25 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) switch (op) { - case EOpPostIncrement: increment = 1; break; - case EOpPostDecrement: increment = -1; break; - case EOpPreIncrement: increment = 1; break; - case EOpPreDecrement: increment = -1; break; - default: UNIMPLEMENTED(); + case EOpPostIncrement: + increment = 1; + break; + case EOpPostDecrement: + increment = -1; + break; + case EOpPreIncrement: + increment = 1; + break; + case EOpPreDecrement: + increment = -1; + break; + default: + UNIMPLEMENTED(); } } } - if (index != NULL && comparator != EOpNull && increment != 0) + if (index != nullptr && comparator != EOpNull && increment != 0) { if (comparator == EOpLessThanEqual) { @@ -3085,11 +2495,11 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) if (iterations <= MAX_LOOP_ITERATIONS) { - return false; // Not an excessive loop + return false; // Not an excessive loop } TIntermSymbol *restoreIndex = mExcessiveLoopIndex; - mExcessiveLoopIndex = index; + mExcessiveLoopIndex = index; out << "{int "; index->traverse(this); @@ -3111,13 +2521,14 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) out << ") {\n"; } - if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment + if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment { - mExcessiveLoopIndex = NULL; // Stops setting the Break flag + mExcessiveLoopIndex = nullptr; // Stops setting the Break flag } // for(int index = initial; index < clampedLimit; index += increment) - const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : ""; + const char *unroll = + mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : ""; out << unroll << " for("; index->traverse(this); @@ -3163,10 +2574,11 @@ bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) return true; } - else UNIMPLEMENTED(); + else + UNIMPLEMENTED(); } - return false; // Not handled as an excessive loop + return false; // Not handled as an excessive loop } void OutputHLSL::outputTriplet(TInfoSinkBase &out, @@ -3218,7 +2630,7 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol) } else { - nameStr = DecorateIfNeeded(name); + nameStr = DecorateVariableIfNeeded(name); } if (IsSampler(type.getBasicType())) @@ -3238,7 +2650,44 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol) } } - return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type); + TStringStream argString; + argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr + << ArrayString(type); + + // If the structure parameter contains samplers, they need to be passed into the function as + // separate parameters. HLSL doesn't natively support samplers in structs. + if (type.isStructureContainingSamplers()) + { + ASSERT(qualifier != EvqOut && qualifier != EvqInOut); + TVector samplerSymbols; + type.createSamplerSymbols("angle" + nameStr, "", &samplerSymbols, nullptr, mSymbolTable); + for (const TIntermSymbol *sampler : samplerSymbols) + { + const TType &samplerType = sampler->getType(); + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + argString << ", const uint " << sampler->getSymbol() << ArrayString(samplerType); + } + else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + ASSERT(IsSampler(samplerType.getBasicType())); + argString << ", " << QualifierString(qualifier) << " " + << TextureString(samplerType.getBasicType()) << " texture_" + << sampler->getSymbol() << ArrayString(samplerType) << ", " + << QualifierString(qualifier) << " " + << SamplerString(samplerType.getBasicType()) << " sampler_" + << sampler->getSymbol() << ArrayString(samplerType); + } + else + { + ASSERT(IsSampler(samplerType.getBasicType())); + argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) + << " " << sampler->getSymbol() << ArrayString(samplerType); + } + } + } + + return argString.str(); } TString OutputHLSL::initializer(const TType &type) @@ -3259,22 +2708,24 @@ TString OutputHLSL::initializer(const TType &type) return "{" + string + "}"; } -void OutputHLSL::outputConstructor(TInfoSinkBase &out, - Visit visit, - const TType &type, - const char *name, - const TIntermSequence *parameters) +void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node) { - if (type.isArray()) - { - UNIMPLEMENTED(); - } + // Array constructors should have been already pruned from the code. + ASSERT(!node->getType().isArray()); if (visit == PreVisit) { - mStructureHLSL->addConstructor(type, name, parameters); - - out << name << "("; + TString constructorName; + if (node->getBasicType() == EbtStruct) + { + constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct()); + } + else + { + constructorName = + mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence()); + } + out << constructorName << "("; } else if (visit == InVisit) { @@ -3292,12 +2743,12 @@ const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out, { const TConstantUnion *constUnionIterated = constUnion; - const TStructure* structure = type.getStruct(); + const TStructure *structure = type.getStruct(); if (structure) { - out << StructNameString(*structure) + "_ctor("; + out << mStructureHLSL->addStructConstructor(*structure) << "("; - const TFieldList& fields = structure->fields(); + const TFieldList &fields = structure->fields(); for (size_t i = 0; i < fields.size(); i++) { @@ -3314,14 +2765,14 @@ const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out, } else { - size_t size = type.getObjectSize(); + size_t size = type.getObjectSize(); bool writeType = size > 1; if (writeType) { out << TypeString(type) << "("; } - constUnionIterated = WriteConstantUnionArray(out, constUnionIterated, size); + constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size); if (writeType) { out << ")"; @@ -3331,13 +2782,23 @@ const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out, return constUnionIterated; } -void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr) +void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op) { - TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr); - outputTriplet(out, visit, preString.c_str(), ", ", ")"); + if (visit == PreVisit) + { + const char *opStr = GetOperatorString(op); + BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr); + out << "("; + } + else + { + outputTriplet(out, visit, nullptr, ", ", ")"); + } } -bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression) +bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, + TIntermSymbol *symbolNode, + TIntermTyped *expression) { sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); expression->traverse(&searchSymbol); @@ -3362,52 +2823,40 @@ 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; + return !expression->getType().isArrayOfArrays() && + (expression->getAsConstantUnion() || + expression->isConstructorWithOnlyConstantUnionParameters()); } bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out, TIntermSymbol *symbolNode, - TIntermTyped *expression) + TIntermTyped *initializer) { - if (canWriteAsHLSLLiteral(expression)) + if (canWriteAsHLSLLiteral(initializer)) { symbolNode->traverse(this); - if (expression->getType().isArray()) + ASSERT(!symbolNode->getType().isArrayOfArrays()); + if (symbolNode->getType().isArray()) { - out << "[" << expression->getType().getArraySize() << "]"; + out << "[" << symbolNode->getType().getOutermostArraySize() << "]"; } out << " = {"; - if (expression->getAsConstantUnion()) + if (initializer->getAsConstantUnion()) { - TIntermConstantUnion *nodeConst = expression->getAsConstantUnion(); + TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion(); const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer(); - WriteConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize()); + writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize()); } else { - TIntermAggregate *constructor = expression->getAsAggregate(); + TIntermAggregate *constructor = initializer->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()); + writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize()); if (node != constructor->getSequence()->back()) { out << ", "; @@ -3420,47 +2869,6 @@ bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out, return false; } -void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out) -{ - out << "#define ANGLE_USES_DEFERRED_INIT\n" - << "\n" - << "void initializeDeferredGlobals()\n" - << "{\n"; - - for (const auto &deferredGlobal : mDeferredGlobalInitializers) - { - 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()) << " = "; - - if (!writeSameSymbolInitializer(out, symbol, expression)) - { - ASSERT(mInfoSinkStack.top() == &out); - expression->traverse(this); - } - out << ";\n"; - } - else if (selection != nullptr) - { - writeSelection(out, selection); - } - else - { - UNREACHABLE(); - } - } - - out << "}\n" - << "\n"; -} - TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) { const TFieldList &fields = structure.fields(); @@ -3476,18 +2884,19 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) const TString &structNameString = StructNameString(structure); StructEqualityFunction *function = new StructEqualityFunction(); - function->structure = &structure; - function->functionName = "angle_eq_" + structNameString; + function->structure = &structure; + function->functionName = "angle_eq_" + structNameString; TInfoSinkBase fnOut; - fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n" + fnOut << "bool " << function->functionName << "(" << structNameString << " a, " + << structNameString + " b)\n" << "{\n" " return "; for (size_t i = 0; i < fields.size(); i++) { - const TField *field = fields[i]; + const TField *field = fields[i]; const TType *fieldType = field->type(); const TString &fieldNameA = "a." + Decorate(field->name()); @@ -3507,7 +2916,8 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) fnOut << ")"; } - fnOut << ";\n" << "}\n"; + fnOut << ";\n" + << "}\n"; function->functionDefinition = fnOut.c_str(); @@ -3517,7 +2927,7 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) return function->functionName; } -TString OutputHLSL::addArrayEqualityFunction(const TType& type) +TString OutputHLSL::addArrayEqualityFunction(const TType &type) { for (const auto &eqFunction : mArrayEqualityFunctions) { @@ -3527,33 +2937,31 @@ TString OutputHLSL::addArrayEqualityFunction(const TType& type) } } - const TString &typeName = TypeString(type); + TType elementType(type); + elementType.toArrayElementType(); ArrayHelperFunction *function = new ArrayHelperFunction(); - function->type = type; + function->type = type; - TInfoSinkBase fnNameOut; - fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName; - function->functionName = fnNameOut.c_str(); - - TType nonArrayType = type; - nonArrayType.clearArrayness(); + function->functionName = ArrayHelperFunctionName("angle_eq", type); TInfoSinkBase fnOut; - fnOut << "bool " << function->functionName << "(" - << typeName << " a[" << type.getArraySize() << "], " - << typeName << " b[" << type.getArraySize() << "])\n" + const TString &typeName = TypeString(type); + fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type) + << ", " << typeName << " b" << ArrayString(type) << ")\n" << "{\n" - " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" + " for (int i = 0; i < " + << type.getOutermostArraySize() + << "; ++i)\n" " {\n" " if ("; - outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut); + outputEqual(PreVisit, elementType, EOpNotEqual, fnOut); fnOut << "a[i]"; - outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut); + outputEqual(InVisit, elementType, EOpNotEqual, fnOut); fnOut << "b[i]"; - outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut); + outputEqual(PostVisit, elementType, EOpNotEqual, fnOut); fnOut << ") { return false; }\n" " }\n" @@ -3568,7 +2976,7 @@ TString OutputHLSL::addArrayEqualityFunction(const TType& type) return function->functionName; } -TString OutputHLSL::addArrayAssignmentFunction(const TType& type) +TString OutputHLSL::addArrayAssignmentFunction(const TType &type) { for (const auto &assignFunction : mArrayAssignmentFunctions) { @@ -3578,26 +2986,35 @@ TString OutputHLSL::addArrayAssignmentFunction(const TType& type) } } - const TString &typeName = TypeString(type); + TType elementType(type); + elementType.toArrayElementType(); ArrayHelperFunction function; function.type = type; - TInfoSinkBase fnNameOut; - fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName; - function.functionName = fnNameOut.c_str(); + function.functionName = ArrayHelperFunctionName("angle_assign", type); TInfoSinkBase fnOut; - fnOut << "void " << function.functionName << "(out " - << typeName << " a[" << type.getArraySize() << "], " - << typeName << " b[" << type.getArraySize() << "])\n" - << "{\n" - " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" - " {\n" - " a[i] = b[i];\n" - " }\n" - "}\n"; + const TString &typeName = TypeString(type); + fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type) + << ", " << typeName << " b" << ArrayString(type) << ")\n" + << "{\n" + " for (int i = 0; i < " + << type.getOutermostArraySize() + << "; ++i)\n" + " {\n" + " "; + + outputAssign(PreVisit, elementType, fnOut); + fnOut << "a[i]"; + outputAssign(InVisit, elementType, fnOut); + fnOut << "b[i]"; + outputAssign(PostVisit, elementType, fnOut); + + fnOut << ";\n" + " }\n" + "}\n"; function.functionDefinition = fnOut.c_str(); @@ -3606,7 +3023,7 @@ TString OutputHLSL::addArrayAssignmentFunction(const TType& type) return function.functionName; } -TString OutputHLSL::addArrayConstructIntoFunction(const TType& type) +TString OutputHLSL::addArrayConstructIntoFunction(const TType &type) { for (const auto &constructIntoFunction : mArrayConstructIntoFunctions) { @@ -3616,29 +3033,34 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType& type) } } - const TString &typeName = TypeString(type); + TType elementType(type); + elementType.toArrayElementType(); ArrayHelperFunction function; function.type = type; - TInfoSinkBase fnNameOut; - fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName; - function.functionName = fnNameOut.c_str(); + function.functionName = ArrayHelperFunctionName("angle_construct_into", type); TInfoSinkBase fnOut; - fnOut << "void " << function.functionName << "(out " - << typeName << " a[" << type.getArraySize() << "]"; - for (int i = 0; i < type.getArraySize(); ++i) + const TString &typeName = TypeString(type); + fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type); + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) { - fnOut << ", " << typeName << " b" << i; + fnOut << ", " << typeName << " b" << i << ArrayString(elementType); } fnOut << ")\n" "{\n"; - for (int i = 0; i < type.getArraySize(); ++i) + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) { - fnOut << " a[" << i << "] = b" << i << ";\n"; + fnOut << " "; + outputAssign(PreVisit, elementType, fnOut); + fnOut << "a[" << i << "]"; + outputAssign(InVisit, elementType, fnOut); + fnOut << "b" << i; + outputAssign(PostVisit, elementType, fnOut); + fnOut << ";\n"; } fnOut << "}\n"; @@ -3651,14 +3073,12 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType& type) void OutputHLSL::ensureStructDefined(const TType &type) { - TStructure *structure = type.getStruct(); - + const TStructure *structure = type.getStruct(); if (structure) { - mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr); + ASSERT(type.getBasicType() == EbtStruct); + mStructureHLSL->ensureStructDefined(*structure); } } - - -} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h index 8756d0ba4c..014f4f5002 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h @@ -8,67 +8,94 @@ #define COMPILER_TRANSLATOR_OUTPUTHLSL_H_ #include -#include #include #include #include "angle_gl.h" #include "compiler/translator/ASTMetadataHLSL.h" -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/ParseContext.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/IntermTraverse.h" class BuiltInFunctionEmulator; namespace sh { -class UnfoldShortCircuit; class StructureHLSL; +class TextureFunctionHLSL; +class TSymbolTable; +class ImageFunctionHLSL; +class UnfoldShortCircuit; class UniformHLSL; -typedef std::map ReferencedSymbols; +typedef std::map ReferencedSymbols; class OutputHLSL : public TIntermTraverser { public: - OutputHLSL(sh::GLenum shaderType, int shaderVersion, - const TExtensionBehavior &extensionBehavior, - const char *sourcePath, ShShaderOutput outputType, - int numRenderTargets, const std::vector &uniforms, - int compileOptions); + OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + const std::vector &uniforms, + ShCompileOptions compileOptions, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics); ~OutputHLSL(); void output(TIntermNode *treeRoot, TInfoSinkBase &objSink); - const std::map &getInterfaceBlockRegisterMap() const; + const std::map &getUniformBlockRegisterMap() const; const std::map &getUniformRegisterMap() const; static TString initializer(const TType &type); - TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); } + TInfoSinkBase &getInfoSink() + { + ASSERT(!mInfoSinkStack.empty()); + return *mInfoSinkStack.top(); + } static bool canWriteAsHLSLLiteral(TIntermTyped *expression); protected: - void header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator); + void header(TInfoSinkBase &out, + const std::vector &std140Structs, + const BuiltInFunctionEmulator *builtInFunctionEmulator) const; + + void writeFloat(TInfoSinkBase &out, float f); + void writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion); + const TConstantUnion *writeConstantUnionArray(TInfoSinkBase &out, + const TConstantUnion *const constUnion, + const size_t size); // Visit AST nodes and output their code to the body stream - void visitSymbol(TIntermSymbol*); - void visitRaw(TIntermRaw*); - void visitConstantUnion(TIntermConstantUnion*); - bool visitBinary(Visit visit, TIntermBinary*); - bool visitUnary(Visit visit, TIntermUnary*); - bool visitSelection(Visit visit, TIntermSelection*); - bool visitSwitch(Visit visit, TIntermSwitch *); - bool visitCase(Visit visit, TIntermCase *); - bool visitAggregate(Visit visit, TIntermAggregate*); - bool visitLoop(Visit visit, TIntermLoop*); - bool visitBranch(Visit visit, TIntermBranch*); - - bool isSingleStatement(TIntermNode *node); + void visitSymbol(TIntermSymbol *) override; + void visitRaw(TIntermRaw *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *) override; + bool visitUnary(Visit visit, TIntermUnary *) override; + bool visitTernary(Visit visit, TIntermTernary *) override; + bool visitIfElse(Visit visit, TIntermIfElse *) override; + bool visitSwitch(Visit visit, TIntermSwitch *) override; + bool visitCase(Visit visit, TIntermCase *) override; + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit visit, TIntermBranch *) override; + 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. + // Emit one of three strings depending on traverse phase. Called with literal strings so using + // const char* instead of TString. void outputTriplet(TInfoSinkBase &out, Visit visit, const char *preString, @@ -76,32 +103,28 @@ class OutputHLSL : public TIntermTraverser 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(TInfoSinkBase &out, - Visit visit, - const TType &type, - const char *name, - const TIntermSequence *parameters); + + void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node); const TConstantUnion *writeConstantUnion(TInfoSinkBase &out, const TType &type, const TConstantUnion *constUnion); void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out); + void outputAssign(Visit visit, const TType &type, TInfoSinkBase &out); - void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, const char *preStr); - void makeFlaggedStructMaps(const std::vector &flaggedStructs); + void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op); - // 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 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); + void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node); // Returns the function name TString addStructEqualityFunction(const TStructure &structure); @@ -117,7 +140,7 @@ class OutputHLSL : public TIntermTraverser const TExtensionBehavior &mExtensionBehavior; const char *mSourcePath; const ShShaderOutput mOutputType; - int mCompileOptions; + ShCompileOptions mCompileOptions; bool mInsideFunction; @@ -126,49 +149,23 @@ class OutputHLSL : public TIntermTraverser TInfoSinkBase mBody; TInfoSinkBase mFooter; - // A stack is useful when we want to traverse in the header, or in helper functions, but not always - // write to the body. Instead use an InfoSink stack to keep our current state intact. + // A stack is useful when we want to traverse in the header, or in helper functions, but not + // always write to the body. Instead use an InfoSink stack to keep our current state intact. // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler. std::stack mInfoSinkStack; ReferencedSymbols mReferencedUniforms; - ReferencedSymbols mReferencedInterfaceBlocks; + ReferencedSymbols mReferencedUniformBlocks; ReferencedSymbols mReferencedAttributes; ReferencedSymbols mReferencedVaryings; ReferencedSymbols mReferencedOutputVariables; StructureHLSL *mStructureHLSL; UniformHLSL *mUniformHLSL; - - struct TextureFunction - { - enum Method - { - IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) - BIAS, - LOD, - LOD0, - LOD0BIAS, - SIZE, // textureSize() - FETCH, - GRAD - }; - - TBasicType sampler; - int coords; - bool proj; - bool offset; - Method method; - - TString name() const; - - bool operator<(const TextureFunction &rhs) const; - }; - - typedef std::set TextureFunctionSet; + TextureFunctionHLSL *mTextureFunctionHLSL; + ImageFunctionHLSL *mImageFunctionHLSL; // Parameters determining what goes in the header output - TextureFunctionSet mUsesTexture; bool mUsesFragColor; bool mUsesFragData; bool mUsesDepthRange; @@ -177,16 +174,23 @@ class OutputHLSL : public TIntermTraverser bool mUsesFrontFacing; bool mUsesPointSize; bool mUsesInstanceID; + bool mHasMultiviewExtensionEnabled; + bool mUsesViewID; + bool mUsesVertexID; bool mUsesFragDepth; + bool mUsesNumWorkGroups; + bool mUsesWorkGroupID; + bool mUsesLocalInvocationID; + bool mUsesGlobalInvocationID; + bool mUsesLocalInvocationIndex; bool mUsesXor; bool mUsesDiscardRewriting; bool mUsesNestedBreak; bool mRequiresIEEEStrictCompiling; - int mNumRenderTargets; - int mUniqueIndex; // For creating unique names + int mUniqueIndex; // For creating unique names CallDAG mCallDag; MetadataList mASTMetadataList; @@ -197,15 +201,7 @@ class OutputHLSL : public TIntermTraverser TIntermSymbol *mExcessiveLoopIndex; - TString structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName); - - std::map mFlaggedStructMappedNames; - std::map mFlaggedStructOriginalNames; - - // 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; + TString structInitializerString(int indent, const TType &type, const TString &name) const; struct HelperFunction { @@ -219,28 +215,34 @@ class OutputHLSL : public TIntermTraverser // which we add the functions, since nested structures call each other recursively, and // structure equality functions may need to call array equality functions and vice versa. // The ownership of the pointers is maintained by the type-specific arrays. - std::vector mEqualityFunctions; + std::vector mEqualityFunctions; struct StructEqualityFunction : public HelperFunction { const TStructure *structure; }; - std::vector mStructEqualityFunctions; + std::vector mStructEqualityFunctions; struct ArrayHelperFunction : public HelperFunction { TType type; }; - std::vector mArrayEqualityFunctions; + 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. + // 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; -}; + PerformanceDiagnostics *mPerfDiagnostics; + + private: + TString generateStructMapping(const std::vector &std140Structs) const; + TString samplerNamePrefixFromStruct(TIntermTyped *node); + bool ancestorEvaluatesToSamplerInStruct(); +}; } -#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputTree.cpp b/src/3rdparty/angle/src/compiler/translator/OutputTree.cpp new file mode 100644 index 0000000000..25e8298af3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/OutputTree.cpp @@ -0,0 +1,682 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info) +{ + const char *internal = info->getNameObj().isInternal() ? " (internal function)" : ""; + out << str << internal << ": " << info->getNameObj().getString() << " (symbol id " + << info->getId().get() << ")"; +} + +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can also directly call traverse() on +// children themselves to have finer grained control over the process than shown here, though +// that's not recommended if it can be avoided. +// 2. Print out a text based description of the tree. + +// The traverser subclass is used to carry along data from node to node in the traversal. +class TOutputTraverser : public TIntermTraverser +{ + public: + TOutputTraverser(TInfoSinkBase &out) : TIntermTraverser(true, false, false), mOut(out) {} + + protected: + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *) override; + bool visitUnary(Visit visit, TIntermUnary *) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit visit, TIntermSwitch *node) override; + bool visitCase(Visit visit, TIntermCase *node) override; + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *) override; + bool visitBlock(Visit visit, TIntermBlock *) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit visit, TIntermBranch *) override; + + TInfoSinkBase &mOut; +}; + +// +// Helper functions for printing, not part of traversing. +// +void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth) +{ + int i; + + out.location(node->getLine().first_file, node->getLine().first_line); + + for (i = 0; i < depth; ++i) + out << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol *node) +{ + OutputTreeText(mOut, node, mDepth); + + mOut << "'" << node->getSymbol() << "' "; + mOut << "(symbol id " << node->getId() << ") "; + mOut << "(" << node->getCompleteString() << ")"; + mOut << "\n"; +} + +bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + OutputTreeText(mOut, node, mDepth); + mOut << "vector swizzle ("; + node->writeOffsetsAsXYZW(&mOut); + mOut << ")"; + + mOut << " (" << node->getCompleteString() << ")"; + mOut << "\n"; + return true; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + OutputTreeText(mOut, node, mDepth); + + switch (node->getOp()) + { + case EOpComma: + mOut << "comma"; + break; + case EOpAssign: + mOut << "move second child to first child"; + break; + case EOpInitialize: + mOut << "initialize first child with second child"; + break; + case EOpAddAssign: + mOut << "add second child into first child"; + break; + case EOpSubAssign: + mOut << "subtract second child into first child"; + break; + case EOpMulAssign: + mOut << "multiply second child into first child"; + break; + case EOpVectorTimesMatrixAssign: + mOut << "matrix mult second child into first child"; + break; + case EOpVectorTimesScalarAssign: + mOut << "vector scale second child into first child"; + break; + case EOpMatrixTimesScalarAssign: + mOut << "matrix scale second child into first child"; + break; + case EOpMatrixTimesMatrixAssign: + mOut << "matrix mult second child into first child"; + break; + case EOpDivAssign: + mOut << "divide second child into first child"; + break; + case EOpIModAssign: + mOut << "modulo second child into first child"; + break; + case EOpBitShiftLeftAssign: + mOut << "bit-wise shift first child left by second child"; + break; + case EOpBitShiftRightAssign: + mOut << "bit-wise shift first child right by second child"; + break; + case EOpBitwiseAndAssign: + mOut << "bit-wise and second child into first child"; + break; + case EOpBitwiseXorAssign: + mOut << "bit-wise xor second child into first child"; + break; + case EOpBitwiseOrAssign: + mOut << "bit-wise or second child into first child"; + break; + + case EOpIndexDirect: + mOut << "direct index"; + break; + case EOpIndexIndirect: + mOut << "indirect index"; + break; + case EOpIndexDirectStruct: + mOut << "direct index for structure"; + break; + case EOpIndexDirectInterfaceBlock: + mOut << "direct index for interface block"; + break; + + case EOpAdd: + mOut << "add"; + break; + case EOpSub: + mOut << "subtract"; + break; + case EOpMul: + mOut << "component-wise multiply"; + break; + case EOpDiv: + mOut << "divide"; + break; + case EOpIMod: + mOut << "modulo"; + break; + case EOpBitShiftLeft: + mOut << "bit-wise shift left"; + break; + case EOpBitShiftRight: + mOut << "bit-wise shift right"; + break; + case EOpBitwiseAnd: + mOut << "bit-wise and"; + break; + case EOpBitwiseXor: + mOut << "bit-wise xor"; + break; + case EOpBitwiseOr: + mOut << "bit-wise or"; + break; + + case EOpEqual: + mOut << "Compare Equal"; + break; + case EOpNotEqual: + mOut << "Compare Not Equal"; + break; + case EOpLessThan: + mOut << "Compare Less Than"; + break; + case EOpGreaterThan: + mOut << "Compare Greater Than"; + break; + case EOpLessThanEqual: + mOut << "Compare Less Than or Equal"; + break; + case EOpGreaterThanEqual: + mOut << "Compare Greater Than or Equal"; + break; + + case EOpVectorTimesScalar: + mOut << "vector-scale"; + break; + case EOpVectorTimesMatrix: + mOut << "vector-times-matrix"; + break; + case EOpMatrixTimesVector: + mOut << "matrix-times-vector"; + break; + case EOpMatrixTimesScalar: + mOut << "matrix-scale"; + break; + case EOpMatrixTimesMatrix: + mOut << "matrix-multiply"; + break; + + case EOpLogicalOr: + mOut << "logical-or"; + break; + case EOpLogicalXor: + mOut << "logical-xor"; + break; + case EOpLogicalAnd: + mOut << "logical-and"; + break; + default: + mOut << ""; + } + + mOut << " (" << node->getCompleteString() << ")"; + + mOut << "\n"; + + // Special handling for direct indexes. Because constant + // unions are not aware they are struct indexes, treat them + // here where we have that contextual knowledge. + if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock) + { + node->getLeft()->traverse(this); + + TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); + ASSERT(intermConstantUnion); + + OutputTreeText(mOut, intermConstantUnion, mDepth + 1); + + // The following code finds the field name from the constant union + const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer(); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + ASSERT(structure || interfaceBlock); + + const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); + + const TField *field = fields[constantUnion->getIConst()]; + + mOut << constantUnion->getIConst() << " (field '" << field->name() << "')"; + + mOut << "\n"; + + return false; + } + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + OutputTreeText(mOut, node, mDepth); + + switch (node->getOp()) + { + // Give verbose names for ops that have special syntax and some built-in functions that are + // easy to confuse with others, but mostly use GLSL names for functions. + case EOpNegative: + mOut << "Negate value"; + break; + case EOpPositive: + mOut << "Positive sign"; + break; + case EOpLogicalNot: + mOut << "negation"; + break; + case EOpBitwiseNot: + mOut << "bit-wise not"; + break; + + case EOpPostIncrement: + mOut << "Post-Increment"; + break; + case EOpPostDecrement: + mOut << "Post-Decrement"; + break; + case EOpPreIncrement: + mOut << "Pre-Increment"; + break; + case EOpPreDecrement: + mOut << "Pre-Decrement"; + break; + + case EOpArrayLength: + mOut << "Array length"; + break; + + case EOpLogicalNotComponentWise: + mOut << "component-wise not"; + break; + + default: + mOut << GetOperatorString(node->getOp()); + break; + } + + mOut << " (" << node->getCompleteString() << ")"; + + mOut << "\n"; + + return true; +} + +bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + OutputTreeText(mOut, node, mDepth); + mOut << "Function Definition:\n"; + mOut << "\n"; + return true; +} + +bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + OutputTreeText(mOut, node, mDepth); + mOut << "Invariant Declaration:\n"; + return true; +} + +bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) +{ + OutputTreeText(mOut, node, mDepth); + OutputFunction(mOut, "Function Prototype", node->getFunctionSymbolInfo()); + mOut << " (" << node->getCompleteString() << ")"; + mOut << "\n"; + + return true; +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + OutputTreeText(mOut, node, mDepth); + + if (node->getOp() == EOpNull) + { + mOut.prefix(SH_ERROR); + mOut << "node is still EOpNull!\n"; + return true; + } + + // Give verbose names for some built-in functions that are easy to confuse with others, but + // mostly use GLSL names for functions. + switch (node->getOp()) + { + case EOpCallFunctionInAST: + OutputFunction(mOut, "Call an user-defined function", node->getFunctionSymbolInfo()); + break; + case EOpCallInternalRawFunction: + OutputFunction(mOut, "Call an internal function with raw implementation", + node->getFunctionSymbolInfo()); + break; + case EOpCallBuiltInFunction: + OutputFunction(mOut, "Call a built-in function", node->getFunctionSymbolInfo()); + break; + + case EOpConstruct: + // The type of the constructor will be printed below. + mOut << "Construct"; + break; + + case EOpEqualComponentWise: + mOut << "component-wise equal"; + break; + case EOpNotEqualComponentWise: + mOut << "component-wise not equal"; + break; + case EOpLessThanComponentWise: + mOut << "component-wise less than"; + break; + case EOpGreaterThanComponentWise: + mOut << "component-wise greater than"; + break; + case EOpLessThanEqualComponentWise: + mOut << "component-wise less than or equal"; + break; + case EOpGreaterThanEqualComponentWise: + mOut << "component-wise greater than or equal"; + break; + + case EOpDot: + mOut << "dot product"; + break; + case EOpCross: + mOut << "cross product"; + break; + case EOpMulMatrixComponentWise: + mOut << "component-wise multiply"; + break; + + default: + mOut << GetOperatorString(node->getOp()); + break; + } + + mOut << " (" << node->getCompleteString() << ")"; + + mOut << "\n"; + + return true; +} + +bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + OutputTreeText(mOut, node, mDepth); + mOut << "Code block\n"; + + return true; +} + +bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + OutputTreeText(mOut, node, mDepth); + mOut << "Declaration\n"; + + return true; +} + +bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + OutputTreeText(mOut, node, mDepth); + + mOut << "Ternary selection"; + mOut << " (" << node->getCompleteString() << ")\n"; + + ++mDepth; + + OutputTreeText(mOut, node, mDepth); + mOut << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(mOut, node, mDepth); + if (node->getTrueExpression()) + { + mOut << "true case\n"; + node->getTrueExpression()->traverse(this); + } + if (node->getFalseExpression()) + { + OutputTreeText(mOut, node, mDepth); + mOut << "false case\n"; + node->getFalseExpression()->traverse(this); + } + + --mDepth; + + return false; +} + +bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node) +{ + OutputTreeText(mOut, node, mDepth); + + mOut << "If test\n"; + + ++mDepth; + + OutputTreeText(mOut, node, mDepth); + mOut << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(mOut, node, mDepth); + if (node->getTrueBlock()) + { + mOut << "true case\n"; + node->getTrueBlock()->traverse(this); + } + else + { + mOut << "true case is null\n"; + } + + if (node->getFalseBlock()) + { + OutputTreeText(mOut, node, mDepth); + mOut << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --mDepth; + + return false; +} + +bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + OutputTreeText(mOut, node, mDepth); + + mOut << "Switch\n"; + + return true; +} + +bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node) +{ + OutputTreeText(mOut, node, mDepth); + + if (node->getCondition() == nullptr) + { + mOut << "Default\n"; + } + else + { + mOut << "Case\n"; + } + + return true; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + size_t size = node->getType().getObjectSize(); + + for (size_t i = 0; i < size; i++) + { + OutputTreeText(mOut, node, mDepth); + switch (node->getUnionArrayPointer()[i].getType()) + { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + mOut << "true"; + else + mOut << "false"; + + mOut << " (" + << "const bool" + << ")"; + mOut << "\n"; + break; + case EbtFloat: + mOut << node->getUnionArrayPointer()[i].getFConst(); + mOut << " (const float)\n"; + break; + case EbtInt: + mOut << node->getUnionArrayPointer()[i].getIConst(); + mOut << " (const int)\n"; + break; + case EbtUInt: + mOut << node->getUnionArrayPointer()[i].getUConst(); + mOut << " (const uint)\n"; + break; + case EbtYuvCscStandardEXT: + mOut << getYuvCscStandardEXTString( + node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst()); + mOut << " (const yuvCscStandardEXT)\n"; + break; + default: + mOut.prefix(SH_ERROR); + mOut << "Unknown constant\n"; + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node) +{ + OutputTreeText(mOut, node, mDepth); + + mOut << "Loop with condition "; + if (node->getType() == ELoopDoWhile) + mOut << "not "; + mOut << "tested first\n"; + + ++mDepth; + + OutputTreeText(mOut, node, mDepth); + if (node->getCondition()) + { + mOut << "Loop Condition\n"; + node->getCondition()->traverse(this); + } + else + { + mOut << "No loop condition\n"; + } + + OutputTreeText(mOut, node, mDepth); + if (node->getBody()) + { + mOut << "Loop Body\n"; + node->getBody()->traverse(this); + } + else + { + mOut << "No loop body\n"; + } + + if (node->getExpression()) + { + OutputTreeText(mOut, node, mDepth); + mOut << "Loop Terminal Expression\n"; + node->getExpression()->traverse(this); + } + + --mDepth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) +{ + OutputTreeText(mOut, node, mDepth); + + switch (node->getFlowOp()) + { + case EOpKill: + mOut << "Branch: Kill"; + break; + case EOpBreak: + mOut << "Branch: Break"; + break; + case EOpContinue: + mOut << "Branch: Continue"; + break; + case EOpReturn: + mOut << "Branch: Return"; + break; + default: + mOut << "Branch: Unknown Branch"; + break; + } + + if (node->getExpression()) + { + mOut << " with expression\n"; + ++mDepth; + node->getExpression()->traverse(this); + --mDepth; + } + else + { + mOut << "\n"; + } + + return false; +} + +} // anonymous namespace + +void OutputTree(TIntermNode *root, TInfoSinkBase &out) +{ + TOutputTraverser it(out); + ASSERT(root); + root->traverse(&it); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputTree.h b/src/3rdparty/angle/src/compiler/translator/OutputTree.h new file mode 100644 index 0000000000..9f11989cb1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/OutputTree.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Output the AST intermediate representation of the GLSL code. + +#ifndef COMPILER_TRANSLATOR_OUTPUTTREE_H_ +#define COMPILER_TRANSLATOR_OUTPUTTREE_H_ + +namespace sh +{ + +class TIntermNode; +class TInfoSinkBase; + +// Output the AST along with metadata. +void OutputTree(TIntermNode *root, TInfoSinkBase &out); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTTREE_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.cpp new file mode 100644 index 0000000000..6d11deb898 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// OutputVulkanGLSL: +// Code that outputs shaders that fit GL_KHR_vulkan_glsl. +// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side). +// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt +// + +#include "compiler/translator/OutputVulkanGLSL.h" + +#include "compiler/translator/util.h" + +namespace sh +{ + +TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions) + : TOutputGLSL(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderType, + shaderVersion, + output, + compileOptions) +{ +} + +// TODO(jmadill): This is not complete. +void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable) +{ + const TType &type = variable->getType(); + + bool needsCustomLayout = + (type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut || + type.getQualifier() == EvqVertexIn || IsVarying(type.getQualifier()) || + IsSampler(type.getBasicType())); + + if (!NeedsToWriteLayoutQualifier(type) && !needsCustomLayout) + { + return; + } + + TInfoSinkBase &out = objSink(); + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + out << "layout("; + + // This isn't super clean, but it gets the job done. + // See corresponding code in GlslangWrapper.cpp. + // TODO(jmadill): Ensure declarations are separated. + + TIntermSymbol *symbol = variable->getAsSymbolNode(); + ASSERT(symbol); + + if (needsCustomLayout) + { + out << "@@ LAYOUT-" << symbol->getName().getString() << " @@"; + } + + if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified) + { + ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform); + out << getImageInternalFormatString(layoutQualifier.imageInternalFormat); + } + + out << ") "; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.h new file mode 100644 index 0000000000..6e5da8b53e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/OutputVulkanGLSL.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// OutputVulkanGLSL: +// Code that outputs shaders that fit GL_KHR_vulkan_glsl. +// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side). +// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt +// + +#include "compiler/translator/OutputGLSL.h" + +namespace sh +{ + +class TOutputVulkanGLSL : public TOutputGLSL +{ + public: + TOutputVulkanGLSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions); + + protected: + void writeLayoutQualifier(TIntermTyped *variable) override; +}; + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ParamType.h b/src/3rdparty/angle/src/compiler/translator/ParamType.h new file mode 100644 index 0000000000..dddb4e9901 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ParamType.h @@ -0,0 +1,102 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ParamType: +// Helper type for built-in function emulator tables. Defines types for parameters. + +#ifndef COMPILER_TRANSLATOR_PARAMTYPE_H_ +#define COMPILER_TRANSLATOR_PARAMTYPE_H_ + +#include "common/angleutils.h" +#include "compiler/translator/BaseTypes.h" + +namespace sh +{ + +enum class ParamType : uint8_t +{ + Void, + Bool1, + Bool2, + Bool3, + Bool4, + Float1, + Float2, + Float3, + Float4, + Int1, + Int2, + Int3, + Int4, + Mat2, + Mat3, + Mat4, + Uint1, + Uint2, + Uint3, + Uint4, + Last, +}; + +struct ParamTypeInfo +{ + ParamType self; + TBasicType basicType; + int primarySize; + int secondarySize; +}; + +constexpr ParamTypeInfo g_ParamTypeInfo[] = { + {ParamType::Void, EbtVoid, 1, 1}, {ParamType::Bool1, EbtBool, 1, 1}, + {ParamType::Bool2, EbtBool, 2, 1}, {ParamType::Bool3, EbtBool, 3, 1}, + {ParamType::Bool4, EbtBool, 4, 1}, {ParamType::Float1, EbtFloat, 1, 1}, + {ParamType::Float2, EbtFloat, 2, 1}, {ParamType::Float3, EbtFloat, 3, 1}, + {ParamType::Float4, EbtFloat, 4, 1}, {ParamType::Int1, EbtInt, 1, 1}, + {ParamType::Int2, EbtInt, 2, 1}, {ParamType::Int3, EbtInt, 3, 1}, + {ParamType::Int4, EbtInt, 4, 1}, {ParamType::Mat2, EbtFloat, 2, 2}, + {ParamType::Mat3, EbtFloat, 3, 3}, {ParamType::Mat4, EbtFloat, 4, 4}, + {ParamType::Uint1, EbtUInt, 1, 1}, {ParamType::Uint2, EbtUInt, 2, 1}, + {ParamType::Uint3, EbtUInt, 3, 1}, {ParamType::Uint4, EbtUInt, 4, 1}, +}; + +constexpr size_t ParamTypeIndex(ParamType paramType) +{ + return static_cast(paramType); +} + +constexpr size_t NumParamTypes() +{ + return ParamTypeIndex(ParamType::Last); +} + +static_assert(ArraySize(g_ParamTypeInfo) == NumParamTypes(), "Invalid array size"); + +constexpr TBasicType GetBasicType(ParamType paramType) +{ + return g_ParamTypeInfo[ParamTypeIndex(paramType)].basicType; +} + +constexpr int GetPrimarySize(ParamType paramType) +{ + return g_ParamTypeInfo[ParamTypeIndex(paramType)].primarySize; +} + +constexpr int GetSecondarySize(ParamType paramType) +{ + return g_ParamTypeInfo[ParamTypeIndex(paramType)].secondarySize; +} + +constexpr bool SameParamType(ParamType paramType, + TBasicType basicType, + int primarySize, + int secondarySize) +{ + return GetBasicType(paramType) == basicType && primarySize == GetPrimarySize(paramType) && + secondarySize == GetSecondarySize(paramType); +} + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_PARAMTYPE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp index 235351cf41..c97f91d781 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp @@ -9,34 +9,252 @@ #include #include +#include "common/mathutil.h" #include "compiler/preprocessor/SourceLocation.h" #include "compiler/translator/Cache.h" -#include "compiler/translator/glslang.h" -#include "compiler/translator/ValidateSwitch.h" +#include "compiler/translator/IntermNode_util.h" #include "compiler/translator/ValidateGlobalInitializer.h" +#include "compiler/translator/ValidateSwitch.h" +#include "compiler/translator/glslang.h" #include "compiler/translator/util.h" +namespace sh +{ + /////////////////////////////////////////////////////////////////////// // // Sub- vector and matrix fields // //////////////////////////////////////////////////////////////////////// -// -// Look at a '.' field selector string and change it into offsets -// for a vector. -// -bool TParseContext::parseVectorFields(const TString &compString, +namespace +{ + +const int kWebGLMaxStructNesting = 4; + +const std::array kAtomicBuiltin = {{"atomicAdd", "atomicMin", "atomicMax", + "atomicAnd", "atomicOr", "atomicXor", + "atomicExchange", "atomicCompSwap"}}; + +bool IsAtomicBuiltin(const TString &name) +{ + for (size_t i = 0; i < kAtomicBuiltin.size(); ++i) + { + if (name.compare(kAtomicBuiltin[i]) == 0) + { + return true; + } + } + return false; +} + +bool ContainsSampler(const TStructure *structType); + +bool ContainsSampler(const TType &type) +{ + if (IsSampler(type.getBasicType())) + { + return true; + } + if (type.getBasicType() == EbtStruct) + { + return ContainsSampler(type.getStruct()); + } + + return false; +} + +bool ContainsSampler(const TStructure *structType) +{ + for (const auto &field : structType->fields()) + { + if (ContainsSampler(*field->type())) + return true; + } + return false; +} + +// Get a token from an image argument to use as an error message token. +const char *GetImageArgumentToken(TIntermTyped *imageNode) +{ + ASSERT(IsImage(imageNode->getBasicType())); + while (imageNode->getAsBinaryNode() && + (imageNode->getAsBinaryNode()->getOp() == EOpIndexIndirect || + imageNode->getAsBinaryNode()->getOp() == EOpIndexDirect)) + { + imageNode = imageNode->getAsBinaryNode()->getLeft(); + } + TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode(); + if (imageSymbol) + { + return imageSymbol->getSymbol().c_str(); + } + return "image"; +} + +bool CanSetDefaultPrecisionOnType(const TPublicType &type) +{ + if (!SupportsPrecision(type.getBasicType())) + { + return false; + } + if (type.getBasicType() == EbtUInt) + { + // ESSL 3.00.4 section 4.5.4 + return false; + } + if (type.isAggregate()) + { + // Not allowed to set for aggregate types + return false; + } + return true; +} + +// Map input primitive types to input array sizes in a geometry shader. +GLuint GetGeometryShaderInputArraySize(TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) + { + case EptPoints: + return 1u; + case EptLines: + return 2u; + case EptTriangles: + return 3u; + case EptLinesAdjacency: + return 4u; + case EptTrianglesAdjacency: + return 6u; + default: + UNREACHABLE(); + return 0u; + } +} + +bool IsBufferOrSharedVariable(TIntermTyped *var) +{ + if (var->isInterfaceBlock() || var->getQualifier() == EvqBuffer || + var->getQualifier() == EvqShared) + { + return true; + } + return false; +} + +} // namespace + +// This tracks each binding point's current default offset for inheritance of subsequent +// variables using the same binding, and keeps offsets unique and non overlapping. +// See GLSL ES 3.1, section 4.4.6. +class TParseContext::AtomicCounterBindingState +{ + public: + AtomicCounterBindingState() : mDefaultOffset(0) {} + // Inserts a new span and returns -1 if overlapping, else returns the starting offset of + // newly inserted span. + int insertSpan(int start, size_t length) + { + gl::RangeI newSpan(start, start + static_cast(length)); + for (const auto &span : mSpans) + { + if (newSpan.intersects(span)) + { + return -1; + } + } + mSpans.push_back(newSpan); + mDefaultOffset = newSpan.high(); + return start; + } + // Inserts a new span starting from the default offset. + int appendSpan(size_t length) { return insertSpan(mDefaultOffset, length); } + void setDefaultOffset(int offset) { mDefaultOffset = offset; } + + private: + int mDefaultOffset; + std::vector mSpans; +}; + +TParseContext::TParseContext(TSymbolTable &symt, + TExtensionBehavior &ext, + sh::GLenum type, + ShShaderSpec spec, + ShCompileOptions options, + bool checksPrecErrors, + TDiagnostics *diagnostics, + const ShBuiltInResources &resources) + : symbolTable(symt), + mDeferredNonEmptyDeclarationErrorCheck(false), + mShaderType(type), + mShaderSpec(spec), + mCompileOptions(options), + mShaderVersion(100), + mTreeRoot(nullptr), + mLoopNestingLevel(0), + mStructNestingLevel(0), + mSwitchNestingLevel(0), + mCurrentFunctionType(nullptr), + mFunctionReturnsValue(false), + mChecksPrecisionErrors(checksPrecErrors), + mFragmentPrecisionHighOnESSL1(false), + mDefaultUniformMatrixPacking(EmpColumnMajor), + mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), + mDefaultBufferMatrixPacking(EmpColumnMajor), + mDefaultBufferBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), + mDiagnostics(diagnostics), + mDirectiveHandler(ext, + *mDiagnostics, + mShaderVersion, + mShaderType, + resources.WEBGL_debug_shader_precision == 1), + mPreprocessor(mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()), + mScanner(nullptr), + mUsesFragData(false), + mUsesFragColor(false), + mUsesSecondaryOutputs(false), + mMinProgramTexelOffset(resources.MinProgramTexelOffset), + mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), + mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset), + mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset), + mComputeShaderLocalSizeDeclared(false), + mComputeShaderLocalSize(-1), + mNumViews(-1), + mMaxNumViews(resources.MaxViewsOVR), + mMaxImageUnits(resources.MaxImageUnits), + mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits), + mMaxUniformLocations(resources.MaxUniformLocations), + mMaxUniformBufferBindings(resources.MaxUniformBufferBindings), + mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings), + mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings), + mDeclaringFunction(false), + mGeometryShaderInputPrimitiveType(EptUndefined), + mGeometryShaderOutputPrimitiveType(EptUndefined), + mGeometryShaderInvocations(0), + mGeometryShaderMaxVertices(-1), + mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations), + mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices), + mGeometryShaderInputArraySize(0u) +{ +} + +TParseContext::~TParseContext() +{ +} + +bool TParseContext::parseVectorFields(const TSourceLoc &line, + const TString &compString, int vecSize, - TVectorFields &fields, - const TSourceLoc &line) + TVector *fieldOffsets) { - fields.num = (int)compString.size(); - if (fields.num > 4) + ASSERT(fieldOffsets); + size_t fieldCount = compString.size(); + if (fieldCount > 4u) { error(line, "illegal vector field selection", compString.c_str()); return false; } + fieldOffsets->resize(fieldCount); enum { @@ -45,57 +263,57 @@ bool TParseContext::parseVectorFields(const TString &compString, estpq } fieldSet[4]; - for (int i = 0; i < fields.num; ++i) + for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) { switch (compString[i]) { case 'x': - fields.offsets[i] = 0; + (*fieldOffsets)[i] = 0; fieldSet[i] = exyzw; break; case 'r': - fields.offsets[i] = 0; + (*fieldOffsets)[i] = 0; fieldSet[i] = ergba; break; case 's': - fields.offsets[i] = 0; + (*fieldOffsets)[i] = 0; fieldSet[i] = estpq; break; case 'y': - fields.offsets[i] = 1; + (*fieldOffsets)[i] = 1; fieldSet[i] = exyzw; break; case 'g': - fields.offsets[i] = 1; + (*fieldOffsets)[i] = 1; fieldSet[i] = ergba; break; case 't': - fields.offsets[i] = 1; + (*fieldOffsets)[i] = 1; fieldSet[i] = estpq; break; case 'z': - fields.offsets[i] = 2; + (*fieldOffsets)[i] = 2; fieldSet[i] = exyzw; break; case 'b': - fields.offsets[i] = 2; + (*fieldOffsets)[i] = 2; fieldSet[i] = ergba; break; case 'p': - fields.offsets[i] = 2; + (*fieldOffsets)[i] = 2; fieldSet[i] = estpq; break; case 'w': - fields.offsets[i] = 3; + (*fieldOffsets)[i] = 3; fieldSet[i] = exyzw; break; case 'a': - fields.offsets[i] = 3; + (*fieldOffsets)[i] = 3; fieldSet[i] = ergba; break; case 'q': - fields.offsets[i] = 3; + (*fieldOffsets)[i] = 3; fieldSet[i] = estpq; break; default: @@ -104,9 +322,9 @@ bool TParseContext::parseVectorFields(const TString &compString, } } - for (int i = 0; i < fields.num; ++i) + for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) { - if (fields.offsets[i] >= vecSize) + if ((*fieldOffsets)[i] >= vecSize) { error(line, "vector field selection out of range", compString.c_str()); return false; @@ -132,52 +350,31 @@ bool TParseContext::parseVectorFields(const TString &compString, // //////////////////////////////////////////////////////////////////////// -// -// Track whether errors have occurred. -// -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) { - pp::SourceLocation srcLoc; - srcLoc.file = loc.first_file; - srcLoc.line = loc.first_line; - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo); + mDiagnostics->error(loc, reason, token); } -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) { - pp::SourceLocation srcLoc; - srcLoc.file = loc.first_file; - srcLoc.line = loc.first_line; - mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo); + mDiagnostics->warning(loc, reason, token); } void TParseContext::outOfRangeError(bool isError, const TSourceLoc &loc, const char *reason, - const char *token, - const char *extraInfo) + const char *token) { if (isError) { - error(loc, reason, token, extraInfo); - recover(); + error(loc, reason, token); } else { - warning(loc, reason, token, extraInfo); + warning(loc, reason, token); } } @@ -186,10 +383,10 @@ void TParseContext::outOfRangeError(bool isError, // void TParseContext::assignError(const TSourceLoc &line, const char *op, TString left, TString right) { - std::stringstream extraInfoStream; - extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'"; - std::string extraInfo = extraInfoStream.str(); - error(line, "", op, extraInfo.c_str()); + std::stringstream reasonStream; + reasonStream << "cannot convert from '" << right << "' to '" << left << "'"; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), op); } // @@ -197,11 +394,12 @@ void TParseContext::assignError(const TSourceLoc &line, const char *op, TString // 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)"; - std::string extraInfo = extraInfoStream.str(); - error(line, " wrong operand type", op, extraInfo.c_str()); + std::stringstream reasonStream; + reasonStream << "wrong operand type - no operation '" << op + << "' exists that takes an operand of type " << operand + << " (or there is no acceptable conversion)"; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), op); } // @@ -212,102 +410,85 @@ void TParseContext::binaryOpError(const TSourceLoc &line, 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)"; - std::string extraInfo = extraInfoStream.str(); - error(line, " wrong operand types ", op, extraInfo.c_str()); + std::stringstream reasonStream; + reasonStream << "wrong operand types - 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 reason = reasonStream.str(); + error(line, reason.c_str(), op); } -bool TParseContext::precisionErrorCheck(const TSourceLoc &line, - TPrecision precision, - TBasicType type) +void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, + TPrecision precision, + TBasicType type) { if (!mChecksPrecisionErrors) - return false; + return; + + if (precision != EbpUndefined && !SupportsPrecision(type)) + { + error(line, "illegal type for precision qualifier", getBasicString(type)); + } + if (precision == EbpUndefined) { switch (type) { case EbtFloat: error(line, "No precision specified for (float)", ""); - return true; + return; case EbtInt: case EbtUInt: UNREACHABLE(); // there's always a predeclared qualifier error(line, "No precision specified (int)", ""); - return true; + return; default: - if (IsSampler(type)) + if (IsOpaqueType(type)) { - error(line, "No precision specified (sampler)", ""); - return true; + error(line, "No precision specified", getBasicString(type)); + return; } } } - return false; } -// // Both test and if necessary, spit out an error, to see if the node is really // an l-value that can be operated on this way. -// -// Returns true if the was an error. -// -bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped *node) +bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node) { - TIntermSymbol *symNode = node->getAsSymbolNode(); - TIntermBinary *binaryNode = node->getAsBinaryNode(); + TIntermSymbol *symNode = node->getAsSymbolNode(); + TIntermBinary *binaryNode = node->getAsBinaryNode(); + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); - if (binaryNode) + if (swizzleNode) { - bool errorReturn; + bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand()); + if (ok && swizzleNode->hasDuplicateOffsets()) + { + error(line, " l-value of swizzle cannot have duplicate components", op); + return false; + } + return ok; + } + if (binaryNode) + { 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; + return checkCanBeLValue(line, op, binaryNode->getLeft()); default: break; } error(line, " l-value required", op); - - return true; + return false; } - const char *symbol = 0; - if (symNode != 0) - symbol = symNode->getSymbol().c_str(); - - const char *message = 0; + std::string message; switch (node->getQualifier()) { case EvqConst: @@ -320,9 +501,11 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn message = "can't modify an attribute"; break; case EvqFragmentIn: - message = "can't modify an input"; - break; case EvqVertexIn: + case EvqGeometryIn: + case EvqFlatIn: + case EvqSmoothIn: + case EvqCentroidIn: message = "can't modify an input"; break; case EvqUniform: @@ -340,6 +523,51 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + case EvqNumWorkGroups: + message = "can't modify gl_NumWorkGroups"; + break; + case EvqWorkGroupSize: + message = "can't modify gl_WorkGroupSize"; + break; + case EvqWorkGroupID: + message = "can't modify gl_WorkGroupID"; + break; + case EvqLocalInvocationID: + message = "can't modify gl_LocalInvocationID"; + break; + case EvqGlobalInvocationID: + message = "can't modify gl_GlobalInvocationID"; + break; + case EvqLocalInvocationIndex: + message = "can't modify gl_LocalInvocationIndex"; + break; + case EvqViewIDOVR: + message = "can't modify gl_ViewID_OVR"; + break; + case EvqComputeIn: + message = "can't modify work group size variable"; + break; + case EvqPerVertexIn: + message = "can't modify any member in gl_in"; + break; + case EvqPrimitiveIDIn: + message = "can't modify gl_PrimitiveIDIn"; + break; + case EvqInvocationID: + message = "can't modify gl_InvocationID"; + break; + case EvqPrimitiveID: + if (mShaderType == GL_FRAGMENT_SHADER) + { + message = "can't modify gl_PrimitiveID in a fragment shader"; + } + break; + case EvqLayer: + if (mShaderType == GL_FRAGMENT_SHADER) + { + message = "can't modify gl_Layer in a fragment shader"; + } + break; default: // // Type that can't be written to? @@ -348,287 +576,270 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn { message = "can't modify void"; } - if (IsSampler(node->getBasicType())) + if (IsOpaqueType(node->getBasicType())) { - message = "can't modify a sampler"; + message = "can't modify a variable with type "; + message += getBasicString(node->getBasicType()); + } + else if (node->getMemoryQualifier().readonly) + { + message = "can't modify a readonly variable"; } } - if (message == 0 && binaryNode == 0 && symNode == 0) + if (message.empty() && binaryNode == 0 && symNode == 0) { - error(line, " l-value required", op); + error(line, "l-value required", op); - return true; + return false; } // // Everything else is okay, no error. // - if (message == 0) - return false; + if (message.empty()) + return true; // // If we get here, we have an error and a message. // if (symNode) { - std::stringstream extraInfoStream; - extraInfoStream << "\"" << symbol << "\" (" << message << ")"; - std::string extraInfo = extraInfoStream.str(); - error(line, " l-value required", op, extraInfo.c_str()); + const char *symbol = symNode->getSymbol().c_str(); + std::stringstream reasonStream; + reasonStream << "l-value required (" << message << " \"" << symbol << "\")"; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), op); } else { - std::stringstream extraInfoStream; - extraInfoStream << "(" << message << ")"; - std::string extraInfo = extraInfoStream.str(); - error(line, " l-value required", op, extraInfo.c_str()); + std::stringstream reasonStream; + reasonStream << "l-value required (" << message << ")"; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), op); } - return true; + return false; } -// // Both test, and if necessary spit out an error, to see if the node is really // a constant. -// -// Returns true if the was an error. -// -bool TParseContext::constErrorCheck(TIntermTyped *node) +void TParseContext::checkIsConst(TIntermTyped *node) { - if (node->getQualifier() == EvqConst) - return false; - - error(node->getLine(), "constant expression required", ""); - - return true; + if (node->getQualifier() != EvqConst) + { + error(node->getLine(), "constant expression required", ""); + } } -// // Both test, and if necessary spit out an error, to see if the node is really // an integer. -// -// Returns true if the was an error. -// -bool TParseContext::integerErrorCheck(TIntermTyped *node, const char *token) +void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token) { - if (node->isScalarInt()) - return false; - - error(node->getLine(), "integer expression required", token); - - return true; + if (!node->isScalarInt()) + { + error(node->getLine(), "integer expression required", token); + } } -// // Both test, and if necessary spit out an error, to see if we are currently // globally scoped. -// -// Returns true if the was an error. -// -bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char *token) +bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token) { - if (global) + if (!symbolTable.atGlobalLevel()) + { + error(line, "only allowed at global scope", token); return false; - - error(line, "only allowed at global scope", token); - + } return true; } -// -// For now, keep it simple: if it starts "gl_", it's reserved, independent -// of scope. Except, if the symbol table is at the built-in push-level, -// which is when we are parsing built-ins. -// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a -// webgl shader. -// -// Returns true if there was an error. -// -bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &identifier) +// ESSL 3.00.5 sections 3.8 and 3.9. +// If it starts "gl_" or contains two consecutive underscores, it's reserved. +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a webgl shader. +bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &identifier) { static const char *reservedErrMsg = "reserved built-in name"; - if (!symbolTable.atBuiltInLevel()) + if (identifier.compare(0, 3, "gl_") == 0) { - if (identifier.compare(0, 3, "gl_") == 0) - { - error(line, reservedErrMsg, "gl_"); - return true; - } - if (IsWebGLBasedSpec(mShaderSpec)) + error(line, reservedErrMsg, "gl_"); + return false; + } + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + if (identifier.compare(0, 6, "webgl_") == 0) { - if (identifier.compare(0, 6, "webgl_") == 0) - { - error(line, reservedErrMsg, "webgl_"); - return true; - } - if (identifier.compare(0, 7, "_webgl_") == 0) - { - error(line, reservedErrMsg, "_webgl_"); - return true; - } - if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) - { - error(line, reservedErrMsg, "css_"); - return true; - } + error(line, reservedErrMsg, "webgl_"); + return false; } - if (identifier.find("__") != TString::npos) + if (identifier.compare(0, 7, "_webgl_") == 0) { - error(line, - "identifiers containing two consecutive underscores (__) are reserved as " - "possible future keywords", - identifier.c_str()); - return true; + error(line, reservedErrMsg, "_webgl_"); + return false; } } - - return false; -} - -// -// Make sure there is enough data provided to the constructor to build -// something of the type of the constructor. Also returns the type of -// the constructor. -// -// Returns true if there was an error in construction. -// -bool TParseContext::constructorErrorCheck(const TSourceLoc &line, - TIntermNode *argumentsNode, - TFunction &function, - TOperator op, - TType *type) -{ - *type = function.getReturnType(); - - bool constructingMatrix = false; - switch (op) + if (identifier.find("__") != TString::npos) { - case EOpConstructMat2: - case EOpConstructMat2x3: - case EOpConstructMat2x4: - case EOpConstructMat3x2: - case EOpConstructMat3: - case EOpConstructMat3x4: - case EOpConstructMat4x2: - case EOpConstructMat4x3: - case EOpConstructMat4: - constructingMatrix = true; - break; - default: - break; + error(line, + "identifiers containing two consecutive underscores (__) are reserved as " + "possible future keywords", + identifier.c_str()); + return false; } + return true; +} - // - // Note: It's okay to have too many components available, but not okay to have unused - // arguments. 'full' will go to true when enough args have been seen. If we loop - // again, there is an extra argument, so 'overfull' will become true. - // - - 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) +// Make sure the argument types are correct for constructing a specific type. +bool TParseContext::checkConstructorArguments(const TSourceLoc &line, + const TIntermSequence *arguments, + const TType &type) +{ + if (arguments->empty()) { - const TConstParameter ¶m = function.getParam(i); - size += param.type->getObjectSize(); - - if (constructingMatrix && param.type->isMatrix()) - matrixInMatrix = true; - if (full) - overFull = true; - if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) - full = true; - if (param.type->getQualifier() != EvqConst) - constType = false; - if (param.type->isArray()) - arrayArg = true; + error(line, "constructor does not have any arguments", "constructor"); + return false; } - if (constType) - type->setQualifier(EvqConst); - - if (type->isArray()) + for (TIntermNode *arg : *arguments) { - if (type->isUnsizedArray()) + const TIntermTyped *argTyped = arg->getAsTyped(); + ASSERT(argTyped != nullptr); + if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType())) { - type->setArraySize(static_cast(function.getParamCount())); + std::string reason("cannot convert a variable with type "); + reason += getBasicString(argTyped->getBasicType()); + error(line, reason.c_str(), "constructor"); + return false; } - else if (static_cast(type->getArraySize()) != function.getParamCount()) + else if (argTyped->getMemoryQualifier().writeonly) { - error(line, "array constructor needs one argument per array element", "constructor"); - return true; + error(line, "cannot convert a variable with writeonly", "constructor"); + return false; } - } - - if (arrayArg && op != EOpConstructStruct) - { - error(line, "constructing from a non-dereferenced array", "constructor"); - return true; - } - - if (matrixInMatrix && !type->isArray()) - { - if (function.getParamCount() != 1) + if (argTyped->getBasicType() == EbtVoid) { - error(line, "constructing matrix from matrix can only take one argument", - "constructor"); - return true; + error(line, "cannot convert a void", "constructor"); + return false; } } - if (overFull) + if (type.isArray()) { - 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"); - return true; + // The size of an unsized constructor should already have been determined. + ASSERT(!type.isUnsizedArray()); + if (static_cast(type.getOutermostArraySize()) != arguments->size()) + { + error(line, "array constructor needs one argument per array element", "constructor"); + return false; + } + // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of + // the array. + for (TIntermNode *const &argNode : *arguments) + { + const TType &argType = argNode->getAsTyped()->getType(); + if (mShaderVersion < 310 && argType.isArray()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + if (!argType.isElementTypeOf(type)) + { + error(line, "Array constructor argument has an incorrect type", "constructor"); + return false; + } + } } - - if (!type->isMatrix() || !matrixInMatrix) + else if (type.getBasicType() == EbtStruct) { - if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || - (op == EOpConstructStruct && size < type->getObjectSize())) + const TFieldList &fields = type.getStruct()->fields(); + if (fields.size() != arguments->size()) { - error(line, "not enough data provided for construction", "constructor"); - return true; + error(line, + "Number of constructor parameters does not match the number of structure fields", + "constructor"); + return false; } - } - if (argumentsNode == nullptr) - { - error(line, "constructor does not have any arguments", "constructor"); - return true; + for (size_t i = 0; i < fields.size(); i++) + { + if (i >= arguments->size() || + (*arguments)[i]->getAsTyped()->getType() != *fields[i]->type()) + { + error(line, "Structure constructor arguments do not match structure fields", + "constructor"); + return false; + } + } } - - TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate(); - for (TIntermNode *&argNode : *argumentsAgg->getSequence()) + else { - TIntermTyped *argTyped = argNode->getAsTyped(); - ASSERT(argTyped != nullptr); - if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType())) + // We're constructing a scalar, vector, or matrix. + + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop again, + // there is an extra argument, so 'overFull' will become true. + + size_t size = 0; + bool full = false; + bool overFull = false; + bool matrixArg = false; + for (TIntermNode *arg : *arguments) { - error(line, "cannot convert a sampler", "constructor"); - return true; + const TIntermTyped *argTyped = arg->getAsTyped(); + ASSERT(argTyped != nullptr); + + if (argTyped->getBasicType() == EbtStruct) + { + error(line, "a struct cannot be used as a constructor argument for this type", + "constructor"); + return false; + } + if (argTyped->getType().isArray()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + if (argTyped->getType().isMatrix()) + { + matrixArg = true; + } + + size += argTyped->getType().getObjectSize(); + if (full) + { + overFull = true; + } + if (size >= type.getObjectSize()) + { + full = true; + } } - if (argTyped->getBasicType() == EbtVoid) + + if (type.isMatrix() && matrixArg) { - error(line, "cannot convert a void", "constructor"); - return true; + if (arguments->size() != 1) + { + error(line, "constructing matrix from matrix can only take one argument", + "constructor"); + return false; + } + } + else + { + if (size != 1 && size < type.getObjectSize()) + { + error(line, "not enough data provided for construction", "constructor"); + return false; + } + if (overFull) + { + error(line, "too many arguments", "constructor"); + return false; + } } } - return false; + return true; } // This function checks to see if a void variable has been declared and raise an error message for @@ -636,126 +847,116 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, // // returns true in case of an error // -bool TParseContext::voidErrorCheck(const TSourceLoc &line, +bool TParseContext::checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type) { if (type == EbtVoid) { error(line, "illegal use of type 'void'", identifier.c_str()); - return true; + return false; } - return false; + return true; } // 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) +// or not. +bool TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type) { - if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) + if (type->getBasicType() != EbtBool || !type->isScalar()) { error(line, "boolean expression expected", ""); - return true; + return false; } - - return false; + return true; } // 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) +// or not. +void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType) { - if (pType.type != EbtBool || pType.isAggregate()) + if (pType.getBasicType() != EbtBool || pType.isAggregate()) { error(line, "boolean expression expected", ""); - return true; } - - return false; } -bool TParseContext::samplerErrorCheck(const TSourceLoc &line, - const TPublicType &pType, - const char *reason) +bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, + const char *reason) { if (pType.type == EbtStruct) { - if (containsSampler(*pType.userDef)) + if (ContainsSampler(pType.userDef)) { - error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); - - return true; + std::stringstream reasonStream; + reasonStream << reason << " (structure contains a sampler)"; + std::string reasonStr = reasonStream.str(); + error(line, reasonStr.c_str(), getBasicString(pType.type)); + return false; } - - return false; + // only samplers need to be checked from structs, since other opaque types can't be struct + // members. + return true; } - else if (IsSampler(pType.type)) + else if (IsOpaqueType(pType.type)) { error(line, reason, getBasicString(pType.type)); - - return true; + return false; } - return false; + return true; } -bool TParseContext::locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType) +void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, + const TPublicType &pType) { if (pType.layoutQualifier.location != -1) { error(line, "location must only be specified for a single input or output variable", "location"); - return true; } - - return false; } -bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line, - TQualifier qualifier, - const TType &type) +void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) { - if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct && - IsSampler(type.getBasicType())) + if (layoutQualifier.location != -1) { - error(line, "samplers cannot be output parameters", type.getBasicString()); - return true; + const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs"; + if (mShaderVersion >= 310) + { + errorMsg = + "invalid layout qualifier: only valid on shader inputs, outputs, and uniforms"; + } + error(location, errorMsg, "location"); } - - return false; } -bool TParseContext::containsSampler(const TType &type) +void TParseContext::checkStd430IsForShaderStorageBlock(const TSourceLoc &location, + const TLayoutBlockStorage &blockStorage, + const TQualifier &qualifier) { - if (IsSampler(type.getBasicType())) - return true; - - if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) + if (blockStorage == EbsStd430 && qualifier != EvqBuffer) { - const TFieldList &fields = type.getStruct()->fields(); - for (unsigned int i = 0; i < fields.size(); ++i) - { - if (containsSampler(*fields[i]->type())) - return true; - } + error(location, "The std430 layout is supported only for shader storage blocks.", "std430"); } +} - return false; +void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line, + TQualifier qualifier, + const TType &type) +{ + ASSERT(qualifier == EvqOut || qualifier == EvqInOut); + if (IsOpaqueType(type.getBasicType())) + { + error(line, "opaque types cannot be output parameters", type.getBasicString()); + } } -// // Do size checking for an array type's size. -// -// Returns true if there was an error. -// -bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size) +unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr) { TIntermConstantUnion *constant = expr->getAsConstantUnion(); @@ -765,36 +966,32 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *ex if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt()) { error(line, "array size must be a constant integer expression", ""); - size = 1; - return true; + return 1u; } - unsigned int unsignedSize = 0; + unsigned int size = 0u; if (constant->getBasicType() == EbtUInt) { - unsignedSize = constant->getUConst(0); - size = static_cast(unsignedSize); + size = constant->getUConst(0); } else { - size = constant->getIConst(0); + int signedSize = constant->getIConst(0); - if (size < 0) + if (signedSize < 0) { error(line, "array size must be non-negative", ""); - size = 1; - return true; + return 1u; } - unsignedSize = static_cast(size); + size = static_cast(signedSize); } - if (size == 0) + if (size == 0u) { error(line, "array size must be greater than zero", ""); - size = 1; - return true; + return 1u; } // The size of arrays is restricted here to prevent issues further down the @@ -802,76 +999,80 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *ex // 4096 registers so this should be reasonable even for aggressively optimizable code. const unsigned int sizeLimit = 65536; - if (unsignedSize > sizeLimit) + if (size > sizeLimit) { error(line, "array size too large", ""); - size = 1; - return true; + return 1u; } - return false; + return size; } -// // See if this qualifier can be an array. -// -// Returns true if there is an error. -// -bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type) +bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line, + const TPublicType &elementQualifier) { - if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || - (type.qualifier == EvqConst && mShaderVersion < 300)) + if ((elementQualifier.qualifier == EvqAttribute) || + (elementQualifier.qualifier == EvqVertexIn) || + (elementQualifier.qualifier == EvqConst && mShaderVersion < 300)) { error(line, "cannot declare arrays of this qualifier", - TType(type).getCompleteString().c_str()); - return true; + TType(elementQualifier).getQualifierString()); + return false; } - return false; + return true; } -// -// See if this type can be an array. -// -// Returns true if there is an error. -// -bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type) +// See if this element type can be formed into an array. +bool TParseContext::checkArrayElementIsNotArray(const TSourceLoc &line, + const TPublicType &elementType) { - // - // Can the type be an array? - // - if (type.array) + if (mShaderVersion < 310 && elementType.isArray()) { - error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); - return true; + error(line, "cannot declare arrays of arrays", + TType(elementType).getCompleteString().c_str()); + return false; + } + return true; +} + +// Check if this qualified element type can be formed into an array. This is only called when array +// brackets are associated with an identifier in a declaration, like this: +// float a[2]; +// Similar checks are done in addFullySpecifiedType for array declarations where the array brackets +// are associated with the type, like this: +// float[2] a; +bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType) +{ + if (!checkArrayElementIsNotArray(indexLocation, elementType)) + { + return false; } // 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)) + if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && + sh::IsVarying(elementType.qualifier)) { - error(line, "cannot declare arrays of structs of this qualifier", - TType(type).getCompleteString().c_str()); - return true; + error(indexLocation, "cannot declare arrays of structs of this qualifier", + TType(elementType).getCompleteString().c_str()); + return false; } - - return false; + return checkIsValidQualifierForArray(indexLocation, elementType); } -// // Enforce non-initializer type/qualifier rules. -// -// Returns true if there was an error. -// -bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, - const TString &identifier, - TPublicType *type) +void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const TString &identifier, + TType *type) { ASSERT(type != nullptr); - if (type->qualifier == EvqConst) + if (type->getQualifier() == EvqConst) { // Make the qualifier make sense. - type->qualifier = EvqTemporary; + type->setQualifier(EvqTemporary); // Generate informative error messages for ESSL1. // In ESSL3 arrays and structures containing arrays can be constant. @@ -886,15 +1087,10 @@ bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, { error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); } - - return true; - } - if (type->isUnsizedArray()) - { - error(line, "implicitly sized arrays need to be initialized", identifier.c_str()); - return true; } - return false; + // This will make the type sized if it isn't sized yet. + checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized", + identifier.c_str(), type); } // Do some simple checks that are shared between all variable declarations, @@ -909,18 +1105,27 @@ bool TParseContext::declareVariable(const TSourceLoc &line, { ASSERT((*variable) == nullptr); - bool needsReservedErrorCheck = true; + checkBindingIsValid(line, type); + + bool needsReservedCheck = 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 (type.isArrayOfArrays()) + { + error(line, "redeclaration of gl_LastFragData as an array of arrays", + identifier.c_str()); + return false; + } + else if (static_cast(type.getOutermostArraySize()) == + maxDrawBuffers->getConstPointer()->getIConst()) { if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) { - needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension()); + needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->getExtension()); } } else @@ -931,184 +1136,602 @@ bool TParseContext::declareVariable(const TSourceLoc &line, } } - if (needsReservedErrorCheck && reservedErrorCheck(line, identifier)) + if (needsReservedCheck && !checkIsNotReserved(line, identifier)) return false; - (*variable) = new TVariable(&identifier, type); - if (!symbolTable.declare(*variable)) + (*variable) = symbolTable.declareVariable(&identifier, type); + if (!(*variable)) { error(line, "redefinition", identifier.c_str()); - *variable = nullptr; return false; } - if (voidErrorCheck(line, identifier, type.getBasicType())) + if (!checkIsNonVoid(line, identifier, type.getBasicType())) return false; return true; } -bool TParseContext::paramErrorCheck(const TSourceLoc &line, - TQualifier qualifier, - TQualifier paramQualifier, - TType *type) +void TParseContext::checkIsParameterQualifierValid( + const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type) { - if (qualifier != EvqConst && qualifier != EvqTemporary) + // The only parameter qualifiers a parameter can have are in, out, inout or const. + TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics); + + if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut) { - error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); - return true; + checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type); } - if (qualifier == EvqConst && paramQualifier != EvqIn) + + if (!IsImage(type->getBasicType())) { - error(line, "qualifier not allowed with ", getQualifierString(qualifier), - getQualifierString(paramQualifier)); - return true; + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line); } - - if (qualifier == EvqConst) - type->setQualifier(EvqConstReadOnly); else - type->setQualifier(paramQualifier); + { + type->setMemoryQualifier(typeQualifier.memoryQualifier); + } - return false; + type->setQualifier(typeQualifier.qualifier); + + if (typeQualifier.precision != EbpUndefined) + { + type->setPrecision(typeQualifier.precision); + } } -bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString &extension) +template +bool TParseContext::checkCanUseOneOfExtensions(const TSourceLoc &line, + const std::array &extensions) { - const TExtensionBehavior &extBehavior = extensionBehavior(); - TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); - if (iter == extBehavior.end()) + ASSERT(!extensions.empty()); + const TExtensionBehavior &extBehavior = extensionBehavior(); + + bool canUseWithWarning = false; + bool canUseWithoutWarning = false; + + const char *errorMsgString = ""; + TExtension errorMsgExtension = TExtension::UNDEFINED; + + for (TExtension extension : extensions) { - error(line, "extension", extension.c_str(), "is not supported"); - return true; + auto extIter = extBehavior.find(extension); + if (canUseWithWarning) + { + // We already have an extension that we can use, but with a warning. + // See if we can use the alternative extension without a warning. + if (extIter == extBehavior.end()) + { + continue; + } + if (extIter->second == EBhEnable || extIter->second == EBhRequire) + { + canUseWithoutWarning = true; + break; + } + continue; + } + if (extIter == extBehavior.end()) + { + errorMsgString = "extension is not supported"; + errorMsgExtension = extension; + } + else if (extIter->second == EBhUndefined || extIter->second == EBhDisable) + { + errorMsgString = "extension is disabled"; + errorMsgExtension = extension; + } + else if (extIter->second == EBhWarn) + { + errorMsgExtension = extension; + canUseWithWarning = true; + } + else + { + ASSERT(extIter->second == EBhEnable || extIter->second == EBhRequire); + canUseWithoutWarning = true; + break; + } } - // In GLSL ES, an extension's default behavior is "disable". - if (iter->second == EBhDisable || iter->second == EBhUndefined) + + if (canUseWithoutWarning) { - error(line, "extension", extension.c_str(), "is disabled"); return true; } - if (iter->second == EBhWarn) + if (canUseWithWarning) { - warning(line, "extension", extension.c_str(), "is being used"); - return false; + warning(line, "extension is being used", GetExtensionNameString(errorMsgExtension)); + return true; } - + error(line, errorMsgString, GetExtensionNameString(errorMsgExtension)); return false; } -// 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) +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array &extensions); +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array &extensions); +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array &extensions); + +bool TParseContext::checkCanUseExtension(const TSourceLoc &line, TExtension extension) { - switch (publicType.qualifier) + ASSERT(extension != TExtension::UNDEFINED); + ASSERT(extension != TExtension::EXT_geometry_shader); + if (extension == TExtension::OES_geometry_shader) { - 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; + // OES_geometry_shader and EXT_geometry_shader are always interchangeable. + constexpr std::array extensions{ + {TExtension::EXT_geometry_shader, TExtension::OES_geometry_shader}}; + return checkCanUseOneOfExtensions(line, extensions); } + return checkCanUseOneOfExtensions(line, std::array{{extension}}); +} - if (publicType.qualifier != EvqUniform && - samplerErrorCheck(identifierLocation, publicType, "samplers must be uniform")) +// ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause +// compile-time or link-time errors are the same whether or not the declaration is empty". +// This function implements all the checks that are done on qualifiers regardless of if the +// declaration is empty. +void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier, + const sh::TLayoutQualifier &layoutQualifier, + const TSourceLoc &location) +{ + if (qualifier == EvqShared && !layoutQualifier.isEmpty()) { - return true; + error(location, "Shared memory declarations cannot have layout specified", "layout"); } - // 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; + error(location, "layout qualifier only valid for interface blocks", + getMatrixPackingString(layoutQualifier.matrixPacking)); + return; } if (layoutQualifier.blockStorage != EbsUnspecified) { - error(identifierLocation, "layout qualifier", - getBlockStorageString(layoutQualifier.blockStorage), - "only valid for interface blocks"); - return true; + error(location, "layout qualifier only valid for interface blocks", + getBlockStorageString(layoutQualifier.blockStorage)); + return; } - if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && - layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier)) + if (qualifier == EvqFragmentOut) { - return true; + if (layoutQualifier.location != -1 && layoutQualifier.yuv == true) + { + error(location, "invalid layout qualifier combination", "yuv"); + return; + } + } + else + { + checkYuvIsNotSpecified(location, layoutQualifier.yuv); } - return false; -} - -bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, - const TLayoutQualifier &layoutQualifier) -{ - if (layoutQualifier.location != -1) + // If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous + // parsing steps. So it needs to be checked here. + if (isExtensionEnabled(TExtension::OVR_multiview) && mShaderVersion < 300 && + qualifier == EvqVertexIn) { - error(location, "invalid layout qualifier:", "location", - "only valid on program inputs and outputs"); - return true; + error(location, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); } - return false; + bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut; + if (mShaderVersion >= 310) + { + canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier); + // We're not checking whether the uniform location is in range here since that depends on + // the type of the variable. + // The type can only be fully determined for non-empty declarations. + } + if (!canHaveLocation) + { + checkLocationIsNotSpecified(location, layoutQualifier); + } } -bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, - TIntermAggregate *aggregate) +void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicType, + const TSourceLoc &location) { - for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) + if (publicType.precision != EbpHigh) { - TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); - if (qual == EvqOut || qual == EvqInOut) - { - TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped(); - if (lValueErrorCheck(node->getLine(), "assign", node)) + error(location, "Can only be highp", "atomic counter"); + } + // dEQP enforces compile error if location is specified. See uniform_location.test. + if (publicType.layoutQualifier.location != -1) + { + error(location, "location must not be set for atomic_uint", "layout"); + } + if (publicType.layoutQualifier.binding == -1) + { + error(location, "no binding specified", "atomic counter"); + } +} + +void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location) +{ + if (type.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(location, "empty array declaration needs to specify a size", ""); + } +} + +// These checks are done for all declarations that are non-empty. They're done for non-empty +// declarations starting a declarator list, and declarators that follow an empty declaration. +void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, + const TSourceLoc &identifierLocation) +{ + switch (publicType.qualifier) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqAttribute: + case EvqVertexIn: + case EvqFragmentOut: + case EvqComputeIn: + if (publicType.getBasicType() == EbtStruct) { - error(node->getLine(), - "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); - recover(); - return true; + error(identifierLocation, "cannot be used with a structure", + getQualifierString(publicType.qualifier)); + return; } + break; + case EvqBuffer: + if (publicType.getBasicType() != EbtInterfaceBlock) + { + error(identifierLocation, + "cannot declare buffer variables at global scope(outside a block)", + getQualifierString(publicType.qualifier)); + return; + } + break; + default: + break; + } + std::string reason(getBasicString(publicType.getBasicType())); + reason += "s must be uniform"; + if (publicType.qualifier != EvqUniform && + !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str())) + { + return; + } + + if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal && + publicType.qualifier != EvqConst) && + publicType.getBasicType() == EbtYuvCscStandardEXT) + { + error(identifierLocation, "cannot be used with a yuvCscStandardEXT", + getQualifierString(publicType.qualifier)); + return; + } + + if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform) + { + // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized. + // But invalid shaders may still reach here with an unsized array declaration. + TType type(publicType); + if (!type.isUnsizedArray()) + { + checkUniformLocationInRange(identifierLocation, type.getLocationCount(), + publicType.layoutQualifier); } } - return false; + + // check for layout qualifier issues + const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; + + if (IsImage(publicType.getBasicType())) + { + + switch (layoutQualifier.imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + case EiifRGBA8: + case EiifRGBA8_SNORM: + if (!IsFloatImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires a floating image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + if (!IsIntegerImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires an integer image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + if (!IsUnsignedImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires an unsigned image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifUnspecified: + error(identifierLocation, "layout qualifier", "No image internal format specified"); + return; + default: + error(identifierLocation, "layout qualifier", "unrecognized token"); + return; + } + + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + switch (layoutQualifier.imageInternalFormat) + { + case EiifR32F: + case EiifR32I: + case EiifR32UI: + break; + default: + if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly) + { + error(identifierLocation, "layout qualifier", + "Except for images with the r32f, r32i and r32ui format qualifiers, " + "image variables must be qualified readonly and/or writeonly"); + return; + } + break; + } + } + else + { + checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat); + checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation); + } + + if (IsAtomicCounter(publicType.getBasicType())) + { + atomicCounterQualifierErrorCheck(publicType, identifierLocation); + } + else + { + checkOffsetIsNotSpecified(identifierLocation, layoutQualifier.offset); + } +} + +void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type) +{ + TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); + // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier + // on arrays of arrays should be handled. We interpret the spec so that the binding value is + // incremented for each element of the innermost nested arrays. This is in line with how arrays + // of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation + // when it comes to which shaders are accepted by the compiler. + int arrayTotalElementCount = type.getArraySizeProduct(); + if (IsImage(type.getBasicType())) + { + checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, + arrayTotalElementCount); + } + else if (IsSampler(type.getBasicType())) + { + checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, + arrayTotalElementCount); + } + else if (IsAtomicCounter(type.getBasicType())) + { + checkAtomicCounterBindingIsValid(identifierLocation, layoutQualifier.binding); + } + else + { + ASSERT(!IsOpaqueType(type.getBasicType())); + checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding); + } +} + +void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, + const TString &layoutQualifierName, + int versionRequired) +{ + + if (mShaderVersion < versionRequired) + { + error(location, "invalid layout qualifier: not supported", layoutQualifierName.c_str()); + } +} + +bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) +{ + const sh::WorkGroupSize &localSize = layoutQualifier.localSize; + for (size_t i = 0u; i < localSize.size(); ++i) + { + if (localSize[i] != -1) + { + error(location, + "invalid layout qualifier: only valid when used with 'in' in a compute shader " + "global layout declaration", + getWorkGroupSizeString(i)); + return false; + } + } + + return true; +} + +void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location, + TLayoutImageInternalFormat internalFormat) +{ + if (internalFormat != EiifUnspecified) + { + error(location, "invalid layout qualifier: only valid when used with images", + getImageInternalFormatString(internalFormat)); + } +} + +void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding) +{ + if (binding != -1) + { + error(location, + "invalid layout qualifier: only valid when used with opaque types or blocks", + "binding"); + } +} + +void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int offset) +{ + if (offset != -1) + { + error(location, "invalid layout qualifier: only valid when used with atomic counters", + "offset"); + } +} + +void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount) +{ + // Expects arraySize to be 1 when setting binding for only a single variable. + if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits) + { + error(location, "image binding greater than gl_MaxImageUnits", "binding"); + } } -void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier, - const TSourceLoc &invariantLocation) +void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount) { - if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut) + // Expects arraySize to be 1 when setting binding for only a single variable. + if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits) { - error(invariantLocation, "Only out variables can be invariant.", "invariant"); - recover(); + error(location, "sampler binding greater than maximum texture units", "binding"); } } -bool TParseContext::supportsExtension(const char *extension) +void TParseContext::checkBlockBindingIsValid(const TSourceLoc &location, + const TQualifier &qualifier, + int binding, + int arraySize) { - const TExtensionBehavior &extbehavior = extensionBehavior(); - TExtensionBehavior::const_iterator iter = extbehavior.find(extension); - return (iter != extbehavior.end()); + int size = (arraySize == 0 ? 1 : arraySize); + if (qualifier == EvqUniform) + { + if (binding + size > mMaxUniformBufferBindings) + { + error(location, "uniform block binding greater than MAX_UNIFORM_BUFFER_BINDINGS", + "binding"); + } + } + else if (qualifier == EvqBuffer) + { + if (binding + size > mMaxShaderStorageBufferBindings) + { + error(location, + "shader storage block binding greater than MAX_SHADER_STORAGE_BUFFER_BINDINGS", + "binding"); + } + } +} +void TParseContext::checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding) +{ + if (binding >= mMaxAtomicCounterBindings) + { + error(location, "atomic counter binding greater than gl_MaxAtomicCounterBindings", + "binding"); + } +} + +void TParseContext::checkUniformLocationInRange(const TSourceLoc &location, + int objectLocationCount, + const TLayoutQualifier &layoutQualifier) +{ + int loc = layoutQualifier.location; + if (loc >= 0 && loc + objectLocationCount > mMaxUniformLocations) + { + error(location, "Uniform location out of range", "location"); + } +} + +void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv) +{ + if (yuv != false) + { + error(location, "invalid layout qualifier: only valid on program outputs", "yuv"); + } +} + +void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, + TIntermAggregate *fnCall) +{ + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) + { + TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); + TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped(); + if (!IsImage(argument->getBasicType()) && (IsQualifierUnspecified(qual) || qual == EvqIn || + qual == EvqInOut || qual == EvqConstReadOnly)) + { + if (argument->getMemoryQualifier().writeonly) + { + error(argument->getLine(), + "Writeonly value cannot be passed for 'in' or 'inout' parameters.", + fnCall->getFunctionSymbolInfo()->getName().c_str()); + return; + } + } + if (qual == EvqOut || qual == EvqInOut) + { + if (!checkCanBeLValue(argument->getLine(), "assign", argument)) + { + error(argument->getLine(), + "Constant value cannot be passed for 'out' or 'inout' parameters.", + fnCall->getFunctionSymbolInfo()->getName().c_str()); + return; + } + } + } +} + +void TParseContext::checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation) +{ + if (!invariant) + return; + + if (mShaderVersion < 300) + { + // input variables in the fragment shader can be also qualified as invariant + if (!sh::CanBeInvariantESSL1(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } + } + else + { + if (!sh::CanBeInvariantESSL3OrGreater(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } + } } -bool TParseContext::isExtensionEnabled(const char *extension) const +bool TParseContext::isExtensionEnabled(TExtension extension) const { - return ::IsExtensionEnabled(extensionBehavior(), extension); + return IsExtensionEnabled(extensionBehavior(), extension); } void TParseContext::handleExtensionDirective(const TSourceLoc &loc, @@ -1132,6 +1755,32 @@ void TParseContext::handlePragmaDirective(const TSourceLoc &loc, mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl); } +sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const +{ + sh::WorkGroupSize result(-1); + for (size_t i = 0u; i < result.size(); ++i) + { + if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1) + { + result[i] = 1; + } + else + { + result[i] = mComputeShaderLocalSize[i]; + } + } + return result; +} + +TIntermConstantUnion *TParseContext::addScalarLiteral(const TConstantUnion *constantUnion, + const TSourceLoc &line) +{ + TIntermConstantUnion *node = new TIntermConstantUnion( + constantUnion, TType(constantUnion->getType(), EbpUndefined, EvqConst)); + node->setLine(line); + return node; +} + ///////////////////////////////////////////////////////////////////////////////// // // Non-Errors. @@ -1142,70 +1791,64 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol) { - const TVariable *variable = NULL; - if (!symbol) { error(location, "undeclared identifier", name->c_str()); - recover(); + return nullptr; } - else if (!symbol->isVariable()) + + if (!symbol->isVariable()) { error(location, "variable expected", name->c_str()); - recover(); + return nullptr; } - else - { - variable = static_cast(symbol); - if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) && - !variable->getExtension().empty() && - extensionErrorCheck(location, variable->getExtension())) - { - recover(); - } + const TVariable *variable = static_cast(symbol); - // 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; - } + if (variable->getExtension() != TExtension::UNDEFINED) + { + checkCanUseExtension(location, variable->getExtension()); + } + + // 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) + // 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) { - 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(); + errorMessage = + "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)" + " and (gl_FragColor, gl_SecondaryFragColorEXT)"; } + error(location, errorMessage, name->c_str()); } - if (!variable) + // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables + if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared && + qualifier == EvqWorkGroupSize) { - TType type(EbtFloat, EbpUndefined); - TVariable *fakeVariable = new TVariable(name, type); - symbolTable.declare(fakeVariable); - variable = fakeVariable; + error(location, + "It is an error to use gl_WorkGroupSize before declaring the local group size", + "gl_WorkGroupSize"); } - return variable; } @@ -1215,75 +1858,82 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, { const TVariable *variable = getNamedVariable(location, name, symbol); + if (!variable) + { + TIntermTyped *node = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + node->setLine(location); + return node; + } + + const TType &variableType = variable->getType(); + TIntermTyped *node = nullptr; + if (variable->getConstPointer()) { const TConstantUnion *constArray = variable->getConstPointer(); - return intermediate.addConstantUnion(constArray, variable->getType(), location); + node = new TIntermConstantUnion(constArray, variableType); } - else + else if (variableType.getQualifier() == EvqWorkGroupSize && mComputeShaderLocalSizeDeclared) { - return intermediate.addSymbol(variable->getUniqueId(), variable->getName(), - variable->getType(), location); - } -} + // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it + // needs to be added to the AST as a constant and not as a symbol. + sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize(); + TConstantUnion *constArray = new TConstantUnion[3]; + for (size_t i = 0; i < 3; ++i) + { + constArray[i].setUConst(static_cast(workGroupSize[i])); + } -// -// 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) -{ - // 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()) - { - symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn); - } + ASSERT(variableType.getBasicType() == EbtUInt); + ASSERT(variableType.getObjectSize() == 3); - if (symbol == 0) - { - error(line, "no matching overloaded function found", call->getName().c_str()); - return 0; + TType type(variableType); + type.setQualifier(EvqConst); + node = new TIntermConstantUnion(constArray, type); } + else if ((mGeometryShaderInputPrimitiveType != EptUndefined) && + (variableType.getQualifier() == EvqPerVertexIn)) + { + ASSERT(mGeometryShaderInputArraySize > 0u); - if (!symbol->isFunction()) + node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variableType); + node->getTypePointer()->sizeOutermostUnsizedArray(mGeometryShaderInputArraySize); + } + else { - error(line, "function name expected", call->getName().c_str()); - return 0; + node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variableType); } - - return static_cast(symbol); + ASSERT(node != nullptr); + node->setLine(location); + return node; } -// // Initializers show up in several places in the grammar. Have one set of // code to handle them here. // -// Returns true on error, false if no error -// +// Returns true on success. bool TParseContext::executeInitializer(const TSourceLoc &line, const TString &identifier, - const TPublicType &pType, + TType type, TIntermTyped *initializer, - TIntermNode **intermNode) + TIntermBinary **initNode) { - ASSERT(intermNode != nullptr); - TType type = TType(pType); + ASSERT(initNode != nullptr); + ASSERT(*initNode == nullptr); TVariable *variable = nullptr; if (type.isUnsizedArray()) { - type.setArraySize(initializer->getArraySize()); + // In case initializer is not an array or type has more dimensions than initializer, this + // will default to setting array sizes to 1. We have not checked yet whether the initializer + // actually is an array or not. Having a non-array initializer for an unsized array will + // result in an error later, so we don't generate an error message here. + auto *arraySizes = initializer->getType().getArraySizes(); + type.sizeUnsizedArrays(arraySizes); } if (!declareVariable(line, identifier, type, &variable)) { - return true; + return false; } bool globalInitWarning = false; @@ -1293,7 +1943,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, // 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; + return false; } if (globalInitWarning) { @@ -1312,7 +1962,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, { error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString()); - return true; + return false; } // // test for and propagate constant @@ -1322,19 +1972,20 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, { if (qualifier != initializer->getType().getQualifier()) { - std::stringstream extraInfoStream; - extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; - std::string extraInfo = extraInfoStream.str(); - error(line, " assigning non-constant to", "=", extraInfo.c_str()); + std::stringstream reasonStream; + reasonStream << "assigning non-constant to '" << variable->getType().getCompleteString() + << "'"; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), "="); variable->getType().setQualifier(EvqTemporary); - return true; + return false; } if (type != initializer->getType()) { error(line, " non-matching types for const initializer ", variable->getType().getQualifierString()); variable->getType().setQualifier(EvqTemporary); - return true; + return false; } // Save the constant folded value to the variable if possible. For example array @@ -1345,8 +1996,8 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, if (initializer->getAsConstantUnion()) { variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); - *intermNode = nullptr; - return false; + ASSERT(*initNode == nullptr); + return true; } else if (initializer->getAsSymbolNode()) { @@ -1358,84 +2009,220 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, if (constArray) { variable->shareConstPointer(constArray); - *intermNode = nullptr; - return false; + ASSERT(*initNode == nullptr); + return true; } } } - TIntermSymbol *intermSymbol = intermediate.addSymbol( - variable->getUniqueId(), variable->getName(), variable->getType(), line); - *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line); - if (*intermNode == nullptr) + TIntermSymbol *intermSymbol = + new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType()); + intermSymbol->setLine(line); + *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line); + if (*initNode == nullptr) { assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); - return true; + return false; } - return false; + return true; } -TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, - bool invariant, - TLayoutQualifier layoutQualifier, +TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType, + const TString &identifier, + TIntermTyped *initializer, + const TSourceLoc &loc) +{ + checkIsScalarBool(loc, pType); + TIntermBinary *initNode = nullptr; + TType type(pType); + if (executeInitializer(loc, identifier, type, initializer, &initNode)) + { + // The initializer is valid. The init condition needs to have a node - either the + // initializer node, or a constant node in case the initialized variable is const and won't + // be recorded in the AST. + if (initNode == nullptr) + { + return initializer; + } + else + { + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(initNode); + return declaration; + } + } + return nullptr; +} + +TIntermNode *TParseContext::addLoop(TLoopType type, + TIntermNode *init, + TIntermNode *cond, + TIntermTyped *expr, + TIntermNode *body, + const TSourceLoc &line) +{ + TIntermNode *node = nullptr; + TIntermTyped *typedCond = nullptr; + if (cond) + { + typedCond = cond->getAsTyped(); + } + if (cond == nullptr || typedCond) + { + if (type == ELoopDoWhile) + { + checkIsScalarBool(line, typedCond); + } + // In the case of other loops, it was checked before that the condition is a scalar boolean. + ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr || + (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && + !typedCond->isVector())); + + node = new TIntermLoop(type, init, typedCond, expr, EnsureBlock(body)); + node->setLine(line); + return node; + } + + ASSERT(type != ELoopDoWhile); + + TIntermDeclaration *declaration = cond->getAsDeclarationNode(); + ASSERT(declaration); + TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode(); + ASSERT(declarator->getLeft()->getAsSymbolNode()); + + // The condition is a declaration. In the AST representation we don't support declarations as + // loop conditions. Wrap the loop to a block that declares the condition variable and contains + // the loop. + TIntermBlock *block = new TIntermBlock(); + + TIntermDeclaration *declareCondition = new TIntermDeclaration(); + declareCondition->appendDeclarator(declarator->getLeft()->deepCopy()); + block->appendStatement(declareCondition); + + TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(), + declarator->getRight()->deepCopy()); + TIntermLoop *loop = new TIntermLoop(type, init, conditionInit, expr, EnsureBlock(body)); + block->appendStatement(loop); + loop->setLine(line); + block->setLine(line); + return block; +} + +TIntermNode *TParseContext::addIfElse(TIntermTyped *cond, + TIntermNodePair code, + const TSourceLoc &loc) +{ + bool isScalarBool = checkIsScalarBool(loc, cond); + + // For compile time constant conditions, prune the code now. + if (isScalarBool && cond->getAsConstantUnion()) + { + if (cond->getAsConstantUnion()->getBConst(0) == true) + { + return EnsureBlock(code.node1); + } + else + { + return EnsureBlock(code.node2); + } + } + + TIntermIfElse *node = new TIntermIfElse(cond, EnsureBlock(code.node1), EnsureBlock(code.node2)); + node->setLine(loc); + + return node; +} + +void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier) +{ + checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision, + typeSpecifier->getBasicType()); + + if (mShaderVersion < 300 && typeSpecifier->isArray()) + { + error(typeSpecifier->getLine(), "not supported", "first-class array"); + typeSpecifier->clearArrayness(); + } +} + +TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, const TPublicType &typeSpecifier) { + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + TPublicType returnType = typeSpecifier; - returnType.qualifier = qualifier; - returnType.invariant = invariant; - returnType.layoutQualifier = layoutQualifier; + returnType.qualifier = typeQualifier.qualifier; + returnType.invariant = typeQualifier.invariant; + returnType.layoutQualifier = typeQualifier.layoutQualifier; + returnType.memoryQualifier = typeQualifier.memoryQualifier; + returnType.precision = typeSpecifier.precision; + + if (typeQualifier.precision != EbpUndefined) + { + returnType.precision = typeQualifier.precision; + } + + checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision, + typeSpecifier.getBasicType()); + + checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier, + typeSpecifier.getLine()); + + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier); if (mShaderVersion < 300) { - if (typeSpecifier.array) + if (typeSpecifier.isArray()) { - error(typeSpecifier.line, "not supported", "first-class array"); - recover(); + error(typeSpecifier.getLine(), "not supported", "first-class array"); returnType.clearArrayness(); } - if (qualifier == EvqAttribute && - (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + if (returnType.qualifier == EvqAttribute && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) { - error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); - recover(); + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); } - if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) && - (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) { - error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); - recover(); + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); } } else { - if (!layoutQualifier.isEmpty()) + if (!returnType.layoutQualifier.isEmpty()) { - if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout")) - { - recover(); - } + checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout"); } - if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut) + if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || + returnType.qualifier == EvqFragmentOut) { - es3InputOutputTypeCheck(qualifier, typeSpecifier, typeSpecifier.line); + checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, + typeSpecifier.getLine()); + } + if (returnType.qualifier == EvqComputeIn) + { + error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size", + "in"); } } return returnType; } -void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, - const TPublicType &type, - const TSourceLoc &qualifierLocation) +void TParseContext::checkInputOutputTypeIsValidES3(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) + if (type.getBasicType() == EbtBool) { error(qualifierLocation, "cannot be bool", getQualifierString(qualifier)); - recover(); } // Specific restrictions apply for vertex shader inputs and fragment shader outputs. @@ -1443,21 +2230,19 @@ void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, { case EvqVertexIn: // ESSL 3.00 section 4.3.4 - if (type.array) + if (type.isArray()) { error(qualifierLocation, "cannot be array", getQualifierString(qualifier)); - recover(); } - // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck + // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck return; case EvqFragmentOut: // ESSL 3.00 section 4.3.6 - if (type.isMatrix()) + if (type.typeSpecifierNonArray.isMatrix()) { error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier)); - recover(); } - // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck + // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck return; default: break; @@ -1466,506 +2251,997 @@ void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, // 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)); + (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || + type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) { error(qualifierLocation, "must use 'flat' interpolation here", getQualifierString(qualifier)); - recover(); } - if (type.type == EbtStruct) + if (type.getBasicType() == 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) + if (type.isArray()) { 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 &identifierOrTypeLocation, - const TString &identifier) +void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier) { - TIntermSymbol *symbol = - intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation); + if (qualifier.getType() == QtStorage) + { + const TStorageQualifierWrapper &storageQualifier = + static_cast(qualifier); + if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst && + !symbolTable.atGlobalLevel()) + { + error(storageQualifier.getLine(), + "Local variables can only use the const storage qualifier.", + storageQualifier.getQualifierString().c_str()); + } + } +} - bool emptyDeclaration = (identifier == ""); +void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, + const TSourceLoc &location) +{ + const std::string reason( + "Only allowed with shader storage blocks, variables declared within shader storage blocks " + "and variables declared as image types."); + if (memoryQualifier.readonly) + { + error(location, reason.c_str(), "readonly"); + } + if (memoryQualifier.writeonly) + { + error(location, reason.c_str(), "writeonly"); + } + if (memoryQualifier.coherent) + { + error(location, reason.c_str(), "coherent"); + } + if (memoryQualifier.restrictQualifier) + { + error(location, reason.c_str(), "restrict"); + } + if (memoryQualifier.volatileQualifier) + { + error(location, reason.c_str(), "volatile"); + } +} + +// Make sure there is no offset overlapping, and store the newly assigned offset to "type" in +// intermediate tree. +void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, + const TSourceLoc &loc, + TType *type) +{ + if (!IsAtomicCounter(type->getBasicType())) + { + return; + } + + const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct() + : kAtomicCounterSize; + TLayoutQualifier layoutQualifier = type->getLayoutQualifier(); + auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding]; + int offset; + if (layoutQualifier.offset == -1 || forceAppend) + { + offset = bindingState.appendSpan(size); + } + else + { + offset = bindingState.insertSpan(layoutQualifier.offset, size); + } + if (offset == -1) + { + error(loc, "Offset overlapping", "atomic counter"); + return; + } + layoutQualifier.offset = offset; + type->setLayoutQualifier(layoutQualifier); +} + +void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, + const char *token, + TType *type) +{ + if (IsGeometryShaderInput(mShaderType, type->getQualifier())) + { + if (type->isArray() && type->getOutermostArraySize() == 0u) + { + // Set size for the unsized geometry shader inputs if they are declared after a valid + // input primitive declaration. + if (mGeometryShaderInputPrimitiveType != EptUndefined) + { + ASSERT(mGeometryShaderInputArraySize > 0u); + type->sizeOutermostUnsizedArray(mGeometryShaderInputArraySize); + } + else + { + // [GLSL ES 3.2 SPEC Chapter 4.4.1.2] + // An input can be declared without an array size if there is a previous layout + // which specifies the size. + error(location, + "Missing a valid input primitive declaration before declaring an unsized " + "array input", + token); + } + } + else if (type->isArray()) + { + setGeometryShaderInputArraySize(type->getOutermostArraySize(), location); + } + else + { + error(location, "Geometry shader input variable must be declared as an array", token); + } + } +} - mDeferredSingleDeclarationErrorCheck = emptyDeclaration; +TIntermDeclaration *TParseContext::parseSingleDeclaration( + TPublicType &publicType, + const TSourceLoc &identifierOrTypeLocation, + const TString &identifier) +{ + TType type(publicType); + if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && + mDirectiveHandler.pragma().stdgl.invariantAll) + { + TQualifier qualifier = type.getQualifier(); + // The directive handler has already taken care of rejecting invalid uses of this pragma + // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all + // affected variable declarations: + // + // 1. Built-in special variables which are inputs to the fragment shader. (These are handled + // elsewhere, in TranslatorGLSL.) + // + // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It + // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but + // the way this is currently implemented we have to enable this compiler option before + // parsing the shader and determining the shading language version it uses. If this were + // implemented as a post-pass, the workaround could be more targeted. + // + // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of + // the specification, but there are desktop OpenGL drivers that expect that this is the + // behavior of the #pragma when specified in ESSL 1.00 fragment shaders. + if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn) + { + type.setInvariant(true); + } + } + + checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier.c_str(), &type); + + declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, + identifierOrTypeLocation); + + bool emptyDeclaration = (identifier == ""); + mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration; + + TIntermSymbol *symbol = nullptr; if (emptyDeclaration) { - if (publicType.isUnsizedArray()) + emptyDeclarationErrorCheck(type, identifierOrTypeLocation); + // In most cases we don't need to create a symbol node for an empty declaration. + // But if the empty declaration is declaring a struct type, the symbol node will store that. + if (type.getBasicType() == EbtStruct) { - // 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()); + symbol = new TIntermSymbol(symbolTable.getEmptySymbolId(), "", type); + } + else if (IsAtomicCounter(publicType.getBasicType())) + { + setAtomicCounterBindingDefaultOffset(publicType, identifierOrTypeLocation); } } else { - if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation)) - recover(); + nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation); - if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType)) - recover(); + checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &type); + + checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, &type); TVariable *variable = nullptr; - if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable)) - recover(); + declareVariable(identifierOrTypeLocation, identifier, type, &variable); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); + if (variable) + { + symbol = new TIntermSymbol(variable->getUniqueId(), identifier, type); + } } - return intermediate.makeAggregate(symbol, identifierOrTypeLocation); + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierOrTypeLocation); + if (symbol) + { + symbol->setLine(identifierOrTypeLocation); + declaration->appendDeclarator(symbol); + } + return declaration; } -TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, - const TSourceLoc &identifierLocation, - const TString &identifier, - const TSourceLoc &indexLocation, - TIntermTyped *indexExpression) +TIntermDeclaration *TParseContext::parseSingleArrayDeclaration( + TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &indexLocation, + const TVector &arraySizes) { - mDeferredSingleDeclarationErrorCheck = false; + mDeferredNonEmptyDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, + identifierLocation); - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) - { - recover(); - } + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); - TType arrayType(publicType); + TType arrayType(elementType); + arrayType.makeArrays(arraySizes); - int size; - if (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); + checkGeometryShaderInputAndSetArraySize(indexLocation, identifier.c_str(), &arrayType); + + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType); + + checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, &arrayType); TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, arrayType, &variable)) - recover(); + declareVariable(identifierLocation, identifier, arrayType, &variable); + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); - TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); + if (variable) + { + TIntermSymbol *symbol = new TIntermSymbol(variable->getUniqueId(), identifier, arrayType); + symbol->setLine(identifierLocation); + declaration->appendDeclarator(symbol); + } - return intermediate.makeAggregate(symbol, identifierLocation); + return declaration; } -TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, - const TSourceLoc &identifierLocation, - const TString &identifier, - const TSourceLoc &initLocation, - TIntermTyped *initializer) +TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer) { - mDeferredSingleDeclarationErrorCheck = false; + mDeferredNonEmptyDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, + identifierLocation); - TIntermNode *intermNode = nullptr; - if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) - { - // - // Build intermediate representation - // - return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr; - } - else + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); + + TIntermBinary *initNode = nullptr; + TType type(publicType); + if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) { - recover(); - return nullptr; + if (initNode) + { + declaration->appendDeclarator(initNode); + } } + return declaration; } -TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration( - TPublicType &publicType, +TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration( + TPublicType &elementType, const TSourceLoc &identifierLocation, const TString &identifier, const TSourceLoc &indexLocation, - TIntermTyped *indexExpression, + const TVector &arraySizes, const TSourceLoc &initLocation, TIntermTyped *initializer) { - mDeferredSingleDeclarationErrorCheck = false; + mDeferredNonEmptyDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, + identifierLocation); - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) - { - recover(); - } + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); - TPublicType arrayType(publicType); + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); - 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); + TType arrayType(elementType); + arrayType.makeArrays(arraySizes); + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); // initNode will correspond to the whole of "type b[n] = initializer". - TIntermNode *initNode = nullptr; - if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) + TIntermBinary *initNode = nullptr; + if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) { - return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr; - } - else - { - recover(); - return nullptr; + if (initNode) + { + declaration->appendDeclarator(initNode); + } } + + return declaration; } -TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc, - const TSourceLoc &identifierLoc, - const TString *identifier, - const TSymbol *symbol) +TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &identifierLoc, + const TString *identifier, + const TSymbol *symbol) { - // invariant declaration - if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying")) + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + if (!typeQualifier.invariant) { - recover(); + error(identifierLoc, "Expected invariant", identifier->c_str()); + return nullptr; + } + if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying")) + { + return nullptr; } - if (!symbol) { error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str()); - recover(); return nullptr; } - else + if (!IsQualifierUnspecified(typeQualifier.qualifier)) { - const TString kGlFrontFacing("gl_FrontFacing"); - if (*identifier == kGlFrontFacing) - { - error(identifierLoc, "identifier should not be declared as invariant", - identifier->c_str()); - recover(); - 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); + error(identifierLoc, "invariant declaration specifies qualifier", + getQualifierString(typeQualifier.qualifier)); + } + if (typeQualifier.precision != EbpUndefined) + { + error(identifierLoc, "invariant declaration specifies precision", + getPrecisionString(typeQualifier.precision)); + } + if (!typeQualifier.layoutQualifier.isEmpty()) + { + error(identifierLoc, "invariant declaration specifies layout", "'layout'"); + } - TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc); - aggregate->setOp(EOpInvariantDeclaration); - return aggregate; + const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); + if (!variable) + { + return nullptr; } + const TType &type = variable->getType(); + + checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(), + typeQualifier.line); + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); + + symbolTable.addInvariantVarying(std::string(identifier->c_str())); + + TIntermSymbol *intermSymbol = new TIntermSymbol(variable->getUniqueId(), *identifier, type); + intermSymbol->setLine(identifierLoc); + + return new TIntermInvariantDeclaration(intermSymbol, identifierLoc); } -TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, - TIntermAggregate *aggregateDeclaration, - const TSourceLoc &identifierLocation, - const TString &identifier) +void TParseContext::parseDeclarator(TPublicType &publicType, + const TSourceLoc &identifierLocation, + const TString &identifier, + TIntermDeclaration *declarationOut) { // If the declaration starting this declarator list was empty (example: int,), some checks were // not performed. - if (mDeferredSingleDeclarationErrorCheck) + if (mDeferredNonEmptyDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); - mDeferredSingleDeclarationErrorCheck = false; + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); - - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable)) - recover(); + TType type(publicType); + + checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier.c_str(), &type); + + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &type); - TIntermSymbol *symbol = - intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); + checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, &type); - return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); + declareVariable(identifierLocation, identifier, type, &variable); + + if (variable) + { + TIntermSymbol *symbol = new TIntermSymbol(variable->getUniqueId(), identifier, type); + symbol->setLine(identifierLocation); + declarationOut->appendDeclarator(symbol); + } } -TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType, - TIntermAggregate *aggregateDeclaration, - const TSourceLoc &identifierLocation, - const TString &identifier, - const TSourceLoc &arrayLocation, - TIntermTyped *indexExpression) +void TParseContext::parseArrayDeclarator(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &arrayLocation, + const TVector &arraySizes, + TIntermDeclaration *declarationOut) { // If the declaration starting this declarator list was empty (example: int,), some checks were // not performed. - if (mDeferredSingleDeclarationErrorCheck) + if (mDeferredNonEmptyDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); - mDeferredSingleDeclarationErrorCheck = false; + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); - - if (arrayTypeErrorCheck(arrayLocation, publicType) || - arrayQualifierErrorCheck(arrayLocation, publicType)) - { - recover(); - } - else + if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType)) { - TType arrayType = TType(publicType); - int size; - if (arraySizeErrorCheck(arrayLocation, indexExpression, size)) - { - recover(); - } - arrayType.setArraySize(size); + TType arrayType(elementType); + arrayType.makeArrays(arraySizes); - TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, arrayType, &variable)) - recover(); + checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier.c_str(), &arrayType); - TIntermSymbol *symbol = - intermediate.addSymbol(0, identifier, arrayType, identifierLocation); - if (variable && symbol) - symbol->setId(variable->getUniqueId()); + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType); - return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); - } + checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, &arrayType); - return nullptr; + TVariable *variable = nullptr; + declareVariable(identifierLocation, identifier, arrayType, &variable); + + if (variable) + { + TIntermSymbol *symbol = + new TIntermSymbol(variable->getUniqueId(), identifier, arrayType); + symbol->setLine(identifierLocation); + declarationOut->appendDeclarator(symbol); + } + } } -TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType, - TIntermAggregate *aggregateDeclaration, - const TSourceLoc &identifierLocation, - const TString &identifier, - const TSourceLoc &initLocation, - TIntermTyped *initializer) +void TParseContext::parseInitDeclarator(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut) { // If the declaration starting this declarator list was empty (example: int,), some checks were // not performed. - if (mDeferredSingleDeclarationErrorCheck) + if (mDeferredNonEmptyDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); - mDeferredSingleDeclarationErrorCheck = false; + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); - TIntermNode *intermNode = nullptr; - if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) + TIntermBinary *initNode = nullptr; + TType type(publicType); + if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) { // // build the intermediate representation // - if (intermNode) + if (initNode) { - return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation); + declarationOut->appendDeclarator(initNode); } - else + } +} + +void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &indexLocation, + const TVector &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut) +{ + // If the declaration starting this declarator list was empty (example: int,), some checks were + // not performed. + if (mDeferredNonEmptyDeclarationErrorCheck) + { + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; + } + + checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); + + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); + + TType arrayType(elementType); + arrayType.makeArrays(arraySizes); + + // initNode will correspond to the whole of "b[n] = initializer". + TIntermBinary *initNode = nullptr; + if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) + { + if (initNode) { - return aggregateDeclaration; + declarationOut->appendDeclarator(initNode); } } - else +} + +TIntermNode *TParseContext::addEmptyStatement(const TSourceLoc &location) +{ + // It's simpler to parse an empty statement as a constant expression rather than having a + // different type of node just for empty statements, that will be pruned from the AST anyway. + TIntermNode *node = CreateZeroNode(TType(EbtInt, EbpMedium)); + node->setLine(location); + return node; +} + +void TParseContext::setAtomicCounterBindingDefaultOffset(const TPublicType &publicType, + const TSourceLoc &location) +{ + const TLayoutQualifier &layoutQualifier = publicType.layoutQualifier; + checkAtomicCounterBindingIsValid(location, layoutQualifier.binding); + if (layoutQualifier.binding == -1 || layoutQualifier.offset == -1) { - recover(); - return nullptr; + error(location, "Requires both binding and offset", "layout"); + return; } + mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset); } -TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType, - TIntermAggregate *aggregateDeclaration, - const TSourceLoc &identifierLocation, - const TString &identifier, - const TSourceLoc &indexLocation, - TIntermTyped *indexExpression, - const TSourceLoc &initLocation, - TIntermTyped *initializer) +void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision, + const TPublicType &type, + const TSourceLoc &loc) { - // If the declaration starting this declarator list was empty (example: int,), some checks were - // not performed. - if (mDeferredSingleDeclarationErrorCheck) + if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) && + !getFragmentPrecisionHigh()) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); - mDeferredSingleDeclarationErrorCheck = false; + error(loc, "precision is not supported in fragment shader", "highp"); } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + if (!CanSetDefaultPrecisionOnType(type)) + { + error(loc, "illegal type argument for default precision qualifier", + getBasicString(type.getBasicType())); + return; + } + symbolTable.setDefaultPrecision(type.getBasicType(), precision); +} - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) +bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier) +{ + switch (typeQualifier.layoutQualifier.primitiveType) { - recover(); + case EptLines: + case EptLinesAdjacency: + case EptTriangles: + case EptTrianglesAdjacency: + return typeQualifier.qualifier == EvqGeometryIn; + + case EptLineStrip: + case EptTriangleStrip: + return typeQualifier.qualifier == EvqGeometryOut; + + case EptPoints: + return true; + + default: + UNREACHABLE(); + return false; } +} - TPublicType arrayType(publicType); +void TParseContext::setGeometryShaderInputArraySize(unsigned int inputArraySize, + const TSourceLoc &line) +{ + if (mGeometryShaderInputArraySize == 0u) + { + mGeometryShaderInputArraySize = inputArraySize; + } + else if (mGeometryShaderInputArraySize != inputArraySize) + { + error(line, + "Array size or input primitive declaration doesn't match the size of earlier sized " + "array inputs.", + "layout"); + } +} - 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)) +bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier) +{ + ASSERT(typeQualifier.qualifier == EvqGeometryIn); + + const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; + + if (layoutQualifier.maxVertices != -1) { - recover(); + error(typeQualifier.line, + "max_vertices can only be declared in 'out' layout in a geometry shader", "layout"); + return false; } - // 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)) + // Set mGeometryInputPrimitiveType if exists + if (layoutQualifier.primitiveType != EptUndefined) { - if (initNode) + if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) { - return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation); + error(typeQualifier.line, "invalid primitive type for 'in' layout", "layout"); + return false; } - else + + if (mGeometryShaderInputPrimitiveType == EptUndefined) { - return aggregateDeclaration; + mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType; + setGeometryShaderInputArraySize( + GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType), + typeQualifier.line); + } + else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType) + { + error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration", + "layout"); + return false; } } - else + + // Set mGeometryInvocations if exists + if (layoutQualifier.invocations > 0) { - recover(); - return nullptr; + if (mGeometryShaderInvocations == 0) + { + mGeometryShaderInvocations = layoutQualifier.invocations; + } + else if (mGeometryShaderInvocations != layoutQualifier.invocations) + { + error(typeQualifier.line, "invocations contradicts to the earlier declaration", + "layout"); + return false; + } } + + return true; } -void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) +bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier) { - if (typeQualifier.qualifier != EvqUniform) + ASSERT(typeQualifier.qualifier == EvqGeometryOut); + + const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; + + if (layoutQualifier.invocations > 0) { - error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), - "global layout must be uniform"); - recover(); - return; + error(typeQualifier.line, + "invocations can only be declared in 'in' layout in a geometry shader", "layout"); + return false; } + // Set mGeometryOutputPrimitiveType if exists + if (layoutQualifier.primitiveType != EptUndefined) + { + if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) + { + error(typeQualifier.line, "invalid primitive type for 'out' layout", "layout"); + return false; + } + + if (mGeometryShaderOutputPrimitiveType == EptUndefined) + { + mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType; + } + else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType) + { + error(typeQualifier.line, + "primitive doesn't match earlier output primitive declaration", "layout"); + return false; + } + } + + // Set mGeometryMaxVertices if exists + if (layoutQualifier.maxVertices > -1) + { + if (mGeometryShaderMaxVertices == -1) + { + mGeometryShaderMaxVertices = layoutQualifier.maxVertices; + } + else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices) + { + error(typeQualifier.line, "max_vertices contradicts to the earlier declaration", + "layout"); + return false; + } + } + + return true; +} + +void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; - ASSERT(!layoutQualifier.isEmpty()); - if (mShaderVersion < 300) + checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier, + typeQualifier.line); + + // It should never be the case, but some strange parser errors can send us here. + if (layoutQualifier.isEmpty()) { - error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout"); - recover(); + error(typeQualifier.line, "Error during layout qualifier parsing.", "?"); return; } - if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier)) + if (!layoutQualifier.isCombinationValid()) { - recover(); + error(typeQualifier.line, "invalid layout qualifier combination", "layout"); return; } - if (layoutQualifier.matrixPacking != EmpUnspecified) + checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding); + + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); + + checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat); + + checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv); + + checkOffsetIsNotSpecified(typeQualifier.line, layoutQualifier.offset); + + checkStd430IsForShaderStorageBlock(typeQualifier.line, layoutQualifier.blockStorage, + typeQualifier.qualifier); + + if (typeQualifier.qualifier == EvqComputeIn) { - mDefaultMatrixPacking = layoutQualifier.matrixPacking; + if (mComputeShaderLocalSizeDeclared && + !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize)) + { + error(typeQualifier.line, "Work group size does not match the previous declaration", + "layout"); + return; + } + + if (mShaderVersion < 310) + { + error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); + return; + } + + if (!layoutQualifier.localSize.isAnyValueSet()) + { + error(typeQualifier.line, "No local work group size specified", "layout"); + return; + } + + const TVariable *maxComputeWorkGroupSize = static_cast( + symbolTable.findBuiltIn("gl_MaxComputeWorkGroupSize", mShaderVersion)); + + const TConstantUnion *maxComputeWorkGroupSizeData = + maxComputeWorkGroupSize->getConstPointer(); + + for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i) + { + if (layoutQualifier.localSize[i] != -1) + { + mComputeShaderLocalSize[i] = layoutQualifier.localSize[i]; + const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst(); + if (mComputeShaderLocalSize[i] < 1 || + mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue) + { + std::stringstream reasonStream; + reasonStream << "invalid value: Value must be at least 1 and no greater than " + << maxComputeWorkGroupSizeValue; + const std::string &reason = reasonStream.str(); + + error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i)); + return; + } + } + } + + mComputeShaderLocalSizeDeclared = true; } + else if (typeQualifier.qualifier == EvqGeometryIn) + { + if (mShaderVersion < 310) + { + error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); + return; + } - if (layoutQualifier.blockStorage != EbsUnspecified) + if (!parseGeometryShaderInputLayoutQualifier(typeQualifier)) + { + return; + } + } + else if (typeQualifier.qualifier == EvqGeometryOut) + { + if (mShaderVersion < 310) + { + error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only", + "layout"); + return; + } + + if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier)) + { + return; + } + } + else if (isExtensionEnabled(TExtension::OVR_multiview) && + typeQualifier.qualifier == EvqVertexIn) + { + // This error is only specified in WebGL, but tightens unspecified behavior in the native + // specification. + if (mNumViews != -1 && layoutQualifier.numViews != mNumViews) + { + error(typeQualifier.line, "Number of views does not match the previous declaration", + "layout"); + return; + } + + if (layoutQualifier.numViews == -1) + { + error(typeQualifier.line, "No num_views specified", "layout"); + return; + } + + if (layoutQualifier.numViews > mMaxNumViews) + { + error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR", + "layout"); + return; + } + + mNumViews = layoutQualifier.numViews; + } + else { - mDefaultBlockStorage = layoutQualifier.blockStorage; + if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier)) + { + return; + } + + if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) + { + error(typeQualifier.line, "invalid qualifier: global layout can only be set for blocks", + getQualifierString(typeQualifier.qualifier)); + return; + } + + if (mShaderVersion < 300) + { + error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above", + "layout"); + return; + } + + checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier); + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + mDefaultUniformMatrixPacking = layoutQualifier.matrixPacking; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + mDefaultBufferMatrixPacking = layoutQualifier.matrixPacking; + } + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + mDefaultUniformBlockStorage = layoutQualifier.blockStorage; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + mDefaultBufferBlockStorage = layoutQualifier.blockStorage; + } + } } } -TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function, - const TSourceLoc &location) +TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction( + const TFunction &function, + const TSourceLoc &location, + bool insertParametersToSymbolTable) { - // 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(); + checkIsNotReserved(location, function.getName()); - TIntermAggregate *prototype = new TIntermAggregate; - prototype->setType(function.getReturnType()); - prototype->setName(function.getMangledName()); - prototype->setFunctionId(function.getUniqueId()); + TIntermFunctionPrototype *prototype = + new TIntermFunctionPrototype(function.getReturnType(), TSymbolUniqueId(function)); + // TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could + // point to the data that already exists in the symbol table. + prototype->getFunctionSymbolInfo()->setFromFunction(function); + prototype->setLine(location); 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); + TIntermSymbol *symbol = nullptr; + + // If the parameter has no name, it's not an error, just don't add it to symbol table (could + // be used for unused args). + if (param.name != nullptr) + { + // Insert the parameter in the symbol table. + if (insertParametersToSymbolTable) + { + TVariable *variable = symbolTable.declareVariable(param.name, *param.type); + if (variable) + { + symbol = new TIntermSymbol(variable->getUniqueId(), variable->getName(), + variable->getType()); + } + else + { + error(location, "redefinition", param.name->c_str()); + } + } + // Unsized type of a named parameter should have already been checked and sanitized. + ASSERT(!param.type->isUnsizedArray()); } else { - TIntermSymbol *paramSymbol = intermediate.addSymbol(0, "", *param.type, location); - prototype = intermediate.growAggregate(prototype, paramSymbol, location); + if (param.type->isUnsizedArray()) + { + error(location, "function parameter array must be sized at compile time", "[]"); + // We don't need to size the arrays since the parameter is unnamed and hence + // inaccessible. + } + } + if (!symbol) + { + // The parameter had no name or declaring the symbol failed - either way, add a nameless + // symbol. + symbol = new TIntermSymbol(symbolTable.getEmptySymbolId(), "", *param.type); } + symbol->setLine(location); + prototype->appendParameter(symbol); + } + return prototype; +} + +TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration( + const TFunction &parsedFunction, + const TSourceLoc &location) +{ + // Note: function found from the symbol table could be the same as parsedFunction 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 *function = static_cast( + symbolTable.find(parsedFunction.getMangledName(), getShaderVersion())); + if (function->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"); } + function->setHasPrototypeDeclaration(); - prototype->setOp(EOpPrototype); + TIntermFunctionPrototype *prototype = + createPrototypeNodeFromFunction(*function, location, false); symbolTable.pop(); @@ -1973,135 +3249,80 @@ TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction { // 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) +TIntermFunctionDefinition *TParseContext::addFunctionDefinition( + TIntermFunctionPrototype *functionPrototype, + TIntermBlock *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 + // Check that non-void functions have at least one return statement. if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) { - error(location, "function does not return a value:", "", function.getName().c_str()); - recover(); + error(location, "function does not return a value:", + functionPrototype->getFunctionSymbolInfo()->getName().c_str()); } - 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()); + if (functionBody == nullptr) + { + functionBody = new TIntermBlock(); + functionBody->setLine(location); + } + TIntermFunctionDefinition *functionNode = + new TIntermFunctionDefinition(functionPrototype, functionBody); + functionNode->setLine(location); symbolTable.pop(); - return aggregate; + return functionNode; } -void TParseContext::parseFunctionPrototype(const TSourceLoc &location, - TFunction *function, - TIntermAggregate **aggregateOut) +void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location, + TFunction **function, + TIntermFunctionPrototype **prototypeOut) { + ASSERT(function); + ASSERT(*function); const TSymbol *builtIn = - symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion()); + symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion()); if (builtIn) { - error(location, "built-in functions cannot be redefined", function->getName().c_str()); - recover(); + error(location, "built-in functions cannot be redefined", (*function)->getName().c_str()); } - - 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()) + else { - // 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()); + TFunction *prevDec = static_cast( + symbolTable.find((*function)->getMangledName(), getShaderVersion())); - // Raise error message if main function takes any parameters or return anything other than void - if (function->getName() == "main") - { - if (function->getParamCount() > 0) + // 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 (*function != prevDec) { - error(location, "function cannot take any parameter(s)", function->getName().c_str()); - recover(); + // Swap the parameters of the previous declaration to the parameters of the function + // definition (parameter names may differ). + prevDec->swapParameters(**function); + + // The function definition will share the same symbol as any previous declaration. + *function = prevDec; } - if (function->getReturnType().getBasicType() != EbtVoid) + + if ((*function)->isDefined()) { - error(location, "", function->getReturnType().getBasicString(), - "main function cannot return a value"); - recover(); + error(location, "function already has a body", (*function)->getName().c_str()); } + + (*function)->setDefined(); } - // - // Remember the return type for later checking for RETURN statements. - // - mCurrentFunctionType = &(prevDec->getReturnType()); + // Remember the return type for later checking for return statements. + mCurrentFunctionType = &((*function)->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; + *prototypeOut = createPrototypeNodeFromFunction(**function, location, true); setLoopNestingLevel(0); } @@ -2117,22 +3338,42 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF // TFunction *prevDec = static_cast(symbolTable.find(function->getMangledName(), getShaderVersion())); - if (prevDec) + + for (size_t i = 0u; i < function->getParamCount(); ++i) + { + auto ¶m = function->getParam(i); + if (param.type->isStructSpecifier()) + { + // ESSL 3.00.6 section 12.10. + error(location, "Function parameter type cannot be a structure definition", + function->getName().c_str()); + } + } + + if (getShaderVersion() >= 300 && + symbolTable.hasUnmangledBuiltInForShaderVersion(function->getName().c_str(), + getShaderVersion())) + { + // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as functions. + // Therefore overloading or redefining builtin functions is an error. + error(location, "Name of a built-in function cannot be redeclared as function", + function->getName().c_str()); + } + else if (prevDec) { if (prevDec->getReturnType() != function->getReturnType()) { - error(location, "overloaded functions must have the same return type", + error(location, "function must have the same return type in all of its declarations", 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", + error(location, + "function must have the same parameter qualifiers in all of its declarations", function->getParam(i).type->getQualifierString()); - recover(); } } } @@ -2145,22 +3386,33 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF { if (!prevSym->isFunction()) { - error(location, "redefinition", function->getName().c_str(), "function"); - recover(); + error(location, "redefinition of a function", function->getName().c_str()); } } 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); + symbolTable.getOuterLevel()->insertUnmangled(function); } // 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); + // 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)", "main"); + } + if (function->getReturnType().getBasicType() != EbtVoid) + { + error(location, "main function cannot return a value", + function->getReturnType().getBasicString()); + } + } + // // 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 @@ -2169,420 +3421,302 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF return function; } -TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) +TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, + const TString *name, + const TSourceLoc &location) { - TPublicType publicType = publicTypeIn; - if (publicType.isStructSpecifier) + if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary) { - error(publicType.line, "constructor can't be a structure definition", - getBasicString(publicType.type)); - recover(); + error(location, "no qualifiers allowed for function return", + getQualifierString(type.qualifier)); } - - TOperator op = EOpNull; - if (publicType.userDef) + if (!type.layoutQualifier.isEmpty()) { - op = EOpConstructStruct; + error(location, "no qualifiers allowed for function return", "layout"); } - else + // make sure an opaque type is not involved as well... + std::string reason(getBasicString(type.getBasicType())); + reason += "s can't be function return values"; + checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str()); + if (mShaderVersion < 300) { - switch (publicType.type) - { - case EbtFloat: - if (publicType.isMatrix()) - { - 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()) - { - case 1: - op = EOpConstructFloat; - break; - case 2: - op = EOpConstructVec2; - break; - case 3: - op = EOpConstructVec3; - break; - case 4: - op = EOpConstructVec4; - break; - } - } - break; - - case EbtInt: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructInt; - break; - case 2: - op = EOpConstructIVec2; - break; - case 3: - op = EOpConstructIVec3; - break; - case 4: - op = EOpConstructIVec4; - break; - } - break; - - case EbtUInt: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructUInt; - break; - case 2: - op = EOpConstructUVec2; - break; - case 3: - op = EOpConstructUVec3; - break; - case 4: - op = EOpConstructUVec4; - break; - } - break; - - case EbtBool: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructBool; - break; - case 2: - op = EOpConstructBVec2; - break; - case 3: - op = EOpConstructBVec3; - break; - case 4: - op = EOpConstructBVec4; - break; - } - break; - - default: - break; - } + // Array return values are forbidden, but there's also no valid syntax for declaring array + // return values in ESSL 1.00. + ASSERT(!type.isArray() || mDiagnostics->numErrors() > 0); - if (op == EOpNull) + if (type.isStructureContainingArrays()) { - error(publicType.line, "cannot construct this type", getBasicString(publicType.type)); - recover(); - publicType.type = EbtFloat; - op = EOpConstructFloat; + // ESSL 1.00.17 section 6.1 Function Definitions + error(location, "structures containing arrays can't be function return values", + TType(type).getCompleteString().c_str()); } } - TString tempString; - const TType *type = new TType(publicType); - return new TFunction(&tempString, type, op); + // Add the function as a prototype after parsing it (we do not support recursion) + return new TFunction(&symbolTable, name, new TType(type)); } -// 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) +TFunction *TParseContext::addNonConstructorFunc(const TString *name, const TSourceLoc &loc) { - TIntermAggregate *constructor = arguments->getAsAggregate(); - ASSERT(constructor != nullptr); + const TType *returnType = TCache::getType(EbtVoid, EbpUndefined); + return new TFunction(&symbolTable, name, returnType); +} - if (type->isArray()) - { - // 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; - } - } - } - else if (op == EOpConstructStruct) +TFunction *TParseContext::addConstructorFunc(const TPublicType &publicType) +{ + if (mShaderVersion < 300 && publicType.isArray()) { - const TFieldList &fields = type->getStruct()->fields(); - 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"); - recover(); - - return 0; - } - } + error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only", + "[]"); } - - // Turn the argument list itself into a constructor - 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. - if (op != EOpConstructStruct) + if (publicType.isStructSpecifier()) { - constructor->setPrecisionFromChildren(); - type->setPrecision(constructor->getPrecision()); + error(publicType.getLine(), "constructor can't be a structure definition", + getBasicString(publicType.getBasicType())); } - TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor); - if (constConstructor) + TType *type = new TType(publicType); + if (!type->canBeConstructed()) { - return constConstructor; + error(publicType.getLine(), "cannot construct this type", + getBasicString(publicType.getBasicType())); + type->setBasicType(EbtFloat); } - return constructor; + return new TFunction(&symbolTable, nullptr, type, EOpConstruct); } -// -// 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, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) +void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line, + const char *errorMessage, + const char *token, + TType *arrayType) { - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - ASSERT(unionArray); - - TConstantUnion *constArray = new TConstantUnion[fields.num]; - - for (int i = 0; i < fields.num; i++) + if (arrayType->isUnsizedArray()) { - 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(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - fields.offsets[i] = node->getType().getNominalSize() - 1; - } - - constArray[i] = unionArray[fields.offsets[i]]; + error(line, errorMessage, token); + arrayType->sizeUnsizedArrays(nullptr); } - 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) -// -TIntermTyped *TParseContext::addConstMatrixNode(int index, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) +TParameter TParseContext::parseParameterDeclarator(TType *type, + const TString *name, + const TSourceLoc &nameLoc) { - if (index >= node->getType().getCols()) + ASSERT(type); + checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size", name->c_str(), + type); + if (type->getBasicType() == EbtVoid) { - std::stringstream extraInfoStream; - extraInfoStream << "matrix field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - index = node->getType().getCols() - 1; + error(nameLoc, "illegal use of type 'void'", name->c_str()); } + checkIsNotReserved(nameLoc, *name); + TParameter param = {name, type}; + return param; +} - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - int size = node->getType().getCols(); - return intermediate.addConstantUnion(&unionArray[size * index], node->getType(), line); +TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType, + const TString *name, + const TSourceLoc &nameLoc) +{ + TType *type = new TType(publicType); + return parseParameterDeclarator(type, name, nameLoc); } -// -// 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, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) +TParameter TParseContext::parseParameterArrayDeclarator(const TString *name, + const TSourceLoc &nameLoc, + const TVector &arraySizes, + const TSourceLoc &arrayLoc, + TPublicType *elementType) { - TType arrayElementType = node->getType(); - arrayElementType.clearArrayness(); + checkArrayElementIsNotArray(arrayLoc, *elementType); + TType *arrayType = new TType(*elementType); + arrayType->makeArrays(arraySizes); + return parseParameterDeclarator(arrayType, name, nameLoc); +} - if (index >= node->getType().getArraySize()) +bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality(TIntermSequence *arguments, + TType type, + const TSourceLoc &line) +{ + if (arguments->empty()) + { + error(line, "implicitly sized array constructor must have at least one argument", "[]"); + return false; + } + for (TIntermNode *arg : *arguments) { - std::stringstream extraInfoStream; - extraInfoStream << "array field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - index = node->getType().getArraySize() - 1; + TIntermTyped *element = arg->getAsTyped(); + ASSERT(element); + size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u; + if (dimensionalityFromElement > type.getNumArraySizes()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + else if (dimensionalityFromElement < type.getNumArraySizes()) + { + if (dimensionalityFromElement == 1u) + { + error(line, "implicitly sized array of arrays constructor argument is not an array", + "constructor"); + } + else + { + error(line, + "implicitly sized array of arrays constructor argument dimensionality is too " + "low", + "constructor"); + } + return false; + } } - size_t arrayElementSize = arrayElementType.getObjectSize(); - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], node->getType(), - line); + return true; } +// 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 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. +// Returns a node to add to the tree regardless of if an error was generated or not. // -TIntermTyped *TParseContext::addConstStruct(const TString &identifier, - TIntermTyped *node, +TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments, + TType type, const TSourceLoc &line) { - const TFieldList &fields = node->getType().getStruct()->fields(); - size_t instanceSize = 0; - - for (size_t index = 0; index < fields.size(); ++index) + if (type.isUnsizedArray()) { - if (fields[index]->name() == identifier) + if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line)) { - break; + type.sizeUnsizedArrays(nullptr); + return CreateZeroNode(type); } - else + TIntermTyped *firstElement = arguments->at(0)->getAsTyped(); + ASSERT(firstElement); + if (type.getOutermostArraySize() == 0u) + { + type.sizeOutermostUnsizedArray(static_cast(arguments->size())); + } + for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i) { - instanceSize += fields[index]->type()->getObjectSize(); + if ((*type.getArraySizes())[i] == 0u) + { + type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]); + } } + ASSERT(!type.isUnsizedArray()); } - TIntermTyped *typedNode; - TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); - if (tempConstantNode) + if (!checkConstructorArguments(line, arguments, type)) { - const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer(); - - // type will be changed in the calling function - typedNode = intermediate.addConstantUnion(constArray + instanceSize, - tempConstantNode->getType(), line); + return CreateZeroNode(type); } - else - { - error(line, "Cannot offset into the structure", "Error"); - recover(); - return 0; - } + TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, arguments); + constructorNode->setLine(line); - return typedNode; + // TODO(oetuaho@nvidia.com): Add support for folding array constructors. + if (!constructorNode->isArray()) + { + return constructorNode->fold(mDiagnostics); + } + return constructorNode; } // // Interface/uniform blocks +// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_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) +TIntermDeclaration *TParseContext::addInterfaceBlock( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &nameLine, + const TString &blockName, + TFieldList *fieldList, + const TString *instanceName, + const TSourceLoc &instanceLine, + TIntermTyped *arrayIndex, + const TSourceLoc &arrayIndexLine) { - if (reservedErrorCheck(nameLine, blockName)) - recover(); + checkIsNotReserved(nameLine, blockName); + + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + if (mShaderVersion < 310 && typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, + "invalid qualifier: interface blocks must be uniform in version lower than GLSL ES " + "3.10", + getQualifierString(typeQualifier.qualifier)); + } + else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) + { + error(typeQualifier.line, "invalid qualifier: interface blocks must be uniform or buffer", + getQualifierString(typeQualifier.qualifier)); + } - if (typeQualifier.qualifier != EvqUniform) + if (typeQualifier.invariant) { - error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), - "interface blocks must be uniform"); - recover(); + error(typeQualifier.line, "invalid qualifier on interface block member", "invariant"); } - TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; - if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier)) + if (typeQualifier.qualifier != EvqBuffer) { - recover(); + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); } + // add array index + unsigned int arraySize = 0; + if (arrayIndex != nullptr) + { + arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex); + } + + if (mShaderVersion < 310) + { + checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding); + } + else + { + checkBlockBindingIsValid(typeQualifier.line, typeQualifier.qualifier, + typeQualifier.layoutQualifier.binding, arraySize); + } + + checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv); + + TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; + checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); + checkStd430IsForShaderStorageBlock(typeQualifier.line, blockLayoutQualifier.blockStorage, + typeQualifier.qualifier); + if (blockLayoutQualifier.matrixPacking == EmpUnspecified) { - blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking; + if (typeQualifier.qualifier == EvqUniform) + { + blockLayoutQualifier.matrixPacking = mDefaultUniformMatrixPacking; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + blockLayoutQualifier.matrixPacking = mDefaultBufferMatrixPacking; + } } if (blockLayoutQualifier.blockStorage == EbsUnspecified) { - blockLayoutQualifier.blockStorage = mDefaultBlockStorage; + if (typeQualifier.qualifier == EvqUniform) + { + blockLayoutQualifier.blockStorage = mDefaultUniformBlockStorage; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + blockLayoutQualifier.blockStorage = mDefaultBufferBlockStorage; + } } - TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName); - if (!symbolTable.declare(blockNameSymbol)) + checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier); + + checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat); + + if (!symbolTable.declareInterfaceBlockName(&blockName)) { - error(nameLine, "redefinition", blockName.c_str(), "interface block name"); - recover(); + error(nameLine, "redefinition of an interface block name", blockName.c_str()); } // check for sampler types and apply layout qualifiers @@ -2590,38 +3724,53 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif { TField *field = (*fieldList)[memberIndex]; TType *fieldType = field->type(); - if (IsSampler(fieldType->getBasicType())) + if (IsOpaqueType(fieldType->getBasicType())) { - error(field->line(), "unsupported type", fieldType->getBasicString(), - "sampler types are not allowed in interface blocks"); - recover(); + std::string reason("unsupported type - "); + reason += fieldType->getBasicString(); + reason += " types are not allowed in interface blocks"; + error(field->line(), reason.c_str(), fieldType->getBasicString()); } const TQualifier qualifier = fieldType->getQualifier(); switch (qualifier) { case EvqGlobal: + break; case EvqUniform: + if (typeQualifier.qualifier == EvqBuffer) + { + error(field->line(), "invalid qualifier on shader storage block member", + getQualifierString(qualifier)); + } + break; + case EvqBuffer: + if (typeQualifier.qualifier == EvqUniform) + { + error(field->line(), "invalid qualifier on uniform block member", + getQualifierString(qualifier)); + } break; default: error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier)); - recover(); break; } - // check layout qualifiers - TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); - if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier)) + if (fieldType->isInvariant()) { - recover(); + error(field->line(), "invalid qualifier on interface block member", "invariant"); } + // check layout qualifiers + TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); + checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier); + checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding); + if (fieldLayoutQualifier.blockStorage != EbsUnspecified) { - error(field->line(), "invalid layout qualifier:", - getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here"); - recover(); + error(field->line(), "invalid layout qualifier: cannot be used here", + getBlockStorageString(fieldLayoutQualifier.blockStorage)); } if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) @@ -2630,29 +3779,51 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif } else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct) { - warning(field->line(), "extraneous layout qualifier:", - getMatrixPackingString(fieldLayoutQualifier.matrixPacking), - "only has an effect on matrix types"); + warning(field->line(), + "extraneous layout qualifier: only has an effect on matrix types", + getMatrixPackingString(fieldLayoutQualifier.matrixPacking)); } fieldType->setLayoutQualifier(fieldLayoutQualifier); - } - // add array index - int arraySize = 0; - if (arrayIndex != NULL) - { - if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize)) - recover(); + if (mShaderVersion < 310 || memberIndex != fieldList->size() - 1u || + typeQualifier.qualifier != EvqBuffer) + { + // ESSL 3.10 spec section 4.1.9 allows for runtime-sized arrays. + checkIsNotUnsizedArray(field->line(), + "array members of interface blocks must specify a size", + field->name().c_str(), field->type()); + } + + if (typeQualifier.qualifier == EvqBuffer) + { + // set memory qualifiers + // GLSL ES 3.10 session 4.9 [Memory Access Qualifiers]. When a block declaration is + // qualified with a memory qualifier, it is as if all of its members were declared with + // the same memory qualifier. + const TMemoryQualifier &blockMemoryQualifier = typeQualifier.memoryQualifier; + TMemoryQualifier fieldMemoryQualifier = fieldType->getMemoryQualifier(); + fieldMemoryQualifier.readonly |= blockMemoryQualifier.readonly; + fieldMemoryQualifier.writeonly |= blockMemoryQualifier.writeonly; + fieldMemoryQualifier.coherent |= blockMemoryQualifier.coherent; + fieldMemoryQualifier.restrictQualifier |= blockMemoryQualifier.restrictQualifier; + fieldMemoryQualifier.volatileQualifier |= blockMemoryQualifier.volatileQualifier; + // TODO(jiajia.qin@intel.com): Decide whether if readonly and writeonly buffer variable + // is legal. See bug https://github.com/KhronosGroup/OpenGL-API/issues/7 + fieldType->setMemoryQualifier(fieldMemoryQualifier); + } } TInterfaceBlock *interfaceBlock = - new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier); - TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, - arraySize); + new TInterfaceBlock(&blockName, fieldList, instanceName, blockLayoutQualifier); + TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier); + if (arrayIndex != nullptr) + { + interfaceBlockType.makeArray(arraySize); + } TString symbolName = ""; - int symbolId = 0; + const TSymbolUniqueId *symbolId = nullptr; if (!instanceName) { @@ -2665,60 +3836,64 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif // set parent pointer of the field variable fieldType->setInterfaceBlock(interfaceBlock); - TVariable *fieldVariable = new TVariable(&field->name(), *fieldType); - fieldVariable->setQualifier(typeQualifier.qualifier); + TVariable *fieldVariable = symbolTable.declareVariable(&field->name(), *fieldType); - if (!symbolTable.declare(fieldVariable)) + if (fieldVariable) { - error(field->line(), "redefinition", field->name().c_str(), - "interface block member name"); - recover(); + fieldVariable->setQualifier(typeQualifier.qualifier); + } + else + { + error(field->line(), "redefinition of an interface block member name", + field->name().c_str()); } } + symbolId = &symbolTable.getEmptySymbolId(); } else { - if (reservedErrorCheck(instanceLine, *instanceName)) - recover(); + checkIsNotReserved(instanceLine, *instanceName); // add a symbol for this interface block - TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false); - instanceTypeDef->setQualifier(typeQualifier.qualifier); - - if (!symbolTable.declare(instanceTypeDef)) + TVariable *instanceTypeDef = symbolTable.declareVariable(instanceName, interfaceBlockType); + if (instanceTypeDef) { - error(instanceLine, "redefinition", instanceName->c_str(), - "interface block instance name"); - recover(); + instanceTypeDef->setQualifier(typeQualifier.qualifier); + symbolId = &instanceTypeDef->getUniqueId(); } - - symbolId = instanceTypeDef->getUniqueId(); - symbolName = instanceTypeDef->getName(); + else + { + error(instanceLine, "redefinition of an interface block instance name", + instanceName->c_str()); + } + symbolName = *instanceName; } - TIntermAggregate *aggregate = intermediate.makeAggregate( - intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), - nameLine); - aggregate->setOp(EOpDeclaration); + TIntermDeclaration *declaration = nullptr; + + if (symbolId) + { + TIntermSymbol *blockSymbol = new TIntermSymbol(*symbolId, symbolName, interfaceBlockType); + blockSymbol->setLine(typeQualifier.line); + declaration = new TIntermDeclaration(); + declaration->appendDeclarator(blockSymbol); + declaration->setLine(nameLine); + } exitStructDeclaration(); - return aggregate; + return declaration; } -bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier) +void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier) { ++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. + // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11. if (mStructNestingLevel > 1) { - error(line, "", "Embedded struct definitions are not allowed"); - return true; + error(line, "Embedded struct definitions are not allowed", "struct"); } - - return false; } void TParseContext::exitStructDeclaration() @@ -2726,22 +3901,16 @@ void TParseContext::exitStructDeclaration() --mStructNestingLevel; } -namespace -{ -const int kWebGLMaxStructNesting = 4; - -} // namespace - -bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field) +void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field) { - if (!IsWebGLBasedSpec(mShaderSpec)) + if (!sh::IsWebGLBasedSpec(mShaderSpec)) { - return false; + return; } if (field.type()->getBasicType() != EbtStruct) { - return false; + return; } // We're already inside a structure definition at this point, so add @@ -2752,11 +3921,9 @@ bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField 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; + error(line, reason.c_str(), field.name().c_str()); + return; } - - return false; } // @@ -2766,8 +3933,6 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc &location, TIntermTyped *indexExpression) { - TIntermTyped *indexedExpression = NULL; - if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) { if (baseExpression->getAsSymbolNode()) @@ -2779,7 +3944,18 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, { error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); } - recover(); + + return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + } + + if (baseExpression->getQualifier() == EvqPerVertexIn) + { + ASSERT(mShaderType == GL_GEOMETRY_SHADER_OES); + if (mGeometryShaderInputPrimitiveType == EptUndefined) + { + error(location, "missing input primitive declaration before indexing gl_in.", "["); + return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + } } TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); @@ -2792,174 +3968,139 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, { if (baseExpression->isInterfaceBlock()) { - error( - location, "", "[", - "array indexes for interface blocks arrays must be constant integral expressions"); - recover(); + // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks. + switch (baseExpression->getQualifier()) + { + case EvqPerVertexIn: + break; + case EvqUniform: + case EvqBuffer: + error(location, + "array indexes for uniform block arrays and shader storage block arrays " + "must be constant integral expressions", + "["); + break; + default: + // We can reach here only in error cases. + ASSERT(mDiagnostics->numErrors() > 0); + break; + } } else if (baseExpression->getQualifier() == EvqFragmentOut) { - error(location, "", "[", - "array indexes for fragment outputs must be constant integral expressions"); - recover(); + error(location, + "array indexes for fragment outputs must be constant integral expressions", "["); } else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData) { - error(location, "", "[", "array index for gl_FragData must be constant zero"); - recover(); + error(location, "array index for gl_FragData must be constant zero", "["); } } 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. + // If an out-of-range 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) + int index = 0; + if (indexConstantUnion->getBasicType() == EbtInt) { - std::stringstream infoStream; - infoStream << index; - std::string info = infoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "negative index", info.c_str()); - index = 0; + index = indexConstantUnion->getIConst(0); } - TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion(); - if (baseConstantUnion) + else if (indexConstantUnion->getBasicType() == EbtUInt) { - if (baseExpression->isArray()) - { - // constant folding for array indexing - indexedExpression = - addConstArrayNode(index, baseConstantUnion, location, outOfRangeIndexIsError); - } - else if (baseExpression->isVector()) - { - // 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, baseConstantUnion, location, outOfRangeIndexIsError); - } - else if (baseExpression->isMatrix()) - { - // constant folding for matrix indexing - indexedExpression = - addConstMatrixNode(index, baseConstantUnion, location, outOfRangeIndexIsError); - } + index = static_cast(indexConstantUnion->getUConst(0)); } - else + + int safeIndex = -1; + + if (index < 0) { - int safeIndex = -1; + outOfRangeError(outOfRangeIndexIsError, location, "index expression is negative", "[]"); + safeIndex = 0; + } + if (!baseExpression->getType().isUnsizedArray()) + { if (baseExpression->isArray()) { if (baseExpression->getQualifier() == EvqFragData && index > 0) { - if (mShaderSpec == SH_WEBGL2_SPEC) + if (!isExtensionEnabled(TExtension::EXT_draw_buffers)) { - // 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, "", "[", + outOfRangeError(outOfRangeIndexIsError, location, "array index for gl_FragData must be zero when " - "GL_EXT_draw_buffers is disabled"); + "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()) + if (safeIndex < 0) { - std::stringstream extraInfoStream; - extraInfoStream << "array index out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str()); - safeIndex = baseExpression->getType().getArraySize() - 1; + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getOutermostArraySize(), + "array index out of range"); } } - else if ((baseExpression->isVector() || baseExpression->isMatrix()) && - baseExpression->getType().getNominalSize() <= index) + else if (baseExpression->isMatrix()) + { + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getType().getCols(), + "matrix field selection out of range"); + } + else if (baseExpression->isVector()) { - std::stringstream extraInfoStream; - extraInfoStream << "field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str()); - safeIndex = baseExpression->getType().getNominalSize() - 1; + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getType().getNominalSize(), + "vector field selection out of range"); } + ASSERT(safeIndex >= 0); // 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) + if (safeIndex != index || indexConstantUnion->getBasicType() != EbtInt) { TConstantUnion *safeConstantUnion = new TConstantUnion(); safeConstantUnion->setIConst(safeIndex); indexConstantUnion->replaceConstantUnion(safeConstantUnion); + indexConstantUnion->getTypePointer()->setBasicType(EbtInt); } - indexedExpression = - intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); + TIntermBinary *node = + new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression); + node->setLine(location); + return node->fold(mDiagnostics); } } - else - { - indexedExpression = - intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); - } - if (indexedExpression == 0) - { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setFConst(0.0f); - indexedExpression = - intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location); - } - else if (baseExpression->isArray()) - { - TType indexedType = baseExpression->getType(); - indexedType.clearArrayness(); - indexedExpression->setType(indexedType); - } - else if (baseExpression->isMatrix()) - { - indexedExpression->setType(TType(baseExpression->getBasicType(), - baseExpression->getPrecision(), EvqTemporary, - static_cast(baseExpression->getRows()))); - } - else if (baseExpression->isVector()) - { - indexedExpression->setType( - TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary)); - } - else - { - indexedExpression->setType(baseExpression->getType()); - } + TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression); + node->setLine(location); + // Indirect indexing can never be constant folded. + return node; +} - if (baseExpression->getType().getQualifier() == EvqConst && - indexExpression->getType().getQualifier() == EvqConst) - { - indexedExpression->getTypePointer()->setQualifier(EvqConst); - } - else +int TParseContext::checkIndexLessThan(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason) +{ + // Should not reach here with an unsized / runtime-sized array. + ASSERT(arraySize > 0); + if (index >= arraySize) { - indexedExpression->getTypePointer()->setQualifier(EvqTemporary); + std::stringstream reasonStream; + reasonStream << reason << " '" << index << "'"; + std::string token = reasonStream.str(); + outOfRangeError(outOfRangeIndexIsError, location, reason, "[]"); + return arraySize - 1; } - - return indexedExpression; + return index; } TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, @@ -2967,62 +4108,37 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre const TString &fieldString, const TSourceLoc &fieldLocation) { - TIntermTyped *indexedExpression = NULL; - if (baseExpression->isArray()) { error(fieldLocation, "cannot apply dot operator to an array", "."); - recover(); + return baseExpression; } if (baseExpression->isVector()) { - TVectorFields fields; - if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, - fieldLocation)) + TVector fieldOffsets; + if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(), + &fieldOffsets)) { - fields.num = 1; - fields.offsets[0] = 0; - recover(); + fieldOffsets.resize(1); + fieldOffsets[0] = 0; } + TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets); + node->setLine(dotLocation); - if (baseExpression->getAsConstantUnion()) - { - // constant folding for vector fields - indexedExpression = addConstVectorNode(fields, baseExpression->getAsConstantUnion(), - fieldLocation, true); - } - else - { - TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation); - indexedExpression = - intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation); - } - if (indexedExpression == nullptr) - { - recover(); - indexedExpression = baseExpression; - } - else - { - // Note that the qualifier set here will be corrected later. - indexedExpression->setType(TType(baseExpression->getBasicType(), - baseExpression->getPrecision(), EvqTemporary, - (unsigned char)(fieldString).size())); - } + return node->fold(); } else if (baseExpression->getBasicType() == EbtStruct) { - bool fieldFound = false; const TFieldList &fields = baseExpression->getType().getStruct()->fields(); if (fields.empty()) { error(dotLocation, "structure has no fields", "Internal Error"); - recover(); - indexedExpression = baseExpression; + return baseExpression; } else { + bool fieldFound = false; unsigned int i; for (i = 0; i < fields.size(); ++i) { @@ -3034,50 +4150,31 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre } if (fieldFound) { - if (baseExpression->getAsConstantUnion()) - { - indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation); - if (indexedExpression == 0) - { - recover(); - indexedExpression = baseExpression; - } - else - { - indexedExpression->setType(*fields[i]->type()); - } - } - else - { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped *index = intermediate.addConstantUnion( - unionArray, *fields[i]->type(), fieldLocation); - indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, - index, dotLocation); - indexedExpression->setType(*fields[i]->type()); - } + TIntermTyped *index = CreateIndexNode(i); + index->setLine(fieldLocation); + TIntermBinary *node = + new TIntermBinary(EOpIndexDirectStruct, baseExpression, index); + node->setLine(dotLocation); + return node->fold(mDiagnostics); } else { error(dotLocation, " no such field in structure", fieldString.c_str()); - recover(); - indexedExpression = baseExpression; + return baseExpression; } } } else if (baseExpression->isInterfaceBlock()) { - bool fieldFound = false; const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); if (fields.empty()) { error(dotLocation, "interface block has no fields", "Internal Error"); - recover(); - indexedExpression = baseExpression; + return baseExpression; } else { + bool fieldFound = false; unsigned int i; for (i = 0; i < fields.size(); ++i) { @@ -3089,19 +4186,18 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre } if (fieldFound) { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped *index = - intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); - indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, - baseExpression, index, dotLocation); - indexedExpression->setType(*fields[i]->type()); + TIntermTyped *index = CreateIndexNode(i); + index->setLine(fieldLocation); + TIntermBinary *node = + new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index); + node->setLine(dotLocation); + // Indexing interface blocks can never be constant folded. + return node; } else { error(dotLocation, " no such field in interface block", fieldString.c_str()); - recover(); - indexedExpression = baseExpression; + return baseExpression; } } } @@ -3109,265 +4205,608 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre { if (mShaderVersion < 300) { - error(dotLocation, " field selection requires structure or vector 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, or interface block on left hand " + "side", + fieldString.c_str()); + } + return baseExpression; + } +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine) +{ + TLayoutQualifier qualifier = TLayoutQualifier::Create(); + + if (qualifierType == "shared") + { + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared"); + } + qualifier.blockStorage = EbsShared; + } + else if (qualifierType == "packed") + { + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed"); + } + qualifier.blockStorage = EbsPacked; + } + else if (qualifierType == "std430") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.blockStorage = EbsStd430; + } + else if (qualifierType == "std140") + { + qualifier.blockStorage = EbsStd140; + } + else if (qualifierType == "row_major") + { + qualifier.matrixPacking = EmpRowMajor; + } + else if (qualifierType == "column_major") + { + qualifier.matrixPacking = EmpColumnMajor; + } + else if (qualifierType == "location") + { + error(qualifierTypeLine, "invalid layout qualifier: location requires an argument", + qualifierType.c_str()); + } + else if (qualifierType == "yuv" && mShaderType == GL_FRAGMENT_SHADER) + { + if (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_YUV_target)) + { + qualifier.yuv = true; + } + } + else if (qualifierType == "rgba32f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32F; + } + else if (qualifierType == "rgba16f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16F; + } + else if (qualifierType == "r32f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32F; + } + else if (qualifierType == "rgba8") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8; + } + else if (qualifierType == "rgba8_snorm") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8_SNORM; + } + else if (qualifierType == "rgba32i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32I; + } + else if (qualifierType == "rgba16i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16I; + } + else if (qualifierType == "rgba8i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8I; + } + else if (qualifierType == "r32i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32I; + } + else if (qualifierType == "rgba32ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32UI; + } + else if (qualifierType == "rgba16ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16UI; + } + else if (qualifierType == "rgba8ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8UI; + } + else if (qualifierType == "r32ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32UI; + } + else if (qualifierType == "points" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptPoints; + } + else if (qualifierType == "lines" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLines; + } + else if (qualifierType == "lines_adjacency" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLinesAdjacency; + } + else if (qualifierType == "triangles" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTriangles; + } + else if (qualifierType == "triangles_adjacency" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTrianglesAdjacency; + } + else if (qualifierType == "line_strip" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLineStrip; + } + else if (qualifierType == "triangle_strip" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTriangleStrip; + } + + else + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); + } + + return qualifier; +} + +void TParseContext::parseLocalSize(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize) +{ + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 1) + { + std::stringstream reasonStream; + reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive"; + std::string reason = reasonStream.str(); + error(intValueLine, reason.c_str(), intValueString.c_str()); + } + (*localSize)[index] = intValue; +} + +void TParseContext::parseNumViews(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numViews) +{ + // This error is only specified in WebGL, but tightens unspecified behavior in the native + // specification. + if (intValue < 1) + { + error(intValueLine, "out of range: num_views must be positive", intValueString.c_str()); + } + *numViews = intValue; +} + +void TParseContext::parseInvocations(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numInvocations) +{ + // Although SPEC isn't clear whether invocations can be less than 1, we add this limit because + // it doesn't make sense to accept invocations <= 0. + if (intValue < 1 || intValue > mMaxGeometryShaderInvocations) + { + error(intValueLine, + "out of range: invocations must be in the range of [1, " + "MAX_GEOMETRY_SHADER_INVOCATIONS_OES]", + intValueString.c_str()); + } + else + { + *numInvocations = intValue; + } +} + +void TParseContext::parseMaxVertices(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *maxVertices) +{ + // Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because + // it doesn't make sense to accept max_vertices < 0. + if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices) + { + error( + intValueLine, + "out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]", + intValueString.c_str()); + } + else + { + *maxVertices = intValue; + } +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine) +{ + TLayoutQualifier qualifier = TLayoutQualifier::Create(); + + std::string intValueString = Str(intValue); + + if (qualifierType == "location") + { + // must check that location is non-negative + if (intValue < 0) + { + error(intValueLine, "out of range: location must be non-negative", + intValueString.c_str()); + } + else + { + qualifier.location = intValue; + qualifier.locationsSpecified = 1; + } + } + else if (qualifierType == "binding") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 0) + { + error(intValueLine, "out of range: binding must be non-negative", + intValueString.c_str()); + } + else + { + qualifier.binding = intValue; + } + } + else if (qualifierType == "offset") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 0) + { + error(intValueLine, "out of range: offset must be non-negative", + intValueString.c_str()); } else { - error(dotLocation, - " field selection requires structure, vector, or interface block on left hand " - "side", - fieldString.c_str()); + qualifier.offset = intValue; } - 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 qualifier; - - qualifier.location = -1; - qualifier.matrixPacking = EmpUnspecified; - qualifier.blockStorage = EbsUnspecified; - - if (qualifierType == "shared") + else if (qualifierType == "local_size_x") { - qualifier.blockStorage = EbsShared; + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u, + &qualifier.localSize); } - else if (qualifierType == "packed") + else if (qualifierType == "local_size_y") { - qualifier.blockStorage = EbsPacked; + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u, + &qualifier.localSize); } - else if (qualifierType == "std140") + else if (qualifierType == "local_size_z") { - qualifier.blockStorage = EbsStd140; + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, + &qualifier.localSize); } - else if (qualifierType == "row_major") + else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER) { - qualifier.matrixPacking = EmpRowMajor; + if (checkCanUseExtension(qualifierTypeLine, TExtension::OVR_multiview)) + { + parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews); + } } - else if (qualifierType == "column_major") + else if (qualifierType == "invocations" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) { - qualifier.matrixPacking = EmpColumnMajor; + parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations); } - else if (qualifierType == "location") + else if (qualifierType == "max_vertices" && mShaderType == GL_GEOMETRY_SHADER_OES && + checkCanUseExtension(qualifierTypeLine, TExtension::OES_geometry_shader)) { - error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), - "location requires an argument"); - recover(); + parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices); } + else { error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); - recover(); } return qualifier; } -TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, - const TSourceLoc &qualifierTypeLine, - const TString &intValueString, - int intValue, - const TSourceLoc &intValueLine) +TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc) { - TLayoutQualifier qualifier; + return new TTypeQualifierBuilder( + new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc), + mShaderVersion); +} - qualifier.location = -1; - qualifier.matrixPacking = EmpUnspecified; - qualifier.blockStorage = EbsUnspecified; +TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier, + const TSourceLoc &loc) +{ + checkIsAtGlobalLevel(loc, getQualifierString(qualifier)); + return new TStorageQualifierWrapper(qualifier, loc); +} - if (qualifierType != "location") +TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc) +{ + if (getShaderType() == GL_VERTEX_SHADER) { - error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), - "only location may have arguments"); - recover(); + return parseGlobalStorageQualifier(EvqVaryingOut, loc); } - else + return parseGlobalStorageQualifier(EvqVaryingIn, loc); +} + +TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) +{ + if (declaringFunction()) { - // must check that location is non-negative - if (intValue < 0) + return new TStorageQualifierWrapper(EvqIn, loc); + } + + switch (getShaderType()) + { + case GL_VERTEX_SHADER: { - error(intValueLine, "out of range:", intValueString.c_str(), - "location must be non-negative"); - recover(); + if (mShaderVersion < 300 && !isExtensionEnabled(TExtension::OVR_multiview)) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); + } + return new TStorageQualifierWrapper(EvqVertexIn, loc); } - else + case GL_FRAGMENT_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); + } + return new TStorageQualifierWrapper(EvqFragmentIn, loc); + } + case GL_COMPUTE_SHADER: + { + return new TStorageQualifierWrapper(EvqComputeIn, loc); + } + case GL_GEOMETRY_SHADER_OES: + { + return new TStorageQualifierWrapper(EvqGeometryIn, loc); + } + default: { - qualifier.location = intValue; + UNREACHABLE(); + return new TStorageQualifierWrapper(EvqLast, loc); } } - - return qualifier; } -TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, - TLayoutQualifier rightQualifier) +TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc) { - TLayoutQualifier joinedQualifier = leftQualifier; - - if (rightQualifier.location != -1) + if (declaringFunction()) { - joinedQualifier.location = rightQualifier.location; + return new TStorageQualifierWrapper(EvqOut, loc); } - if (rightQualifier.matrixPacking != EmpUnspecified) + switch (getShaderType()) { - joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + case GL_VERTEX_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); + } + return new TStorageQualifierWrapper(EvqVertexOut, loc); + } + case GL_FRAGMENT_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); + } + return new TStorageQualifierWrapper(EvqFragmentOut, loc); + } + case GL_COMPUTE_SHADER: + { + error(loc, "storage qualifier isn't supported in compute shaders", "out"); + return new TStorageQualifierWrapper(EvqLast, loc); + } + case GL_GEOMETRY_SHADER_OES: + { + return new TStorageQualifierWrapper(EvqGeometryOut, loc); + } + default: + { + UNREACHABLE(); + return new TStorageQualifierWrapper(EvqLast, loc); + } } - if (rightQualifier.blockStorage != EbsUnspecified) +} + +TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc) +{ + if (!declaringFunction()) { - joinedQualifier.blockStorage = rightQualifier.blockStorage; + error(loc, "invalid qualifier: can be only used with function parameters", "inout"); } + return new TStorageQualifierWrapper(EvqInOut, loc); +} - return joinedQualifier; +TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation) +{ + return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation, + mDiagnostics); } -TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, - TQualifier interpolationQualifier, - const TSourceLoc &storageLoc, - TQualifier storageQualifier) +TField *TParseContext::parseStructDeclarator(TString *identifier, const TSourceLoc &loc) { - TQualifier mergedQualifier = EvqSmoothIn; + checkIsNotReserved(loc, *identifier); + TType *type = new TType(EbtVoid, EbpUndefined); + return new TField(type, identifier, loc); +} - if (storageQualifier == EvqFragmentIn) - { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqSmoothIn; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatIn; - else - UNREACHABLE(); - } - else if (storageQualifier == EvqCentroidIn) +TField *TParseContext::parseStructArrayDeclarator(TString *identifier, + const TSourceLoc &loc, + const TVector &arraySizes, + const TSourceLoc &arraySizeLoc) +{ + checkIsNotReserved(loc, *identifier); + + TType *type = new TType(EbtVoid, EbpUndefined); + type->makeArrays(arraySizes); + + return new TField(type, identifier, loc); +} + +void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, + const TFieldList::const_iterator end, + const TString &name, + const TSourceLoc &location) +{ + for (auto fieldIter = begin; fieldIter != end; ++fieldIter) { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqCentroidIn; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatIn; - else - UNREACHABLE(); + if ((*fieldIter)->name() == name) + { + error(location, "duplicate field name in structure", name.c_str()); + } } - else if (storageQualifier == EvqVertexOut) +} + +TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location) +{ + for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end(); + ++fieldIter) { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqSmoothOut; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatOut; - else - UNREACHABLE(); + checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(), + location); } - else if (storageQualifier == EvqCentroidOut) + return fields; +} + +TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields, + const TFieldList *newlyAddedFields, + const TSourceLoc &location) +{ + for (TField *field : *newlyAddedFields) { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqCentroidOut; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatOut; - else - UNREACHABLE(); + checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(), + field->name(), location); + processedFields->push_back(field); } - else - { - error(interpolationLoc, - "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", - getInterpolationString(interpolationQualifier)); - recover(); + return processedFields; +} - mergedQualifier = storageQualifier; - } +TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + TFieldList *fieldList) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); - TPublicType type; - type.setBasic(EbtVoid, mergedQualifier, storageLoc); - return type; + typeSpecifier->qualifier = typeQualifier.qualifier; + typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier; + typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier; + typeSpecifier->invariant = typeQualifier.invariant; + if (typeQualifier.precision != EbpUndefined) + { + typeSpecifier->precision = typeQualifier.precision; + } + return addStructDeclaratorList(*typeSpecifier, fieldList); } TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, - TFieldList *fieldList) + TFieldList *declaratorList) { - if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type)) - { - recover(); - } + checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, + typeSpecifier.getBasicType()); - for (unsigned int i = 0; i < fieldList->size(); ++i) - { - // - // Careful not to replace already known aspects of type, like array-ness - // - TType *type = (*fieldList)[i]->type(); - type->setBasicType(typeSpecifier.type); - type->setPrimarySize(typeSpecifier.primarySize); - type->setSecondarySize(typeSpecifier.secondarySize); - type->setPrecision(typeSpecifier.precision); - type->setQualifier(typeSpecifier.qualifier); - type->setLayoutQualifier(typeSpecifier.layoutQualifier); + checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(), + typeSpecifier.getBasicType()); - // don't allow arrays of arrays - if (type->isArray()) - { - if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier)) - recover(); - } - if (typeSpecifier.array) - type->setArraySize(typeSpecifier.arraySize); - if (typeSpecifier.userDef) + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); + + for (TField *declarator : *declaratorList) + { + // Don't allow arrays of arrays in ESSL < 3.10. + if (declarator->type()->isArray()) { - type->setStruct(typeSpecifier.userDef->getStruct()); + checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier); } - if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) + auto *declaratorArraySizes = declarator->type()->getArraySizes(); + + TType *type = declarator->type(); + *type = TType(typeSpecifier); + if (declaratorArraySizes != nullptr) { - recover(); + for (unsigned int arraySize : *declaratorArraySizes) + { + type->makeArray(arraySize); + } } + + checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *declarator); } - return fieldList; + return declaratorList; } -TPublicType TParseContext::addStructure(const TSourceLoc &structLine, - const TSourceLoc &nameLine, - const TString *structName, - TFieldList *fieldList) +TTypeSpecifierNonArray 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(&symbolTable, structName, fieldList); // Store a bool in the struct if we're at global scope, to allow us to // skip the local struct scoping workaround in HLSL. - structure->setUniqueId(TSymbolTable::nextUniqueId()); structure->setAtGlobalScope(symbolTable.atGlobalLevel()); if (!structName->empty()) { - if (reservedErrorCheck(nameLine, *structName)) + checkIsNotReserved(nameLine, *structName); + if (!symbolTable.declareStructType(structure)) { - recover(); - } - TVariable *userTypeDef = new TVariable(structName, *structureType, true); - if (!symbolTable.declare(userTypeDef)) - { - error(nameLine, "redefinition", structName->c_str(), "struct"); - recover(); + error(nameLine, "redefinition of a struct", structName->c_str()); } } // 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]; + TField &field = *(*fieldList)[typeListIndex]; const TQualifier qualifier = field.type()->getQualifier(); switch (qualifier) { @@ -3377,22 +4816,37 @@ TPublicType TParseContext::addStructure(const TSourceLoc &structLine, default: error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier)); - recover(); break; } + if (field.type()->isInvariant()) + { + error(field.line(), "invalid qualifier on struct member", "invariant"); + } + // ESSL 3.10 section 4.1.8 -- atomic_uint or images are not allowed as structure member. + if (IsImage(field.type()->getBasicType()) || IsAtomicCounter(field.type()->getBasicType())) + { + error(field.line(), "disallowed type in struct", field.type()->getBasicString()); + } + + checkIsNotUnsizedArray(field.line(), "array members of structs must specify a size", + field.name().c_str(), field.type()); + + checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line()); + + checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding); + + checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); } - TPublicType publicType; - publicType.setBasic(EbtStruct, EvqTemporary, structLine); - publicType.userDef = structureType; - publicType.isStructSpecifier = true; + TTypeSpecifierNonArray typeSpecifierNonArray; + typeSpecifierNonArray.initializeStruct(structure, true, structLine); exitStructDeclaration(); - return publicType; + return typeSpecifierNonArray; } TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, - TIntermAggregate *statementList, + TIntermBlock *statementList, const TSourceLoc &loc) { TBasicType switchType = init->getBasicType(); @@ -3401,26 +4855,18 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, { error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch"); - recover(); return nullptr; } - if (statementList) - { - if (!ValidateSwitch::validate(switchType, this, statementList, loc)) - { - recover(); - return nullptr; - } - } - - TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc); - if (node == nullptr) + ASSERT(statementList); + if (!ValidateSwitchStatementList(switchType, mShaderVersion, mDiagnostics, statementList, loc)) { - error(loc, "erroneous switch statement", "switch"); - recover(); + ASSERT(mDiagnostics->numErrors() > 0); return nullptr; } + + TIntermSwitch *node = new TIntermSwitch(init, statementList); + node->setLine(loc); return node; } @@ -3429,20 +4875,17 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l if (mSwitchNestingLevel == 0) { error(loc, "case labels need to be inside switch statements", "case"); - recover(); return nullptr; } if (condition == nullptr) { error(loc, "case label must have a condition", "case"); - recover(); return nullptr; } if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || condition->isMatrix() || condition->isArray() || condition->isVector()) { error(condition->getLine(), "case label must be a scalar integer", "case"); - recover(); } TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant @@ -3451,15 +4894,9 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l if (condition->getQualifier() != EvqConst || conditionConst == nullptr) { error(condition->getLine(), "case label must be constant", "case"); - recover(); - } - TIntermCase *node = intermediate.addCase(condition, loc); - if (node == nullptr) - { - error(loc, "erroneous case statement", "case"); - recover(); - return nullptr; } + TIntermCase *node = new TIntermCase(condition); + node->setLine(loc); return node; } @@ -3468,28 +4905,18 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) if (mSwitchNestingLevel == 0) { error(loc, "default labels need to be inside switch statements", "default"); - recover(); - return nullptr; - } - TIntermCase *node = intermediate.addCase(nullptr, loc); - if (node == nullptr) - { - error(loc, "erroneous default statement", "default"); - recover(); return nullptr; } + TIntermCase *node = new TIntermCase(nullptr); + node->setLine(loc); return node; } TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, - const TSourceLoc &loc, - const TType *funcReturnType) + const TSourceLoc &loc) { - if (child == nullptr) - { - return nullptr; - } + ASSERT(child != nullptr); switch (op) { @@ -3497,6 +4924,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() || child->isVector()) { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); return nullptr; } break; @@ -3504,6 +4932,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || child->isMatrix() || child->isArray()) { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); return nullptr; } break; @@ -3513,9 +4942,11 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, case EOpPreDecrement: case EOpNegative: case EOpPositive: - if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool || - child->isArray()) + if (child->getBasicType() == EbtStruct || child->isInterfaceBlock() || + child->getBasicType() == EbtBool || child->isArray() || + IsOpaqueType(child->getBasicType())) { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); return nullptr; } // Operators for built-ins are already type checked against their prototype. @@ -3523,49 +4954,134 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, break; } - return intermediate.addUnaryMath(op, child, loc, funcReturnType); -} - -TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) -{ - TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); - if (node == nullptr) + if (child->getMemoryQualifier().writeonly) + { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); + return nullptr; + } + + TIntermUnary *node = new TIntermUnary(op, child); + node->setLine(loc); + + return node->fold(mDiagnostics); +} + +TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + ASSERT(op != EOpNull); + TIntermTyped *node = createUnaryMath(op, child, loc); + if (node == nullptr) + { + return child; + } + return node; +} + +TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, + TIntermTyped *child, + const TSourceLoc &loc) +{ + checkCanBeLValue(loc, GetOperatorString(op), child); + return addUnaryMath(op, child, loc); +} + +bool TParseContext::binaryOpCommonCheck(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + // Check opaque types are not allowed to be operands in expressions other than array indexing + // and structure member selection. + if (IsOpaqueType(left->getBasicType()) || IsOpaqueType(right->getBasicType())) + { + switch (op) + { + case EOpIndexDirect: + case EOpIndexIndirect: + break; + case EOpIndexDirectStruct: + UNREACHABLE(); + + default: + error(loc, "Invalid operation for variables with an opaque type", + GetOperatorString(op)); + return false; + } + } + + if (right->getMemoryQualifier().writeonly) + { + error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); + return false; + } + + if (left->getMemoryQualifier().writeonly) + { + switch (op) + { + case EOpAssign: + case EOpInitialize: + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + break; + default: + error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); + return false; + } + } + + if (left->getType().getStruct() || right->getType().getStruct()) + { + switch (op) + { + case EOpIndexDirectStruct: + ASSERT(left->getType().getStruct()); + break; + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + if (left->getType() != right->getType()) + { + return false; + } + break; + default: + error(loc, "Invalid operation for structs", GetOperatorString(op)); + return false; + } + } + + if (left->isInterfaceBlock() || right->isInterfaceBlock()) + { + switch (op) + { + case EOpIndexDirectInterfaceBlock: + ASSERT(left->getType().getInterfaceBlock()); + break; + default: + error(loc, "Invalid operation for interface blocks", GetOperatorString(op)); + return false; + } + } + + if (left->isArray() != right->isArray()) { - unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); - recover(); - return child; + error(loc, "array / non-array mismatch", GetOperatorString(op)); + return false; } - return node; -} - -TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, - TIntermTyped *child, - const TSourceLoc &loc) -{ - if (lValueErrorCheck(loc, GetOperatorString(op), child)) - recover(); - return addUnaryMath(op, child, loc); -} -bool TParseContext::binaryOpCommonCheck(TOperator op, - TIntermTyped *left, - TIntermTyped *right, - const TSourceLoc &loc) -{ - if (left->isArray() || right->isArray()) + if (left->isArray()) { + ASSERT(right->isArray()); if (mShaderVersion < 300) { error(loc, "Invalid operation for arrays", GetOperatorString(op)); return false; } - if (left->isArray() != right->isArray()) - { - error(loc, "array / non-array mismatch", GetOperatorString(op)); - return false; - } - switch (op) { case EOpEqual: @@ -3578,7 +5094,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, return false; } // At this point, size of implicitly sized arrays should be resolved. - if (left->getArraySize() != right->getArraySize()) + if (*left->getType().getArraySizes() != *right->getType().getArraySizes()) { error(loc, "array size mismatch", GetOperatorString(op)); return false; @@ -3625,8 +5141,10 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, return false; } - // Check that type sizes match exactly on ops that require that. - // Also check restrictions for structs that contain arrays or samplers. + // Check that: + // 1. Type sizes match exactly on ops that require that. + // 2. Restrictions for structs that contain arrays or samplers are respected. + // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected. switch (op) { case EOpAssign: @@ -3650,15 +5168,65 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, GetOperatorString(op)); return false; } + + if ((left->getNominalSize() != right->getNominalSize()) || + (left->getSecondarySize() != right->getSecondarySize())) + { + error(loc, "dimension mismatch", GetOperatorString(op)); + return false; + } + break; case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - if ((left->getNominalSize() != right->getNominalSize()) || - (left->getSecondarySize() != right->getSecondarySize())) + if (!left->isScalar() || !right->isScalar()) + { + error(loc, "comparison operator only defined for scalars", GetOperatorString(op)); + return false; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) { return false; } + + // Are the sizes compatible? + if (left->getNominalSize() != right->getNominalSize() || + left->getSecondarySize() != right->getSecondarySize()) + { + // If the nominal sizes of operands do not match: + // One of them must be a scalar. + if (!left->isScalar() && !right->isScalar()) + return false; + + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if (!right->isScalar() && + (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) + return false; + } + break; default: break; } @@ -3666,6 +5234,49 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, return true; } +bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op, + const TType &left, + const TType &right) +{ + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && + left.getSecondarySize() == right.getSecondarySize(); + case EOpVectorTimesScalar: + return true; + case EOpVectorTimesScalarAssign: + ASSERT(!left.isMatrix() && !right.isMatrix()); + return left.isVector() && !right.isVector(); + case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + ASSERT(!left.isMatrix() && right.isMatrix()); + return left.isVector() && left.getNominalSize() == right.getRows() && + left.getNominalSize() == right.getCols(); + case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); + case EOpMatrixTimesScalar: + return true; + case EOpMatrixTimesScalarAssign: + ASSERT(left.isMatrix() && !right.isMatrix()); + return !right.isVector(); + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + ASSERT(left.isMatrix() && right.isMatrix()); + // We need to check two things: + // 1. The matrix multiplication step is valid. + // 2. The result will have the same number of columns as the lvalue. + return left.getCols() == right.getRows() && left.getCols() == right.getCols(); + + default: + UNREACHABLE(); + return false; + } +} + TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, @@ -3678,52 +5289,61 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator 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()) + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar()) { return nullptr; } + // Basic types matching should have been already checked. + ASSERT(right->getBasicType() == EbtBool); break; case EOpAdd: case EOpSub: case EOpDiv: case EOpMul: - ASSERT(!left->isArray() && !right->isArray()); - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->getBasicType() == EbtBool) { return nullptr; } break; case EOpIMod: - ASSERT(!left->isArray() && !right->isArray()); + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); // Note that this is only for the % operator, not for mod() - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || - left->getBasicType() == EbtFloat) + if (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); + if (op == EOpMul) + { + op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType()); + if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + return nullptr; + } + } + + TIntermBinary *node = new TIntermBinary(op, left, right); + node->setLine(loc); + + // See if we can fold constants. + return node->fold(mDiagnostics); } TIntermTyped *TParseContext::addBinaryMath(TOperator op, @@ -3736,7 +5356,6 @@ TIntermTyped *TParseContext::addBinaryMath(TOperator op, { binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); - recover(); return left; } return node; @@ -3748,27 +5367,35 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, const TSourceLoc &loc) { TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); - if (node == 0) + if (node == nullptr) { binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); - recover(); - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setBConst(false); - return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), - loc); + node = CreateBoolNode(false); + node->setLine(loc); } return node; } -TIntermTyped *TParseContext::createAssign(TOperator op, - TIntermTyped *left, - TIntermTyped *right, - const TSourceLoc &loc) +TIntermBinary *TParseContext::createAssign(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) { if (binaryOpCommonCheck(op, left, right, loc)) { - return intermediate.addAssign(op, left, right, loc); + if (op == EOpMulAssign) + { + op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType()); + if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + return nullptr; + } + } + TIntermBinary *node = new TIntermBinary(op, left, right); + node->setLine(loc); + + return node; } return nullptr; } @@ -3778,11 +5405,11 @@ TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *right, const TSourceLoc &loc) { + checkCanBeLValue(loc, "assign", left); TIntermTyped *node = createAssign(op, left, right, loc); if (node == nullptr) { assignError(loc, "assign", left->getCompleteString(), right->getCompleteString()); - recover(); return left; } return node; @@ -3792,7 +5419,22 @@ TIntermTyped *TParseContext::addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) { - return intermediate.addComma(left, right, loc, mShaderVersion); + // WebGL2 section 5.26, the following results in an error: + // "Sequence operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && + (left->isArray() || left->getBasicType() == EbtVoid || + left->getType().isStructureContainingArrays() || right->isArray() || + right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays())) + { + error(loc, + "sequence operator is not allowed for void, arrays, or structs containing arrays", + ","); + } + + TIntermBinary *commaNode = new TIntermBinary(EOpComma, left, right); + TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(mShaderVersion, left, right); + commaNode->getTypePointer()->setQualifier(resultQualifier); + return commaNode->fold(mDiagnostics); } TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) @@ -3803,319 +5445,553 @@ TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) 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; + case EOpKill: + if (mShaderType != GL_FRAGMENT_SHADER) + { + error(loc, "discard supported in fragment shaders only", "discard"); } break; default: - // No checks for discard + UNREACHABLE(); break; } - return intermediate.addBranch(op, loc); + return addBranch(op, nullptr, loc); } TIntermBranch *TParseContext::addBranch(TOperator op, - TIntermTyped *returnValue, + TIntermTyped *expression, const TSourceLoc &loc) { - ASSERT(op == EOpReturn); - mFunctionReturnsValue = true; - if (mCurrentFunctionType->getBasicType() == EbtVoid) + if (expression != nullptr) { - error(loc, "void function cannot return a value", "return"); - recover(); + ASSERT(op == EOpReturn); + mFunctionReturnsValue = true; + if (mCurrentFunctionType->getBasicType() == EbtVoid) + { + error(loc, "void function cannot return a value", "return"); + } + else if (*mCurrentFunctionType != expression->getType()) + { + error(loc, "function return is not matching type:", "return"); + } } - else if (*mCurrentFunctionType != returnValue->getType()) - { - error(loc, "function return is not matching type:", "return"); - recover(); + TIntermBranch *node = new TIntermBranch(op, expression); + node->setLine(loc); + return node; +} + +void TParseContext::checkTextureGather(TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + const TString &name = functionCall->getFunctionSymbolInfo()->getName(); + bool isTextureGather = (name == "textureGather"); + bool isTextureGatherOffset = (name == "textureGatherOffset"); + if (isTextureGather || isTextureGatherOffset) + { + TIntermNode *componentNode = nullptr; + TIntermSequence *arguments = functionCall->getSequence(); + ASSERT(arguments->size() >= 2u && arguments->size() <= 4u); + const TIntermTyped *sampler = arguments->front()->getAsTyped(); + ASSERT(sampler != nullptr); + switch (sampler->getBasicType()) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + if ((isTextureGather && arguments->size() == 3u) || + (isTextureGatherOffset && arguments->size() == 4u)) + { + componentNode = arguments->back(); + } + break; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + ASSERT(!isTextureGatherOffset); + if (arguments->size() == 3u) + { + componentNode = arguments->back(); + } + break; + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSamplerCubeShadow: + break; + default: + UNREACHABLE(); + break; + } + if (componentNode) + { + const TIntermConstantUnion *componentConstantUnion = + componentNode->getAsConstantUnion(); + if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion) + { + error(functionCall->getLine(), "Texture component must be a constant expression", + name.c_str()); + } + else + { + int component = componentConstantUnion->getIConst(0); + if (component < 0 || component > 3) + { + error(functionCall->getLine(), "Component must be in the range [0;3]", + name.c_str()); + } + } + } } - return intermediate.addBranch(op, returnValue, loc); } void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) { - ASSERT(!functionCall->isUserDefined()); - const TString &name = functionCall->getName(); + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + const TString &name = functionCall->getFunctionSymbolInfo()->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) + bool useTextureGatherOffsetConstraints = false; + if (name == "texelFetchOffset" || name == "textureLodOffset" || + name == "textureProjLodOffset" || name == "textureGradOffset" || + name == "textureProjGradOffset") { offset = arguments->back(); } - else if (name.compare(0, 13, "textureOffset") == 0 || - name.compare(0, 17, "textureProjOffset") == 0) + else if (name == "textureOffset" || name == "textureProjOffset") { // A bias parameter might follow the offset parameter. ASSERT(arguments->size() >= 3); offset = (*arguments)[2]; } + else if (name == "textureGatherOffset") + { + ASSERT(arguments->size() >= 3u); + const TIntermTyped *sampler = arguments->front()->getAsTyped(); + ASSERT(sampler != nullptr); + switch (sampler->getBasicType()) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + offset = (*arguments)[2]; + break; + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + offset = (*arguments)[3]; + break; + default: + UNREACHABLE(); + break; + } + useTextureGatherOffsetConstraints = true; + } 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(); + name.c_str()); } else { ASSERT(offsetConstantUnion->getBasicType() == EbtInt); size_t size = offsetConstantUnion->getType().getObjectSize(); const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer(); + int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset + : mMinProgramTexelOffset; + int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset + : mMaxProgramTexelOffset; for (size_t i = 0u; i < size; ++i) { int offsetValue = values[i].getIConst(); - if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset) + if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue) { 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) +void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall) { - *fatalError = false; - TOperator op = fnCall->getBuiltInOp(); - TIntermTyped *callNode = nullptr; - - if (thisNode != nullptr) + const TString &name = functionCall->getFunctionSymbolInfo()->getName(); + if (IsAtomicBuiltin(name)) { - TConstantUnion *unionArray = new TConstantUnion[1]; - int arraySize = 0; - TIntermTyped *typedThis = thisNode->getAsTyped(); - if (fnCall->getName() != "length") + TIntermSequence *arguments = functionCall->getSequence(); + TIntermTyped *memNode = (*arguments)[0]->getAsTyped(); + + if (IsBufferOrSharedVariable(memNode)) { - error(loc, "invalid method", fnCall->getName().c_str()); - recover(); + return; } - else if (paramNode != nullptr) + + while (memNode->getAsBinaryNode()) { - error(loc, "method takes no parameters", "length"); - recover(); + memNode = memNode->getAsBinaryNode()->getLeft(); + if (IsBufferOrSharedVariable(memNode)) + { + return; + } } - else if (typedThis == nullptr || !typedThis->isArray()) + + error(memNode->getLine(), + "The value passed to the mem argument of an atomic memory function does not " + "correspond to a buffer or shared variable.", + functionCall->getFunctionSymbolInfo()->getName().c_str()); + } +} + +// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers +void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + const TString &name = functionCall->getFunctionSymbolInfo()->getName(); + + if (name.compare(0, 5, "image") == 0) + { + TIntermSequence *arguments = functionCall->getSequence(); + TIntermTyped *imageNode = (*arguments)[0]->getAsTyped(); + + const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier(); + + if (name.compare(5, 5, "Store") == 0) { - error(loc, "length can only be called on arrays", "length"); - recover(); + if (memoryQualifier.readonly) + { + error(imageNode->getLine(), + "'imageStore' cannot be used with images qualified as 'readonly'", + GetImageArgumentToken(imageNode)); + } } - else + else if (name.compare(5, 4, "Load") == 0) { - arraySize = typedThis->getArraySize(); - if (typedThis->getAsSymbolNode() == nullptr) + if (memoryQualifier.writeonly) { - // 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(); + error(imageNode->getLine(), + "'imageLoad' cannot be used with images qualified as 'writeonly'", + GetImageArgumentToken(imageNode)); } } - unionArray->setIConst(arraySize); - callNode = - intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), loc); } - else if (op != EOpNull) +} + +// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters +void TParseContext::checkImageMemoryAccessForUserDefinedFunctions( + const TFunction *functionDefinition, + const TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallFunctionInAST); + + const TIntermSequence &arguments = *functionCall->getSequence(); + + ASSERT(functionDefinition->getParamCount() == arguments.size()); + + for (size_t i = 0; i < arguments.size(); ++i) { - // - // Then this should be a constructor. - // Don't go through the symbol table for constructors. - // Their parameters will be verified algorithmically. - // - TType type(EbtVoid, EbpUndefined); // use this to get the type back - if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type)) - { - // - // It's a constructor, of type 'type'. - // - callNode = addConstructor(paramNode, &type, op, fnCall, loc); - } + TIntermTyped *typedArgument = arguments[i]->getAsTyped(); + const TType &functionArgumentType = typedArgument->getType(); + const TType &functionParameterType = *functionDefinition->getParam(i).type; + ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType()); - if (callNode == nullptr) + if (IsImage(functionArgumentType.getBasicType())) { - recover(); - callNode = intermediate.setAggregateOperator(nullptr, op, loc); + const TMemoryQualifier &functionArgumentMemoryQualifier = + functionArgumentType.getMemoryQualifier(); + const TMemoryQualifier &functionParameterMemoryQualifier = + functionParameterType.getMemoryQualifier(); + if (functionArgumentMemoryQualifier.readonly && + !functionParameterMemoryQualifier.readonly) + { + error(functionCall->getLine(), + "Function call discards the 'readonly' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.writeonly && + !functionParameterMemoryQualifier.writeonly) + { + error(functionCall->getLine(), + "Function call discards the 'writeonly' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.coherent && + !functionParameterMemoryQualifier.coherent) + { + error(functionCall->getLine(), + "Function call discards the 'coherent' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.volatileQualifier && + !functionParameterMemoryQualifier.volatileQualifier) + { + error(functionCall->getLine(), + "Function call discards the 'volatile' qualifier from image", + GetImageArgumentToken(typedArgument)); + } } - callNode->setType(type); + } +} + +TIntermSequence *TParseContext::createEmptyArgumentsList() +{ + return new TIntermSequence(); +} + +TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, + TIntermSequence *arguments, + TIntermNode *thisNode, + const TSourceLoc &loc) +{ + if (thisNode != nullptr) + { + return addMethod(fnCall, arguments, thisNode, loc); + } + + TOperator op = fnCall->getBuiltInOp(); + if (op == EOpConstruct) + { + return addConstructor(arguments, fnCall->getReturnType(), loc); } else { - // - // Not a constructor. Find it in the symbol table. - // - const TFunction *fnCandidate; - bool builtIn; - fnCandidate = findFunction(loc, fnCall, mShaderVersion, &builtIn); - if (fnCandidate) + ASSERT(op == EOpNull); + return addNonConstructorFunctionCall(fnCall, arguments, loc); + } +} + +TIntermTyped *TParseContext::addMethod(TFunction *fnCall, + TIntermSequence *arguments, + TIntermNode *thisNode, + const TSourceLoc &loc) +{ + TIntermTyped *typedThis = thisNode->getAsTyped(); + // It's possible for the name pointer in the TFunction to be null in case it gets parsed as + // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS + // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead. + // So accessing fnCall->getName() below is safe. + if (fnCall->getName() != "length") + { + error(loc, "invalid method", fnCall->getName().c_str()); + } + else if (!arguments->empty()) + { + error(loc, "method takes no parameters", "length"); + } + else if (typedThis == nullptr || !typedThis->isArray()) + { + error(loc, "length can only be called on arrays", "length"); + } + else if (typedThis->getQualifier() == EvqPerVertexIn && + mGeometryShaderInputPrimitiveType == EptUndefined) + { + ASSERT(mShaderType == GL_GEOMETRY_SHADER_OES); + error(loc, "missing input primitive declaration before calling length on gl_in", "length"); + } + else + { + TIntermUnary *node = new TIntermUnary(EOpArrayLength, typedThis); + node->setLine(loc); + return node->fold(mDiagnostics); + } + return CreateZeroNode(TType(EbtInt, EbpUndefined, EvqConst)); +} + +TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall, + TIntermSequence *arguments, + const TSourceLoc &loc) +{ + // 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. + bool builtIn; + const TSymbol *symbol = symbolTable.find(fnCall->getName(), mShaderVersion, &builtIn); + if (symbol != nullptr && !symbol->isFunction()) + { + error(loc, "function name expected", fnCall->getName().c_str()); + } + else + { + symbol = symbolTable.find(TFunction::GetMangledNameFromCall(fnCall->getName(), *arguments), + mShaderVersion, &builtIn); + if (symbol == nullptr) + { + error(loc, "no matching overloaded function found", fnCall->getName().c_str()); + } + else { + const TFunction *fnCandidate = static_cast(symbol); // // A declared function. // - if (builtIn && !fnCandidate->getExtension().empty() && - extensionErrorCheck(loc, fnCandidate->getExtension())) + if (builtIn && fnCandidate->getExtension() != TExtension::UNDEFINED) { - recover(); + checkCanUseExtension(loc, fnCandidate->getExtension()); } - op = fnCandidate->getBuiltInOp(); + TOperator op = fnCandidate->getBuiltInOp(); if (builtIn && op != EOpNull) { - // // A function call mapped to a built-in operation. - // if (fnCandidate->getParamCount() == 1) { - // // Treat it like a built-in unary operator. - // - 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(paramNode)->getCompleteString(); - std::string extraInfo = extraInfoStream.str(); - error(paramNode->getLine(), " wrong operand type", "Internal Error", - extraInfo.c_str()); - *fatalError = true; - return nullptr; - } + TIntermNode *unaryParamNode = arguments->front(); + TIntermTyped *callNode = createUnaryMath(op, unaryParamNode->getAsTyped(), loc); + ASSERT(callNode != nullptr); + return callNode; } else { - TIntermAggregate *aggregate = - intermediate.setAggregateOperator(paramNode, op, loc); - aggregate->setType(fnCandidate->getReturnType()); - aggregate->setPrecisionFromChildren(); - if (aggregate->areChildrenConstQualified()) - { - aggregate->getTypePointer()->setQualifier(EvqConst); - } + TIntermAggregate *callNode = + TIntermAggregate::Create(fnCandidate->getReturnType(), op, arguments); + callNode->setLine(loc); // Some built-in functions have out parameters too. - functionCallLValueErrorCheck(fnCandidate, aggregate); + functionCallRValueLValueErrorCheck(fnCandidate, callNode); - // 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) + if (TIntermAggregate::CanFoldAggregateBuiltInOp(callNode->getOp())) { - callNode = foldedNode; + // See if we can constant fold a built-in. Note that this may be possible + // even if it is not const-qualified. + return callNode->fold(mDiagnostics); } else { - callNode = aggregate; + return callNode; } } } else { // This is a real function call - 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 - // 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 + TIntermAggregate *callNode = nullptr; + + // If builtIn == false, the function is user defined - could be an overloaded + // built-in as well. + // if builtIn == true, it's a builtIn function with no op associated with it. + // This needs to happen after the function info including name is set. if (builtIn) { - aggregate->setBuiltInFunctionPrecision(); - - checkTextureOffsetConst(aggregate); + callNode = TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, arguments); + checkTextureOffsetConst(callNode); + checkTextureGather(callNode); + checkImageMemoryAccessForBuiltinFunctions(callNode); + checkAtomicMemoryBuiltinFunctions(callNode); + } + else + { + callNode = TIntermAggregate::CreateFunctionCall(*fnCandidate, arguments); + checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); } - callNode = aggregate; + functionCallRValueLValueErrorCheck(fnCandidate, callNode); + + callNode->setLine(loc); - functionCallLValueErrorCheck(fnCandidate, aggregate); + return callNode; } } - else - { - // error message was put out by findFunction() - // Put on a dummy node for error recovery - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setFConst(0.0f); - callNode = intermediate.addConstantUnion(unionArray, - TType(EbtFloat, EbpUndefined, EvqConst), loc); - recover(); - } } - return callNode; + + // Error message was already written. Put on a dummy node for error recovery. + return CreateZeroNode(TType(EbtFloat, EbpMedium, EvqConst)); } TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, - TIntermTyped *trueBlock, - TIntermTyped *falseBlock, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, const TSourceLoc &loc) { - if (boolErrorCheck(loc, cond)) - recover(); + if (!checkIsScalarBool(loc, cond)) + { + return falseExpression; + } - if (trueBlock->getType() != falseBlock->getType()) + if (trueExpression->getType() != falseExpression->getType()) { - binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString()); - recover(); - return falseBlock; + std::stringstream reasonStream; + reasonStream << "mismatching ternary operator operand types '" + << trueExpression->getCompleteString() << " and '" + << falseExpression->getCompleteString() << "'"; + std::string reason = reasonStream.str(); + error(loc, reason.c_str(), "?:"); + return falseExpression; + } + if (IsOpaqueType(trueExpression->getBasicType())) + { + // ESSL 1.00 section 4.1.7 + // ESSL 3.00.6 section 4.1.7 + // Opaque/sampler types are not allowed in most types of expressions, including ternary. + // Note that structs containing opaque types don't need to be checked as structs are + // forbidden below. + error(loc, "ternary operator is not allowed for opaque types", "?:"); + return falseExpression; } - // ESSL1 sections 5.2 and 5.7: - // ESSL3 section 5.7: + + if (cond->getMemoryQualifier().writeonly || trueExpression->getMemoryQualifier().writeonly || + falseExpression->getMemoryQualifier().writeonly) + { + error(loc, "ternary operator is not allowed for variables with writeonly", "?:"); + return falseExpression; + } + + // ESSL 1.00.17 sections 5.2 and 5.7: // Ternary operator is not among the operators allowed for structures/arrays. - if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct) + // ESSL 3.00.6 section 5.7: + // Ternary operator support is optional for arrays. No certainty that it works across all + // devices with struct either, so we err on the side of caution here. TODO (oetuaho@nvidia.com): + // Would be nice to make the spec and implementation agree completely here. + if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct) { - error(loc, "ternary operator is not allowed for structures or arrays", ":"); - recover(); - return falseBlock; + error(loc, "ternary operator is not allowed for structures or arrays", "?:"); + return falseExpression; } - return intermediate.addSelection(cond, trueBlock, falseBlock, loc); + if (trueExpression->getBasicType() == EbtInterfaceBlock) + { + error(loc, "ternary operator is not allowed for interface blocks", "?:"); + return falseExpression; + } + + // WebGL2 section 5.26, the following results in an error: + // "Ternary operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid) + { + error(loc, "ternary operator is not allowed for void", "?:"); + return falseExpression; + } + + // Note that the node resulting from here can be a constant union without being qualified as + // constant. + TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression); + node->setLine(loc); + + return node->fold(); } // @@ -4128,7 +6004,7 @@ int PaParseStrings(size_t count, const int length[], TParseContext *context) { - if ((count == 0) || (string == NULL)) + if ((count == 0) || (string == nullptr)) return 1; if (glslang_initialize(context)) @@ -4142,3 +6018,5 @@ int PaParseStrings(size_t count, return (error == 0) && (context->numErrors() == 0) ? 0 : 1; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.h b/src/3rdparty/angle/src/compiler/translator/ParseContext.h index 1eaf1e5b42..8bfdbd5e3f 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h @@ -9,10 +9,13 @@ #include "compiler/translator/Compiler.h" #include "compiler/translator/Diagnostics.h" #include "compiler/translator/DirectiveHandler.h" -#include "compiler/translator/Intermediate.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/QualifierTypes.h" #include "compiler/preprocessor/Preprocessor.h" +namespace sh +{ + struct TMatrixFields { bool wholeRow; @@ -30,44 +33,13 @@ class TParseContext : angle::NonCopyable public: TParseContext(TSymbolTable &symt, TExtensionBehavior &ext, - TIntermediate &interm, sh::GLenum type, ShShaderSpec spec, - int options, + ShCompileOptions 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) - { - } + TDiagnostics *diagnostics, + const ShBuiltInResources &resources); + ~TParseContext(); const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; } pp::Preprocessor &getPreprocessor() { return mPreprocessor; } @@ -76,23 +48,18 @@ class TParseContext : angle::NonCopyable 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=""); + int numErrors() const { return mDiagnostics->numErrors(); } + void error(const TSourceLoc &loc, const char *reason, const char *token); + void warning(const TSourceLoc &loc, const char *reason, const char *token); // 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 = ""); + const char *token); - void recover(); - TIntermNode *getTreeRoot() const { return mTreeRoot; } - void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; } + TIntermBlock *getTreeRoot() const { return mTreeRoot; } + void setTreeRoot(TIntermBlock *treeRoot) { mTreeRoot = treeRoot; } bool getFragmentPrecisionHigh() const { @@ -103,10 +70,7 @@ class TParseContext : angle::NonCopyable mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh; } - void setLoopNestingLevel(int loopNestintLevel) - { - mLoopNestingLevel = loopNestintLevel; - } + void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; } void incrLoopNestingLevel() { ++mLoopNestingLevel; } void decrLoopNestingLevel() { --mLoopNestingLevel; } @@ -114,279 +78,580 @@ class TParseContext : angle::NonCopyable void incrSwitchNestingLevel() { ++mSwitchNestingLevel; } void decrSwitchNestingLevel() { --mSwitchNestingLevel; } + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + sh::WorkGroupSize getComputeShaderLocalSize() const; + + int getNumViews() const { return mNumViews; } + + void enterFunctionDeclaration() { mDeclaringFunction = true; } + + void exitFunctionDeclaration() { mDeclaringFunction = false; } + + bool declaringFunction() const { return mDeclaringFunction; } + + TIntermConstantUnion *addScalarLiteral(const TConstantUnion *constantUnion, + const TSourceLoc &line); + // 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); + 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); + // Look at a '.' field selector string and change it into offsets for a vector. + bool parseVectorFields(const TSourceLoc &line, + const TString &compString, + int vecSize, + TVector *fieldOffsets); - 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 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); + // Check functions - the ones that return bool return false if an error was generated. + + bool checkIsNotReserved(const TSourceLoc &line, const TString &identifier); + void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type); + bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node); + void checkIsConst(TIntermTyped *node); + void checkIsScalarInteger(TIntermTyped *node, const char *token); + bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token); + bool checkConstructorArguments(const TSourceLoc &line, + const TIntermSequence *arguments, + const TType &type); + + // Returns a sanitized array size to use (the size is at least 1). + unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr); + bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier); + bool checkArrayElementIsNotArray(const TSourceLoc &line, const TPublicType &elementType); + bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type); + bool checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type); + void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType); + bool checkIsNotOpaqueType(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, + const char *reason); + void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType); + void checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + void checkStd430IsForShaderStorageBlock(const TSourceLoc &location, + const TLayoutBlockStorage &blockStorage, + const TQualifier &qualifier); + void checkIsParameterQualifierValid(const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type); + + // Check if at least one of the specified extensions can be used, and generate error/warning as + // appropriate according to the spec. + // This function is only needed for a few different small constant sizes of extension array, and + // we want to avoid unnecessary dynamic allocations. That's why checkCanUseOneOfExtensions is a + // template function rather than one taking a vector. + template + bool checkCanUseOneOfExtensions(const TSourceLoc &line, + const std::array &extensions); + bool checkCanUseExtension(const TSourceLoc &line, TExtension extension); + + // Done for all declarations, whether empty or not. + void declarationQualifierErrorCheck(const sh::TQualifier qualifier, + const sh::TLayoutQualifier &layoutQualifier, + const TSourceLoc &location); + // Done for the first non-empty declarator in a declaration. + void nonEmptyDeclarationErrorCheck(const TPublicType &publicType, + const TSourceLoc &identifierLocation); + // Done only for empty declarations. + void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location); + + void checkLayoutQualifierSupported(const TSourceLoc &location, + const TString &layoutQualifierName, + int versionRequired); + bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); + void checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation); + void checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation); + void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier); 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; + const TExtensionBehavior &extensionBehavior() const + { + return mDirectiveHandler.extensionBehavior(); + } + + bool isExtensionEnabled(TExtension 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); + 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); + // Returns true on success. *initNode may still be nullptr on success in case the initialization + // is not needed in the AST. bool executeInitializer(const TSourceLoc &line, const TString &identifier, - const TPublicType &pType, + TType type, TIntermTyped *initializer, - TIntermNode **intermNode); - - TPublicType addFullySpecifiedType(TQualifier qualifier, - bool invariant, - TLayoutQualifier layoutQualifier, + TIntermBinary **initNode); + TIntermNode *addConditionInitializer(const TPublicType &pType, + const TString &identifier, + TIntermTyped *initializer, + const TSourceLoc &loc); + TIntermNode *addLoop(TLoopType type, + TIntermNode *init, + TIntermNode *cond, + TIntermTyped *expr, + TIntermNode *body, + const TSourceLoc &loc); + + // For "if" test nodes. There are three children: a condition, a true path, and a false path. + // The two paths are in TIntermNodePair code. + TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &loc); + + void addFullySpecifiedType(TPublicType *typeSpecifier); + TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, 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); + TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType, + const TSourceLoc &identifierOrTypeLocation, + const TString &identifier); + TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &indexLocation, + const TVector &arraySizes); + TIntermDeclaration *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); + TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &indexLocation, + const TVector &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer); + + TIntermInvariantDeclaration *parseInvariantDeclaration( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &identifierLoc, + const TString *identifier, + const TSymbol *symbol); + + void parseDeclarator(TPublicType &publicType, + const TSourceLoc &identifierLocation, + const TString &identifier, + TIntermDeclaration *declarationOut); + void parseArrayDeclarator(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &arrayLocation, + const TVector &arraySizes, + TIntermDeclaration *declarationOut); + void parseInitDeclarator(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut); // 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); - - void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); - 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); + void parseArrayInitDeclarator(const TPublicType &elementType, + const TSourceLoc &identifierLocation, + const TString &identifier, + const TSourceLoc &indexLocation, + const TVector &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut); + + TIntermNode *addEmptyStatement(const TSourceLoc &location); + + void parseDefaultPrecisionQualifier(const TPrecision precision, + const TPublicType &type, + const TSourceLoc &loc); + void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder); + + TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction, + const TSourceLoc &location); + TIntermFunctionDefinition *addFunctionDefinition(TIntermFunctionPrototype *functionPrototype, + TIntermBlock *functionBody, + const TSourceLoc &location); + void parseFunctionDefinitionHeader(const TSourceLoc &location, + TFunction **function, + TIntermFunctionPrototype **prototypeOut); + TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function); + TFunction *parseFunctionHeader(const TPublicType &type, + const TString *name, + const TSourceLoc &location); + TFunction *addNonConstructorFunc(const TString *name, const TSourceLoc &loc); 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); + TParameter parseParameterDeclarator(const TPublicType &publicType, + const TString *name, + const TSourceLoc &nameLoc); + + TParameter parseParameterArrayDeclarator(const TString *name, + const TSourceLoc &nameLoc, + const TVector &arraySizes, + const TSourceLoc &arrayLoc, + TPublicType *elementType); + TIntermTyped *addIndexExpression(TIntermTyped *baseExpression, - const TSourceLoc& location, + const TSourceLoc &location, TIntermTyped *indexExpression); - TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression, + 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); + // Parse declarator for a single field + TField *parseStructDeclarator(TString *identifier, const TSourceLoc &loc); + TField *parseStructArrayDeclarator(TString *identifier, + const TSourceLoc &loc, + const TVector &arraySizes, + const TSourceLoc &arraySizeLoc); - TIntermAggregate* addInterfaceBlock(const TPublicType &typeQualifier, + void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, + const TFieldList::const_iterator end, + const TString &name, + const TSourceLoc &location); + TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location); + TFieldList *combineStructFieldLists(TFieldList *processedFields, + const TFieldList *newlyAddedFields, + const TSourceLoc &location); + TFieldList *addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + TFieldList *fieldList); + TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList); + TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine, 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); + const TString *structName, + TFieldList *fieldList); + + TIntermDeclaration *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &nameLine, + const TString &blockName, + TFieldList *fieldList, + const TString *instanceName, + const TSourceLoc &instanceLine, + TIntermTyped *arrayIndex, + const TSourceLoc &arrayIndexLine); + + void parseLocalSize(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize); + void parseNumViews(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numViews); + void parseInvocations(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numInvocations); + void parseMaxVertices(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numMaxVertices); + 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); + TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc); + TStorageQualifierWrapper *parseGlobalStorageQualifier(TQualifier qualifier, + const TSourceLoc &loc); + TStorageQualifierWrapper *parseVaryingQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseInQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseOutQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseInOutQualifier(const TSourceLoc &loc); + TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation); // 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); + void enterStructDeclaration(const TSourceLoc &line, const TString &identifier); void exitStructDeclaration(); - bool structNestingErrorCheck(const TSourceLoc &line, const TField &field); + void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field); - TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc); + TIntermSwitch *addSwitch(TIntermTyped *init, + TIntermBlock *statementList, + const TSourceLoc &loc); TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc); TIntermCase *addDefault(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 *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); + TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc); + void checkTextureGather(TIntermAggregate *functionCall); void checkTextureOffsetConst(TIntermAggregate *functionCall); + void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall); + void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition, + const TIntermAggregate *functionCall); + void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall); + TIntermSequence *createEmptyArgumentsList(); + + // fnCall is only storing the built-in op, and function name or constructor type. arguments + // has the arguments. TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, - TIntermNode *paramNode, + TIntermSequence *arguments, TIntermNode *thisNode, - const TSourceLoc &loc, - bool *fatalError); + const TSourceLoc &loc); - TIntermTyped *addTernarySelection( - TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line); + TIntermTyped *addTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &line); - // TODO(jmadill): make these private - TIntermediate &intermediate; // to hold and build a parse tree + int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; } + int getGeometryShaderInvocations() const + { + return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1; + } + TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const + { + return mGeometryShaderInputPrimitiveType; + } + TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const + { + return mGeometryShaderOutputPrimitiveType; + } + + // TODO(jmadill): make this private TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed private: - 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); + class AtomicCounterBindingState; + constexpr static size_t kAtomicCounterSize = 4; + // UNIFORM_ARRAY_STRIDE for atomic counter arrays is an implementation-dependent value which + // can be queried after a program is linked according to ES 3.10 section 7.7.1. This is + // controversial with the offset inheritance as described in ESSL 3.10 section 4.4.6. Currently + // we treat it as always 4 in favour of the original interpretation in + // "ARB_shader_atomic_counters". + // TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved. + // Note that there may be tests in AtomicCounter_test that will need to be updated as well. + constexpr static size_t kAtomicCounterArrayStride = 4; + + // Returns a clamped index. If it prints out an error message, the token is "[]". + int checkIndexLessThan(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason); + + bool declareVariable(const TSourceLoc &line, + const TString &identifier, + const TType &type, + TVariable **variable); + + void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const TString &identifier, + TType *type); + + TParameter parseParameterDeclarator(TType *type, + const TString *name, + const TSourceLoc &nameLoc); + + bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType); + // Done for all atomic counter declarations, whether empty or not. + void atomicCounterQualifierErrorCheck(const TPublicType &publicType, + const TSourceLoc &location); + + // Assumes that multiplication op has already been set based on the types. + bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right); + + void checkOutParameterIsNotOpaqueType(const TSourceLoc &line, + TQualifier qualifier, + const TType &type); + + void checkInternalFormatIsNotSpecified(const TSourceLoc &location, + TLayoutImageInternalFormat internalFormat); + void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, + const TSourceLoc &location); + void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, + const TSourceLoc &loc, + TType *type); + void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type); + void checkBindingIsNotSpecified(const TSourceLoc &location, int binding); + void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset); + void checkImageBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount); + void checkSamplerBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount); + void checkBlockBindingIsValid(const TSourceLoc &location, + const TQualifier &qualifier, + int binding, + int arraySize); + void checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding); + + void checkUniformLocationInRange(const TSourceLoc &location, + int objectLocationCount, + const TLayoutQualifier &layoutQualifier); + + void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv); + + bool checkUnsizedArrayConstructorArgumentDimensionality(TIntermSequence *arguments, + TType type, + const TSourceLoc &line); + + // Will set the size of the outermost array according to geometry shader input layout. + void checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, + const char *token, + TType *type); + + // Will size any unsized array type so unsized arrays won't need to be taken into account + // further along the line in parsing. + void checkIsNotUnsizedArray(const TSourceLoc &line, + const char *errorMessage, + const char *token, + TType *arrayType); + + TIntermTyped *addBinaryMathInternal(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + TIntermBinary *createAssign(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc); + + TIntermTyped *addMethod(TFunction *fnCall, + TIntermSequence *arguments, + TIntermNode *thisNode, + const TSourceLoc &loc); + TIntermTyped *addConstructor(TIntermSequence *arguments, + TType type, + const TSourceLoc &line); + TIntermTyped *addNonConstructorFunctionCall(TFunction *fnCall, + TIntermSequence *arguments, + const TSourceLoc &loc); // Return true if the checks pass - 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. + bool binaryOpCommonCheck(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + + TIntermFunctionPrototype *createPrototypeNodeFromFunction(const TFunction &function, + const TSourceLoc &location, + bool insertParametersToSymbolTable); + + void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration, + const TSourceLoc &location); + + bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier); + bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier); + bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier); + void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line); + + // Set to true when the last/current declarator list was started with an empty declaration. The + // non-empty declaration error check will need to be performed if the empty declaration is + // followed by a declarator. + bool mDeferredNonEmptyDeclarationErrorCheck; + + sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack) + ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + ShCompileOptions mCompileOptions; // Options passed to TCompiler 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. + TIntermBlock *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; + TLayoutMatrixPacking mDefaultUniformMatrixPacking; + TLayoutBlockStorage mDefaultUniformBlockStorage; + TLayoutMatrixPacking mDefaultBufferMatrixPacking; + TLayoutBlockStorage mDefaultBufferBlockStorage; TString mHashErrMsg; - TDiagnostics mDiagnostics; + TDiagnostics *mDiagnostics; TDirectiveHandler mDirectiveHandler; pp::Preprocessor mPreprocessor; void *mScanner; - bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor + 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 mMinProgramTextureGatherOffset; + int mMaxProgramTextureGatherOffset; + + // keep track of local group size declared in layout. It should be declared only once. + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + // keep track of number of views declared in layout. + int mNumViews; + int mMaxNumViews; + int mMaxImageUnits; + int mMaxCombinedTextureImageUnits; + int mMaxUniformLocations; + int mMaxUniformBufferBindings; + int mMaxAtomicCounterBindings; + int mMaxShaderStorageBufferBindings; + + // keeps track whether we are declaring / defining a function + bool mDeclaringFunction; + + // Track the state of each atomic counter binding. + std::map mAtomicCounterBindingStates; + + // Track the geometry shader global parameters declared in layout. + TLayoutPrimitiveType mGeometryShaderInputPrimitiveType; + TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType; + int mGeometryShaderInvocations; + int mGeometryShaderMaxVertices; + int mMaxGeometryShaderInvocations; + int mMaxGeometryShaderMaxVertices; + + // Track if all input array sizes are same and matches the latter input primitive declaration. + unsigned int mGeometryShaderInputArraySize; }; -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); + +} // namespace sh -#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_ +#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp index 887cb66504..0f1cd8b5c9 100644 --- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp +++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.cpp @@ -6,16 +6,16 @@ #include "compiler/translator/PoolAlloc.h" -#include "compiler/translator/InitializeGlobals.h" - -#include "common/platform.h" -#include "common/angleutils.h" -#include "common/tls.h" - #include #include #include +#include "common/angleutils.h" +#include "common/debug.h" +#include "common/platform.h" +#include "common/tls.h" +#include "compiler/translator/InitializeGlobals.h" + TLSIndex PoolIndex = TLS_INVALID_INDEX; bool InitializePoolIndex() @@ -34,13 +34,13 @@ void FreePoolIndex() PoolIndex = TLS_INVALID_INDEX; } -TPoolAllocator* GetGlobalPoolAllocator() +TPoolAllocator *GetGlobalPoolAllocator() { assert(PoolIndex != TLS_INVALID_INDEX); - return static_cast(GetTLSValue(PoolIndex)); + return static_cast(GetTLSValue(PoolIndex)); } -void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) +void SetGlobalPoolAllocator(TPoolAllocator *poolAllocator) { assert(PoolIndex != TLS_INVALID_INDEX); SetTLSValue(PoolIndex, poolAllocator); @@ -50,56 +50,66 @@ void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) // Implement the functionality of the TPoolAllocator class, which // is documented in PoolAlloc.h. // -TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : - pageSize(growthIncrement), - alignment(allocationAlignment), - freeList(0), - inUseList(0), - numCalls(0), - totalBytes(0) +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) + : alignment(allocationAlignment), +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + pageSize(growthIncrement), + freeList(0), + inUseList(0), + numCalls(0), + totalBytes(0), +#endif + mLocked(false) { - // - // Don't allow page sizes we know are smaller than all common - // OS page sizes. - // - if (pageSize < 4*1024) - pageSize = 4*1024; - - // - // A large currentPageOffset indicates a new page needs to - // be obtained to allocate memory. - // - currentPageOffset = pageSize; - // // Adjust alignment to be at least pointer aligned and // power of 2. // - size_t minAlign = sizeof(void*); + size_t minAlign = sizeof(void *); alignment &= ~(minAlign - 1); if (alignment < minAlign) alignment = minAlign; - size_t a = 1; + size_t a = 1; while (a < alignment) a <<= 1; - alignment = a; + alignment = a; alignmentMask = a - 1; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4 * 1024) + pageSize = 4 * 1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + // // Align header skip // headerSkip = minAlign; - if (headerSkip < sizeof(tHeader)) { + if (headerSkip < sizeof(tHeader)) + { headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; } +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + mStack.push_back({}); +#endif } TPoolAllocator::~TPoolAllocator() { - while (inUseList) { - tHeader* next = inUseList->nextPage; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + while (inUseList) + { + tHeader *next = inUseList->nextPage; inUseList->~tHeader(); - delete [] reinterpret_cast(inUseList); + delete[] reinterpret_cast(inUseList); inUseList = next; } @@ -107,11 +117,22 @@ TPoolAllocator::~TPoolAllocator() // here, because we did it already when the block was // placed into the free list. // - while (freeList) { - tHeader* next = freeList->nextPage; - delete [] reinterpret_cast(freeList); + while (freeList) + { + tHeader *next = freeList->nextPage; + delete[] reinterpret_cast(freeList); freeList = next; } +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + for (auto &allocs : mStack) + { + for (auto alloc : allocs) + { + free(alloc); + } + } + mStack.clear(); +#endif } // Support MSVC++ 6.0 @@ -120,28 +141,32 @@ const unsigned char TAllocation::guardBlockEndVal = 0xfe; const unsigned char TAllocation::userDataFill = 0xcd; #ifdef GUARD_BLOCKS - const size_t TAllocation::guardBlockSize = 16; +const size_t TAllocation::guardBlockSize = 16; #else - const size_t TAllocation::guardBlockSize = 0; +const size_t TAllocation::guardBlockSize = 0; #endif // // Check a single guard block for damage // -void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const +void TAllocation::checkGuardBlock(unsigned char *blockMem, + unsigned char val, + const char *locText) const { #ifdef GUARD_BLOCKS - for (size_t x = 0; x < guardBlockSize; x++) { - if (blockMem[x] != val) { + for (size_t x = 0; x < guardBlockSize; x++) + { + if (blockMem[x] != val) + { char assertMsg[80]; - // We don't print the assert message. It's here just to be helpful. +// We don't print the assert message. It's here just to be helpful. #if defined(_MSC_VER) - snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n", - locText, size, data()); + snprintf(assertMsg, sizeof(assertMsg), + "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n", locText, size, data()); #else - snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", - locText, size, data()); + snprintf(assertMsg, sizeof(assertMsg), + "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", locText, size, data()); #endif assert(0 && "PoolAlloc: Damage in guard block"); } @@ -149,17 +174,20 @@ void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, co #endif } - void TPoolAllocator::push() { - tAllocState state = { currentPageOffset, inUseList }; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + tAllocState state = {currentPageOffset, inUseList}; + + mStack.push_back(state); - stack.push_back(state); - // // Indicate there is no current page to allocate from. // currentPageOffset = pageSize; +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + mStack.push_back({}); +#endif } // @@ -171,27 +199,37 @@ void TPoolAllocator::push() // void TPoolAllocator::pop() { - if (stack.size() < 1) + if (mStack.size() < 1) return; - tHeader* page = stack.back().page; - currentPageOffset = stack.back().offset; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + tHeader *page = mStack.back().page; + currentPageOffset = mStack.back().offset; - while (inUseList != page) { + while (inUseList != page) + { // invoke destructor to free allocation list inUseList->~tHeader(); - - tHeader* nextInUse = inUseList->nextPage; + + tHeader *nextInUse = inUseList->nextPage; if (inUseList->pageCount > 1) - delete [] reinterpret_cast(inUseList); - else { + delete[] reinterpret_cast(inUseList); + else + { inUseList->nextPage = freeList; - freeList = inUseList; + freeList = inUseList; } inUseList = nextInUse; } - stack.pop_back(); + mStack.pop_back(); +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + for (auto &alloc : mStack.back()) + { + free(alloc); + } + mStack.pop_back(); +#endif } // @@ -200,12 +238,15 @@ void TPoolAllocator::pop() // void TPoolAllocator::popAll() { - while (stack.size() > 0) + while (mStack.size() > 0) pop(); } -void* TPoolAllocator::allocate(size_t numBytes) +void *TPoolAllocator::allocate(size_t numBytes) { + ASSERT(!mLocked); + +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) // // Just keep some interesting statistics. // @@ -226,18 +267,20 @@ void* TPoolAllocator::allocate(size_t numBytes) // Do the allocation, most likely case first, for efficiency. // This step could be moved to be inline sometime. // - if (allocationSize <= pageSize - currentPageOffset) { + if (allocationSize <= pageSize - currentPageOffset) + { // // Safe to allocate from currentPageOffset. // - unsigned char* memory = reinterpret_cast(inUseList) + currentPageOffset; + unsigned char *memory = reinterpret_cast(inUseList) + currentPageOffset; currentPageOffset += allocationSize; currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; return initializeAllocation(inUseList, memory, numBytes); } - if (allocationSize > pageSize - headerSkip) { + if (allocationSize > pageSize - headerSkip) + { // // Do a multi-page allocation. Don't mix these with the others. // The OS is efficient and allocating and free-ing multiple pages. @@ -247,49 +290,71 @@ void* TPoolAllocator::allocate(size_t numBytes) if (numBytesToAlloc < allocationSize) return 0; - tHeader* memory = reinterpret_cast(::new char[numBytesToAlloc]); + tHeader *memory = reinterpret_cast(::new char[numBytesToAlloc]); if (memory == 0) return 0; // Use placement-new to initialize header - new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); + new (memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); inUseList = memory; currentPageOffset = pageSize; // make next allocation come from a new page // No guard blocks for multi-page allocations (yet) - return reinterpret_cast(reinterpret_cast(memory) + headerSkip); + return reinterpret_cast(reinterpret_cast(memory) + headerSkip); } // // Need a simple page to allocate from. // - tHeader* memory; - if (freeList) { - memory = freeList; + tHeader *memory; + if (freeList) + { + memory = freeList; freeList = freeList->nextPage; - } else { - memory = reinterpret_cast(::new char[pageSize]); + } + else + { + memory = reinterpret_cast(::new char[pageSize]); if (memory == 0) return 0; } // Use placement-new to initialize header - new(memory) tHeader(inUseList, 1); + new (memory) tHeader(inUseList, 1); inUseList = memory; - - unsigned char* ret = reinterpret_cast(inUseList) + headerSkip; - currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; + + unsigned char *ret = reinterpret_cast(inUseList) + headerSkip; + currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; return initializeAllocation(inUseList, ret, numBytes); +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + void *alloc = malloc(numBytes + alignmentMask); + mStack.back().push_back(alloc); + + intptr_t intAlloc = reinterpret_cast(alloc); + intAlloc = (intAlloc + alignmentMask) & ~alignmentMask; + return reinterpret_cast(intAlloc); +#endif +} + +void TPoolAllocator::lock() +{ + ASSERT(!mLocked); + mLocked = true; } +void TPoolAllocator::unlock() +{ + ASSERT(mLocked); + mLocked = false; +} // // Check all allocations in a list for damage by calling check on each. // void TAllocation::checkAllocList() const { - for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + for (const TAllocation *alloc = this; alloc != 0; alloc = alloc->prevAlloc) alloc->check(); } diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h index dab2926c90..ad63bc4cd6 100644 --- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h +++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h @@ -13,8 +13,8 @@ // // This header defines an allocator that can be used to efficiently -// allocate a large number of small requests for heap memory, with the -// intention that they are not individually deallocated, but rather +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather // collectively deallocated at one time. // // This simultaneously @@ -38,53 +38,58 @@ // If we are using guard blocks, we must track each indivual // allocation. If we aren't using guard blocks, these // never get instantiated, so won't have any impact. -// - -class TAllocation { -public: - TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : - size(size), mem(mem), prevAlloc(prev) { - // Allocations are bracketed: - // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] - // This would be cleaner with if (guardBlockSize)..., but that - // makes the compiler print warnings about 0 length memsets, - // even with the if() protecting them. +// + +class TAllocation +{ + public: + TAllocation(size_t size, unsigned char *mem, TAllocation *prev = 0) + : size(size), mem(mem), prevAlloc(prev) + { +// Allocations are bracketed: +// [allocationHeader][initialGuardBlock][userData][finalGuardBlock] +// This would be cleaner with if (guardBlockSize)..., but that +// makes the compiler print warnings about 0 length memsets, +// even with the if() protecting them. #ifdef GUARD_BLOCKS memset(preGuard(), guardBlockBeginVal, guardBlockSize); - memset(data(), userDataFill, size); - memset(postGuard(), guardBlockEndVal, guardBlockSize); + memset(data(), userDataFill, size); + memset(postGuard(), guardBlockEndVal, guardBlockSize); #endif } - void check() const { - checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); - checkGuardBlock(postGuard(), guardBlockEndVal, "after"); + void check() const + { + checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); + checkGuardBlock(postGuard(), guardBlockEndVal, "after"); } void checkAllocList() const; // Return total size needed to accomodate user buffer of 'size', // plus our tracking data. - inline static size_t allocationSize(size_t size) { + inline static size_t allocationSize(size_t size) + { return size + 2 * guardBlockSize + headerSize(); } // Offset from surrounding buffer to get to user data buffer. - inline static unsigned char* offsetAllocation(unsigned char* m) { + inline static unsigned char *offsetAllocation(unsigned char *m) + { return m + guardBlockSize + headerSize(); } -private: - void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const; + private: + void checkGuardBlock(unsigned char *blockMem, unsigned char val, const char *locText) const; // Find offsets to pre and post guard blocks, and user data buffer - unsigned char* preGuard() const { return mem + headerSize(); } - unsigned char* data() const { return preGuard() + guardBlockSize; } - unsigned char* postGuard() const { return data() + size; } + unsigned char *preGuard() const { return mem + headerSize(); } + unsigned char *data() const { return preGuard() + guardBlockSize; } + unsigned char *postGuard() const { return data() + size; } - size_t size; // size of the user data area - unsigned char* mem; // beginning of our allocation (pts to header) - TAllocation* prevAlloc; // prior allocation in the chain + size_t size; // size of the user data area + unsigned char *mem; // beginning of our allocation (pts to header) + TAllocation *prevAlloc; // prior allocation in the chain // Support MSVC++ 6.0 const static unsigned char guardBlockBeginVal; @@ -101,7 +106,7 @@ private: // // There are several stacks. One is to track the pushing and popping -// of the user, and not yet implemented. The others are simply a +// of the user, and not yet implemented. The others are simply a // repositories of free pages or used pages. // // Page stacks are linked together with a simple header at the beginning @@ -110,12 +115,13 @@ private: // re-use. // // The "page size" used is not, nor must it match, the underlying OS -// page size. But, having it be about that size or equal to a set of +// page size. But, having it be about that size or equal to a set of // pages is likely most optimal. // -class TPoolAllocator { -public: - TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16); +class TPoolAllocator +{ + public: + TPoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = 16); // // Don't call the destructor just to free up the memory, call pop() @@ -143,7 +149,7 @@ public: // Call allocate() to actually acquire memory. Returns 0 if no memory // available, otherwise a properly aligned pointer to 'numBytes' of memory. // - void* allocate(size_t numBytes); + void *allocate(size_t numBytes); // // There is no deallocate. The point of this class is that @@ -152,75 +158,92 @@ public: // by calling pop(), and to not have to solve memory leak problems. // -protected: + // Catch unwanted allocations. + // TODO(jmadill): Remove this when we remove the global allocator. + void lock(); + void unlock(); + + private: + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) friend struct tHeader; - - struct tHeader { - tHeader(tHeader* nextPage, size_t pageCount) : - nextPage(nextPage), - pageCount(pageCount) + + struct tHeader + { + tHeader(tHeader *nextPage, size_t pageCount) + : nextPage(nextPage), + pageCount(pageCount) #ifdef GUARD_BLOCKS - , lastAllocation(0) + , + lastAllocation(0) #endif - { } + { + } - ~tHeader() { + ~tHeader() + { #ifdef GUARD_BLOCKS if (lastAllocation) lastAllocation->checkAllocList(); #endif } - tHeader* nextPage; + tHeader *nextPage; size_t pageCount; #ifdef GUARD_BLOCKS - TAllocation* lastAllocation; + TAllocation *lastAllocation; #endif }; - struct tAllocState { + struct tAllocState + { size_t offset; - tHeader* page; + tHeader *page; }; typedef std::vector tAllocStack; // Track allocations if and only if we're using guard blocks - void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) { + void *initializeAllocation(tHeader *block, unsigned char *memory, size_t numBytes) + { #ifdef GUARD_BLOCKS - new(memory) TAllocation(numBytes, memory, block->lastAllocation); - block->lastAllocation = reinterpret_cast(memory); + new (memory) TAllocation(numBytes, memory, block->lastAllocation); + block->lastAllocation = reinterpret_cast(memory); #endif // This is optimized entirely away if GUARD_BLOCKS is not defined. return TAllocation::offsetAllocation(memory); } - size_t pageSize; // granularity of allocation from the OS - size_t alignment; // all returned allocations will be aligned at - // this granularity, which will be a power of 2 - size_t alignmentMask; - size_t headerSkip; // amount of memory to skip to make room for the - // header (basically, size of header, rounded - // up to make it aligned + size_t pageSize; // granularity of allocation from the OS + size_t headerSkip; // amount of memory to skip to make room for the + // header (basically, size of header, rounded + // up to make it aligned size_t currentPageOffset; // next offset in top of inUseList to allocate from - tHeader* freeList; // list of popped memory - tHeader* inUseList; // list of all memory currently being used - tAllocStack stack; // stack of where to allocate from, to partition pool - - int numCalls; // just an interesting statistic - size_t totalBytes; // just an interesting statistic -private: - TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator - TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor -}; + tHeader *freeList; // list of popped memory + tHeader *inUseList; // list of all memory currently being used + tAllocStack mStack; // stack of where to allocate from, to partition pool + int numCalls; // just an interesting statistic + size_t totalBytes; // just an interesting statistic + +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + std::vector> mStack; +#endif + + TPoolAllocator &operator=(const TPoolAllocator &); // dont allow assignment operator + TPoolAllocator(const TPoolAllocator &); // dont allow default copy constructor + bool mLocked; +}; // // There could potentially be many pools with pops happening at // different times. But a simple use is to have a global pop // with everyone using the same global allocator. // -extern TPoolAllocator* GetGlobalPoolAllocator(); -extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator); +extern TPoolAllocator *GetGlobalPoolAllocator(); +extern void SetGlobalPoolAllocator(TPoolAllocator *poolAllocator); // // This STL compatible allocator is intended to be used as the allocator @@ -229,63 +252,68 @@ extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator); // It will use the pools for allocation, and not // do any deallocation, but will still do destruction. // -template -class pool_allocator { -public: +template +class pool_allocator +{ + public: typedef size_t size_type; typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; typedef T value_type; - template - struct rebind { + template + struct rebind + { typedef pool_allocator other; }; pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } - pool_allocator() { } + pool_allocator() {} - template - pool_allocator(const pool_allocator& p) { } + template + pool_allocator(const pool_allocator &p) + { + } template - pool_allocator& operator=(const pool_allocator& p) { return *this; } + 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. // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be // allocated, not the number of elements. - void* allocate(size_type n) { - return getAllocator().allocate(n); - } - void* allocate(size_type n, const void*) { - return getAllocator().allocate(n); - } - void deallocate(void*, size_type) {} + void *allocate(size_type n) { return getAllocator().allocate(n); } + void *allocate(size_type n, const void *) { return getAllocator().allocate(n); } + void deallocate(void *, size_type) {} #else - pointer allocate(size_type n) { + pointer allocate(size_type n) + { return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } - pointer allocate(size_type n, const void*) { + pointer allocate(size_type n, const void *) + { return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } void deallocate(pointer, size_type) {} #endif // _RWSTD_ALLOCATOR - void construct(pointer p, const T& val) { new ((void *)p) T(val); } + 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 true; } - bool operator!=(const pool_allocator& rhs) const { return false; } + 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; } - TPoolAllocator& getAllocator() const { return *GetGlobalPoolAllocator(); } + TPoolAllocator &getAllocator() const { return *GetGlobalPoolAllocator(); } }; -#endif // COMPILER_TRANSLATOR_POOLALLOC_H_ +#endif // COMPILER_TRANSLATOR_POOLALLOC_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Pragma.h b/src/3rdparty/angle/src/compiler/translator/Pragma.h index 57b1134970..8c419fc17e 100644 --- a/src/3rdparty/angle/src/compiler/translator/Pragma.h +++ b/src/3rdparty/angle/src/compiler/translator/Pragma.h @@ -11,17 +11,16 @@ struct TPragma { struct STDGL { - STDGL() : invariantAll(false) { } + STDGL() : invariantAll(false) {} bool invariantAll; }; - // By default optimization is turned on and debug is turned off. // Precision emulation is turned on by default, but has no effect unless // the extension is enabled. - TPragma() : optimize(true), debug(false), debugShaderPrecision(true) { } - TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) { } + TPragma() : optimize(true), debug(false), debugShaderPrecision(true) {} + TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) {} bool optimize; bool debug; @@ -29,4 +28,4 @@ struct TPragma STDGL stdgl; }; -#endif // COMPILER_TRANSLATOR_PRAGMA_H_ +#endif // COMPILER_TRANSLATOR_PRAGMA_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp b/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp deleted file mode 100644 index ef62dbfce7..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// 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 deleted file mode 100644 index 122e830902..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/PruneEmptyDeclarations.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// 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/PruneNoOps.cpp b/src/3rdparty/angle/src/compiler/translator/PruneNoOps.cpp new file mode 100644 index 0000000000..6c9a02cd1c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/PruneNoOps.cpp @@ -0,0 +1,156 @@ +// +// 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. +// +// PruneNoOps.cpp: The PruneNoOps function prunes: +// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example: +// int , a; +// is turned into +// int a; +// 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision for float, +// so float literal statements would end up with no precision which is invalid ESSL. + +#include "compiler/translator/PruneNoOps.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +bool IsNoOp(TIntermNode *node) +{ + if (node->getAsConstantUnion() != nullptr) + { + return true; + } + bool isEmptyDeclaration = node->getAsDeclarationNode() != nullptr && + node->getAsDeclarationNode()->getSequence()->empty(); + if (isEmptyDeclaration) + { + return true; + } + return false; +} + +class PruneNoOpsTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermBlock *root); + + private: + PruneNoOpsTraverser(); + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitLoop(Visit visit, TIntermLoop *loop) override; +}; + +void PruneNoOpsTraverser::apply(TIntermBlock *root) +{ + PruneNoOpsTraverser prune; + root->traverse(&prune); + prune.updateTree(); +} + +PruneNoOpsTraverser::PruneNoOpsTraverser() : TIntermTraverser(true, false, false) +{ +} + +bool PruneNoOpsTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + 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) + { + // If there are entirely empty non-struct declarations, they result in + // TIntermDeclaration nodes without any children in the parsing stage. These are + // handled in visitBlock and visitLoop. + UNREACHABLE(); + } + else if (sym->getType().getQualifier() != EvqGlobal && + sym->getType().getQualifier() != EvqTemporary) + { + // Single struct declarations may just declare the struct type and no variables, so + // they should not be pruned. Here we handle an empty struct declaration with a + // qualifier, for example like this: + // const struct a { int i; }; + // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so we + // convert the declaration to a regular struct declaration. This is okay, since ESSL + // 1.00 spec section 4.1.8 says about structs that "The optional qualifiers only + // apply to any declarators, and are not part of the type being defined for name." + + if (mInGlobalScope) + { + sym->getTypePointer()->setQualifier(EvqGlobal); + } + else + { + sym->getTypePointer()->setQualifier(EvqTemporary); + } + } + } + } + return false; +} + +bool PruneNoOpsTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + TIntermSequence *statements = node->getSequence(); + + for (TIntermNode *statement : *statements) + { + if (IsNoOp(statement)) + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(node, statement, emptyReplacement)); + } + } + + return true; +} + +bool PruneNoOpsTraverser::visitLoop(Visit visit, TIntermLoop *loop) +{ + TIntermTyped *expr = loop->getExpression(); + if (expr != nullptr && IsNoOp(expr)) + { + loop->setExpression(nullptr); + } + TIntermNode *init = loop->getInit(); + if (init != nullptr && IsNoOp(init)) + { + loop->setInit(nullptr); + } + + return true; +} + +} // namespace + +void PruneNoOps(TIntermBlock *root) +{ + PruneNoOpsTraverser::apply(root); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/PruneNoOps.h b/src/3rdparty/angle/src/compiler/translator/PruneNoOps.h new file mode 100644 index 0000000000..c421cecca4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/PruneNoOps.h @@ -0,0 +1,24 @@ +// +// 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. +// +// PruneNoOps.h: The PruneNoOps function prunes: +// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example: +// int , a; +// is turned into +// int a; +// 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision for float, +// so float literal statements would end up with no precision which is invalid ESSL. + +#ifndef COMPILER_TRANSLATOR_PRUNENOOPS_H_ +#define COMPILER_TRANSLATOR_PRUNENOOPS_H_ + +namespace sh +{ +class TIntermBlock; + +void PruneNoOps(TIntermBlock *root); +} + +#endif // COMPILER_TRANSLATOR_PRUNENOOPS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp deleted file mode 100644 index 3d950aab5a..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/IntermNode.h" - -class TAliveTraverser : public TIntermTraverser { -public: - TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q) - { - } - - bool wasFound() { return found; } - -protected: - bool found; - TQualifier qualifier; - - void visitSymbol(TIntermSymbol*); - bool visitSelection(Visit, TIntermSelection*); -}; - -// -// Report whether or not a variable of the given qualifier type -// is guaranteed written. Not always possible to determine if -// it is written conditionally. -// -// ?? It does not do this well yet, this is just a place holder -// that simply determines if it was reference at all, anywhere. -// -bool QualifierWritten(TIntermNode* node, TQualifier qualifier) -{ - TAliveTraverser it(qualifier); - - if (node) - node->traverse(&it); - - return it.wasFound(); -} - -void TAliveTraverser::visitSymbol(TIntermSymbol* node) -{ - // - // If it's what we're looking for, record it. - // - if (node->getQualifier() == qualifier) - found = true; -} - -bool TAliveTraverser::visitSelection(Visit, TIntermSelection*) -{ - if (wasFound()) - return false; - - return true; -} diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h deleted file mode 100644 index 3e4f18012a..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ -#define COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ - -bool QualifierWritten(TIntermNode* root, TQualifier); - -#endif // COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierTypes.cpp b/src/3rdparty/angle/src/compiler/translator/QualifierTypes.cpp new file mode 100644 index 0000000000..f748175957 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/QualifierTypes.cpp @@ -0,0 +1,784 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project 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/QualifierTypes.h" + +#include "compiler/translator/Diagnostics.h" + +#include + +namespace sh +{ + +namespace +{ + +// GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout +// declarations. +// GLSL ES 3.10 Revision 4, 4.10 Order of Qualification +bool AreTypeQualifierChecksRelaxed(int shaderVersion) +{ + return shaderVersion >= 310; +} + +bool IsScopeQualifier(TQualifier qualifier) +{ + return qualifier == EvqGlobal || qualifier == EvqTemporary; +} + +bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier) +{ + if (qualifier->getType() != QtStorage) + return false; + const TStorageQualifierWrapper *storageQualifier = + static_cast(qualifier); + TQualifier q = storageQualifier->getQualifier(); + return IsScopeQualifier(q); +} + +// Returns true if the invariant for the qualifier sequence holds +bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We should have at least one qualifier. + // The first qualifier always tells the scope. + return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]); +} + +// Returns true if there are qualifiers which have been specified multiple times +// If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed. +bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + bool areQualifierChecksRelaxed, + std::string *errorMessage) +{ + bool invariantFound = false; + bool precisionFound = false; + bool layoutFound = false; + bool interpolationFound = false; + + unsigned int locationsSpecified = 0; + bool isOut = false; + + // The iteration starts from one since the first qualifier only reveals the scope of the + // expression. It is inserted first whenever the sequence gets created. + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + { + if (invariantFound) + { + *errorMessage = "The invariant qualifier specified multiple times."; + return true; + } + invariantFound = true; + break; + } + case QtPrecision: + { + if (precisionFound) + { + *errorMessage = "The precision qualifier specified multiple times."; + return true; + } + precisionFound = true; + break; + } + case QtLayout: + { + if (layoutFound && !areQualifierChecksRelaxed) + { + *errorMessage = "The layout qualifier specified multiple times."; + return true; + } + if (invariantFound && !areQualifierChecksRelaxed) + { + // This combination is not correct according to the syntax specified in the + // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have + // a similar restriction. + *errorMessage = + "The layout qualifier and invariant qualifier cannot coexist in the same " + "declaration according to the grammar."; + return true; + } + layoutFound = true; + const TLayoutQualifier ¤tQualifier = + static_cast(qualifiers[i])->getQualifier(); + locationsSpecified += currentQualifier.locationsSpecified; + break; + } + case QtInterpolation: + { + // 'centroid' is treated as a storage qualifier + // 'flat centroid' will be squashed to 'flat' + // 'smooth centroid' will be squashed to 'centroid' + if (interpolationFound) + { + *errorMessage = "The interpolation qualifier specified multiple times."; + return true; + } + interpolationFound = true; + break; + } + case QtStorage: + { + // Go over all of the storage qualifiers up until the current one and check for + // repetitions. + TQualifier currentQualifier = + static_cast(qualifiers[i])->getQualifier(); + if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut) + { + isOut = true; + } + for (size_t j = 1; j < i; ++j) + { + if (qualifiers[j]->getType() == QtStorage) + { + const TStorageQualifierWrapper *previousQualifierWrapper = + static_cast(qualifiers[j]); + TQualifier previousQualifier = previousQualifierWrapper->getQualifier(); + if (currentQualifier == previousQualifier) + { + *errorMessage = previousQualifierWrapper->getQualifierString().c_str(); + *errorMessage += " specified multiple times"; + return true; + } + } + } + break; + } + case QtMemory: + { + // Go over all of the memory qualifiers up until the current one and check for + // repetitions. + // Having both readonly and writeonly in a sequence is valid. + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + TQualifier currentQualifier = + static_cast(qualifiers[i])->getQualifier(); + for (size_t j = 1; j < i; ++j) + { + if (qualifiers[j]->getType() == QtMemory) + { + const TMemoryQualifierWrapper *previousQualifierWrapper = + static_cast(qualifiers[j]); + TQualifier previousQualifier = previousQualifierWrapper->getQualifier(); + if (currentQualifier == previousQualifier) + { + *errorMessage = previousQualifierWrapper->getQualifierString().c_str(); + *errorMessage += " specified multiple times"; + return true; + } + } + } + break; + } + default: + UNREACHABLE(); + } + } + + if (locationsSpecified > 1 && isOut) + { + // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers + // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers + // "The qualifier may appear at most once within a declaration." + *errorMessage = "Output layout location specified multiple times."; + return true; + } + + return false; +} + +// GLSL ES 3.00_6, 4.7 Order of Qualification +// The correct order of qualifiers is: +// invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier +// layout-qualifier has to be before storage-qualifier. +bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + std::string *errorMessage) +{ + bool foundInterpolation = false; + bool foundStorage = false; + bool foundPrecision = false; + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + if (foundInterpolation || foundStorage || foundPrecision) + { + *errorMessage = "The invariant qualifier has to be first in the expression."; + return false; + } + break; + case QtInterpolation: + if (foundStorage) + { + *errorMessage = "Storage qualifiers have to be after interpolation qualifiers."; + return false; + } + else if (foundPrecision) + { + *errorMessage = + "Precision qualifiers have to be after interpolation qualifiers."; + return false; + } + foundInterpolation = true; + break; + case QtLayout: + if (foundStorage) + { + *errorMessage = "Storage qualifiers have to be after layout qualifiers."; + return false; + } + else if (foundPrecision) + { + *errorMessage = "Precision qualifiers have to be after layout qualifiers."; + return false; + } + break; + case QtStorage: + if (foundPrecision) + { + *errorMessage = "Precision qualifiers have to be after storage qualifiers."; + return false; + } + foundStorage = true; + break; + case QtMemory: + if (foundPrecision) + { + *errorMessage = "Precision qualifiers have to be after memory qualifiers."; + return false; + } + break; + case QtPrecision: + foundPrecision = true; + break; + default: + UNREACHABLE(); + } + } + return true; +} + +struct QualifierComparator +{ + bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2) + { + return q1->getRank() < q2->getRank(); + } +}; + +void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We need a stable sorting algorithm since the order of layout-qualifier declarations matter. + // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope + // and we always want it to be first. + std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator()); +} + +// Handles the joining of storage qualifiers for variables. +bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqGlobal: + *joinedQualifier = storageQualifier; + break; + case EvqTemporary: + { + switch (storageQualifier) + { + case EvqConst: + *joinedQualifier = storageQualifier; + break; + default: + return false; + } + break; + } + case EvqSmooth: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqCentroid; + break; + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqSmoothOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqSmoothIn; + break; + default: + return false; + } + break; + } + case EvqFlat: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqFlat; + break; + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqFlatOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqFlatIn; + break; + default: + return false; + } + break; + } + case EvqCentroid: + { + switch (storageQualifier) + { + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqCentroidOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqCentroidIn; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +// Handles the joining of storage qualifiers for a parameter in a function. +bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqTemporary: + *joinedQualifier = storageQualifier; + break; + case EvqConst: + { + switch (storageQualifier) + { + case EvqIn: + *joinedQualifier = EvqConstReadOnly; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier) +{ + switch (memoryQualifier) + { + case EvqReadOnly: + joinedMemoryQualifier->readonly = true; + break; + case EvqWriteOnly: + joinedMemoryQualifier->writeonly = true; + break; + case EvqCoherent: + joinedMemoryQualifier->coherent = true; + break; + case EvqRestrict: + joinedMemoryQualifier->restrictQualifier = true; + break; + case EvqVolatile: + // Variables having the volatile qualifier are automatcally treated as coherent as well. + // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers + joinedMemoryQualifier->volatileQualifier = true; + joinedMemoryQualifier->coherent = true; + break; + default: + UNREACHABLE(); + } + return true; +} + +TTypeQualifier GetVariableTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier( + static_cast(sortedSequence[0])->getQualifier(), + sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + isQualifierValid = true; + typeQualifier.invariant = true; + break; + case QtInterpolation: + { + switch (typeQualifier.qualifier) + { + case EvqGlobal: + isQualifierValid = true; + typeQualifier.qualifier = + static_cast(qualifier) + ->getQualifier(); + break; + default: + isQualifierValid = false; + } + break; + } + case QtLayout: + { + const TLayoutQualifierWrapper *layoutQualifierWrapper = + static_cast(qualifier); + isQualifierValid = true; + typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers( + typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(), + layoutQualifierWrapper->getLine(), diagnostics); + break; + } + case QtStorage: + isQualifierValid = JoinVariableStorageQualifier( + &typeQualifier.qualifier, + static_cast(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + case QtMemory: + isQualifierValid = JoinMemoryQualifier( + &typeQualifier.memoryQualifier, + static_cast(qualifier)->getQualifier()); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const TString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid qualifier combination", + qualifierString.c_str()); + break; + } + } + return typeQualifier; +} + +TTypeQualifier GetParameterTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + case QtInterpolation: + case QtLayout: + break; + case QtMemory: + isQualifierValid = JoinMemoryQualifier( + &typeQualifier.memoryQualifier, + static_cast(qualifier)->getQualifier()); + break; + case QtStorage: + isQualifierValid = JoinParameterStorageQualifier( + &typeQualifier.qualifier, + static_cast(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const TString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid parameter qualifier", + qualifierString.c_str()); + break; + } + } + + switch (typeQualifier.qualifier) + { + case EvqIn: + case EvqConstReadOnly: // const in + case EvqOut: + case EvqInOut: + break; + case EvqConst: + typeQualifier.qualifier = EvqConstReadOnly; + break; + case EvqTemporary: + // no qualifier has been specified, set it to EvqIn which is the default + typeQualifier.qualifier = EvqIn; + break; + default: + diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ", + getQualifierString(typeQualifier.qualifier)); + } + return typeQualifier; +} +} // namespace + +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics) +{ + TLayoutQualifier joinedQualifier = leftQualifier; + + if (rightQualifier.location != -1) + { + joinedQualifier.location = rightQualifier.location; + ++joinedQualifier.locationsSpecified; + } + if (rightQualifier.yuv != false) + { + joinedQualifier.yuv = rightQualifier.yuv; + } + if (rightQualifier.binding != -1) + { + joinedQualifier.binding = rightQualifier.binding; + } + if (rightQualifier.offset != -1) + { + joinedQualifier.offset = rightQualifier.offset; + } + if (rightQualifier.matrixPacking != EmpUnspecified) + { + joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + } + if (rightQualifier.blockStorage != EbsUnspecified) + { + joinedQualifier.blockStorage = rightQualifier.blockStorage; + } + + for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i) + { + if (rightQualifier.localSize[i] != -1) + { + if (joinedQualifier.localSize[i] != -1 && + joinedQualifier.localSize[i] != rightQualifier.localSize[i]) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different work group size specifiers", + getWorkGroupSizeString(i)); + } + joinedQualifier.localSize[i] = rightQualifier.localSize[i]; + } + } + + if (rightQualifier.numViews != -1) + { + joinedQualifier.numViews = rightQualifier.numViews; + } + + if (rightQualifier.imageInternalFormat != EiifUnspecified) + { + joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat; + } + + if (rightQualifier.primitiveType != EptUndefined) + { + if (joinedQualifier.primitiveType != EptUndefined && + joinedQualifier.primitiveType != rightQualifier.primitiveType) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different primitive specifiers", + getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType)); + } + joinedQualifier.primitiveType = rightQualifier.primitiveType; + } + + if (rightQualifier.invocations != 0) + { + if (joinedQualifier.invocations != 0 && + joinedQualifier.invocations != rightQualifier.invocations) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different invocations specifiers", + "invocations"); + } + joinedQualifier.invocations = rightQualifier.invocations; + } + + if (rightQualifier.maxVertices != -1) + { + if (joinedQualifier.maxVertices != -1 && + joinedQualifier.maxVertices != rightQualifier.maxVertices) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different max_vertices specifiers", + "max_vertices"); + } + joinedQualifier.maxVertices = rightQualifier.maxVertices; + } + + return joinedQualifier; +} + +unsigned int TInvariantQualifierWrapper::getRank() const +{ + return 0u; +} + +unsigned int TInterpolationQualifierWrapper::getRank() const +{ + return 1u; +} + +unsigned int TLayoutQualifierWrapper::getRank() const +{ + return 2u; +} + +unsigned int TStorageQualifierWrapper::getRank() const +{ + // Force the 'centroid' auxilary storage qualifier to be always first among all storage + // qualifiers. + if (mStorageQualifier == EvqCentroid) + { + return 3u; + } + else + { + return 4u; + } +} + +unsigned int TMemoryQualifierWrapper::getRank() const +{ + return 4u; +} + +unsigned int TPrecisionQualifierWrapper::getRank() const +{ + return 5u; +} + +TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc) + : layoutQualifier(TLayoutQualifier::Create()), + memoryQualifier(TMemoryQualifier::Create()), + precision(EbpUndefined), + qualifier(scope), + invariant(false), + line(loc) +{ + ASSERT(IsScopeQualifier(qualifier)); +} + +TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, + int shaderVersion) + : mShaderVersion(shaderVersion) +{ + ASSERT(IsScopeQualifier(scope->getQualifier())); + mQualifiers.push_back(scope); +} + +void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier) +{ + mQualifiers.push_back(qualifier); +} + +bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const +{ + bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion); + std::string errorMessage; + if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence"); + return false; + } + + if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), errorMessage.c_str(), "qualifier sequence"); + return false; + } + + return true; +} + +TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + ASSERT(static_cast(mQualifiers[0])->getQualifier() == + EvqTemporary); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} + +TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier( + static_cast(mQualifiers[0])->getQualifier(), + mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierTypes.h b/src/3rdparty/angle/src/compiler/translator/QualifierTypes.h new file mode 100644 index 0000000000..10bdeed89d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/QualifierTypes.h @@ -0,0 +1,191 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project 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_QUALIFIER_TYPES_H_ +#define COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ + +#include "common/angleutils.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Types.h" + +namespace sh +{ +class TDiagnostics; + +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics); + +enum TQualifierType +{ + QtInvariant, + QtInterpolation, + QtLayout, + QtStorage, + QtPrecision, + QtMemory +}; + +class TQualifierWrapperBase : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {} + virtual ~TQualifierWrapperBase(){}; + virtual TQualifierType getType() const = 0; + virtual TString getQualifierString() const = 0; + virtual unsigned int getRank() const = 0; + const TSourceLoc &getLine() const { return mLine; } + private: + TSourceLoc mLine; +}; + +class TInvariantQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInvariantQualifierWrapper(const TSourceLoc &line) : TQualifierWrapperBase(line) {} + ~TInvariantQualifierWrapper() {} + + TQualifierType getType() const { return QtInvariant; } + TString getQualifierString() const { return "invariant"; } + unsigned int getRank() const; +}; + +class TInterpolationQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier) + { + } + ~TInterpolationQualifierWrapper() {} + + TQualifierType getType() const { return QtInterpolation; } + TString getQualifierString() const { return sh::getQualifierString(mInterpolationQualifier); } + TQualifier getQualifier() const { return mInterpolationQualifier; } + unsigned int getRank() const; + + private: + TQualifier mInterpolationQualifier; +}; + +class TLayoutQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier) + { + } + ~TLayoutQualifierWrapper() {} + + TQualifierType getType() const { return QtLayout; } + TString getQualifierString() const { return "layout"; } + const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; } + unsigned int getRank() const; + + private: + TLayoutQualifier mLayoutQualifier; +}; + +class TStorageQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mStorageQualifier(storageQualifier) + { + } + ~TStorageQualifierWrapper() {} + + TQualifierType getType() const { return QtStorage; } + TString getQualifierString() const { return sh::getQualifierString(mStorageQualifier); } + TQualifier getQualifier() const { return mStorageQualifier; } + unsigned int getRank() const; + + private: + TQualifier mStorageQualifier; +}; + +class TPrecisionQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier) + { + } + ~TPrecisionQualifierWrapper() {} + + TQualifierType getType() const { return QtPrecision; } + TString getQualifierString() const { return sh::getPrecisionString(mPrecisionQualifier); } + TPrecision getQualifier() const { return mPrecisionQualifier; } + unsigned int getRank() const; + + private: + TPrecision mPrecisionQualifier; +}; + +class TMemoryQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TMemoryQualifierWrapper(TQualifier memoryQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mMemoryQualifier(memoryQualifier) + { + } + ~TMemoryQualifierWrapper() {} + + TQualifierType getType() const { return QtMemory; } + TString getQualifierString() const { return sh::getQualifierString(mMemoryQualifier); } + TQualifier getQualifier() const { return mMemoryQualifier; } + unsigned int getRank() const; + + private: + TQualifier mMemoryQualifier; +}; + +// TTypeQualifier tightly covers type_qualifier from the grammar +struct TTypeQualifier +{ + // initializes all of the qualifiers and sets the scope + TTypeQualifier(TQualifier scope, const TSourceLoc &loc); + + TLayoutQualifier layoutQualifier; + TMemoryQualifier memoryQualifier; + TPrecision precision; + TQualifier qualifier; + bool invariant; + TSourceLoc line; +}; + +// TTypeQualifierBuilder contains all of the qualifiers when type_qualifier gets parsed. +// It is to be used to validate the qualifier sequence and build a TTypeQualifier from it. +class TTypeQualifierBuilder : angle::NonCopyable +{ + public: + using QualifierSequence = TVector; + + public: + POOL_ALLOCATOR_NEW_DELETE(); + TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, int shaderVersion); + // Adds the passed qualifier to the end of the sequence. + void appendQualifier(const TQualifierWrapperBase *qualifier); + // Checks for the order of qualification and repeating qualifiers. + bool checkSequenceIsValid(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a function + // parameter. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getParameterTypeQualifier(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a variable. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getVariableTypeQualifier(TDiagnostics *diagnostics) const; + + private: + QualifierSequence mQualifiers; + int mShaderVersion; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp index 14e88b749a..5233a29f19 100644 --- a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.cpp @@ -3,20 +3,24 @@ // 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. +// 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. +// 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" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -24,7 +28,7 @@ namespace class RecordConstantPrecisionTraverser : public TIntermTraverser { public: - RecordConstantPrecisionTraverser(); + RecordConstantPrecisionTraverser(TSymbolTable *symbolTable); void visitConstantUnion(TIntermConstantUnion *node) override; @@ -37,14 +41,18 @@ class RecordConstantPrecisionTraverser : public TIntermTraverser bool mFoundHigherPrecisionConstant; }; -RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser() - : TIntermTraverser(true, false, true), - mFoundHigherPrecisionConstant(false) +RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFoundHigherPrecisionConstant(false) { } bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand) { + if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock()) + { + return false; + } + const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode(); if (parentAsBinary != nullptr) { @@ -52,15 +60,15 @@ bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TI // its precision has no effect. switch (parentAsBinary->getOp()) { - case EOpInitialize: - case EOpAssign: - case EOpIndexDirect: - case EOpIndexDirectStruct: - case EOpIndexDirectInterfaceBlock: - case EOpIndexIndirect: - return false; - default: - break; + case EOpInitialize: + case EOpAssign: + case EOpIndexDirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + case EOpIndexIndirect: + return false; + default: + break; } TIntermTyped *otherOperand = parentAsBinary->getRight(); @@ -68,9 +76,10 @@ bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TI { 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()) + // 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; } @@ -92,14 +101,15 @@ bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TI { 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. + // 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 && + if (parameter != operand && typedParameter != nullptr && + parameter->getAsConstantUnion() == nullptr && typedParameter->getPrecision() >= operand->getPrecision()) { return false; @@ -114,37 +124,36 @@ void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion * if (mFoundHigherPrecisionConstant) return; - // If the constant has lowp or undefined precision, it can't increase the precision of consuming operations. + // 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. + // 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. + // 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)); + queueReplacement(createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); mFoundHigherPrecisionConstant = true; } void RecordConstantPrecisionTraverser::nextIteration() { - nextTemporaryIndex(); + nextTemporaryId(); mFoundHigherPrecisionConstant = false; } -} // namespace +} // namespace -void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex) +void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable) { - RecordConstantPrecisionTraverser traverser; - ASSERT(temporaryIndex != nullptr); - traverser.useTemporaryIndex(temporaryIndex); + RecordConstantPrecisionTraverser traverser(symbolTable); // Iterate as necessary, and reset the traverser between iterations. do { @@ -152,6 +161,7 @@ void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex) root->traverse(&traverser); if (traverser.foundHigherPrecisionConstant()) traverser.updateTree(); - } - while (traverser.foundHigherPrecisionConstant()); + } while (traverser.foundHigherPrecisionConstant()); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h index 2cd401b418..f86c2a8693 100644 --- a/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h +++ b/src/3rdparty/angle/src/compiler/translator/RecordConstantPrecision.h @@ -3,21 +3,26 @@ // 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. +// 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. +// 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_ +namespace sh +{ class TIntermNode; +class TSymbolTable; -void RecordConstantPrecision(TIntermNode *root, unsigned int *temporaryIndex); +void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh -#endif // COMPILER_TRANSLATOR_RECORDCONSTANTPRECISION_H_ +#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 5e0db2ad26..55fb124a42 100644 --- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.cpp @@ -7,6 +7,9 @@ #include "common/debug.h" #include "compiler/translator/RegenerateStructNames.h" +namespace sh +{ + void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol) { ASSERT(symbol); @@ -16,7 +19,7 @@ void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol) if (!userType) return; - if (mSymbolTable.findBuiltIn(userType->name(), mShaderVersion)) + if (mSymbolTable->findBuiltIn(userType->name(), mShaderVersion)) { // Built-in struct, do not touch it. return; @@ -53,30 +56,21 @@ void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol) return; } std::string id = Str(uniqueId); - TString tmp = kPrefix + TString(id.c_str()); + TString tmp = kPrefix + TString(id.c_str()); tmp += "_" + userType->name(); userType->setName(tmp); } -bool RegenerateStructNames::visitAggregate(Visit, TIntermAggregate *aggregate) +bool RegenerateStructNames::visitBlock(Visit, TIntermBlock *block) { - ASSERT(aggregate); - switch (aggregate->getOp()) + ++mScopeDepth; + TIntermSequence &sequence = *(block->getSequence()); + for (TIntermNode *node : sequence) { - case EOpSequence: - ++mScopeDepth; - { - TIntermSequence &sequence = *(aggregate->getSequence()); - for (size_t ii = 0; ii < sequence.size(); ++ii) - { - TIntermNode *node = sequence[ii]; - ASSERT(node != NULL); - node->traverse(this); - } - } - --mScopeDepth; - return false; - default: - return true; + node->traverse(this); } + --mScopeDepth; + return false; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h index 3b98e5d709..293720b6a4 100644 --- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h +++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h @@ -7,27 +7,29 @@ #ifndef COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ #define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ -#include "compiler/translator/Intermediate.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/SymbolTable.h" #include +namespace sh +{ + class RegenerateStructNames : public TIntermTraverser { public: - RegenerateStructNames(const TSymbolTable &symbolTable, - int shaderVersion) - : TIntermTraverser(true, false, false), - mSymbolTable(symbolTable), + RegenerateStructNames(TSymbolTable *symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false, symbolTable), mShaderVersion(shaderVersion), - mScopeDepth(0) {} + mScopeDepth(0) + { + } protected: void visitSymbol(TIntermSymbol *) override; - bool visitAggregate(Visit, TIntermAggregate *) override; + bool visitBlock(Visit, TIntermBlock *block) override; private: - const TSymbolTable &mSymbolTable; int mShaderVersion; // Indicating the depth of the current scope. @@ -38,4 +40,6 @@ class RegenerateStructNames : public TIntermTraverser std::set mDeclaredGlobalStructs; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.cpp new file mode 100644 index 0000000000..e9e6a17013 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveArrayLengthMethod.cpp: +// Fold array length expressions, including cases where the "this" node has side effects. +// Example: +// int i = (a = b).length(); +// int j = (func()).length(); +// becomes: +// (a = b); +// int i = ; +// func(); +// int j = ; +// +// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps +// have been done to expressions containing calls of the array length method. +// +// Does nothing to length method calls done on runtime-sized arrays. + +#include "compiler/translator/RemoveArrayLengthMethod.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RemoveArrayLengthTraverser : public TIntermTraverser +{ + public: + RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {} + + bool visitUnary(Visit visit, TIntermUnary *node) override; + + void nextIteration() { mFoundArrayLength = false; } + + bool foundArrayLength() const { return mFoundArrayLength; } + + private: + bool mFoundArrayLength; +}; + +bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + // The only case where we leave array length() in place is for runtime-sized arrays. + if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray()) + { + mFoundArrayLength = true; + if (!node->getOperand()->hasSideEffects()) + { + queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED); + return false; + } + insertStatementInParentBlock(node->getOperand()->deepCopy()); + TConstantUnion *constArray = new TConstantUnion[1]; + constArray->setIConst(node->getOperand()->getOutermostArraySize()); + queueReplacement(new TIntermConstantUnion(constArray, node->getType()), + OriginalNode::IS_DROPPED); + return false; + } + return true; +} + +} // anonymous namespace + +void RemoveArrayLengthMethod(TIntermBlock *root) +{ + RemoveArrayLengthTraverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundArrayLength()) + traverser.updateTree(); + } while (traverser.foundArrayLength()); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.h b/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.h new file mode 100644 index 0000000000..3b2c6df824 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveArrayLengthMethod.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveArrayLengthMethod.h: +// Fold array length expressions, including cases where the "this" node has side effects. +// Example: +// int i = (a = b).length(); +// int j = (func()).length(); +// becomes: +// (a = b); +// int i = ; +// func(); +// int j = ; +// +// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps +// have been done to expressions containing calls of the array length method. +// +// Does nothing to length method calls done on runtime-sized arrays. + +namespace sh +{ + +class TIntermBlock; + +void RemoveArrayLengthMethod(TIntermBlock *root); + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp index 74814f22a7..7766c1abc6 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.cpp @@ -9,14 +9,20 @@ #include "compiler/translator/RemoveDynamicIndexing.h" +#include "compiler/translator/Diagnostics.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/SymbolTable.h" +namespace sh +{ + namespace { -TName GetIndexFunctionName(const TType &type, bool write) +std::string GetIndexFunctionName(const TType &type, bool write) { TInfoSinkBase nameSink; nameSink << "dyn_index_"; @@ -49,31 +55,29 @@ TName GetIndexFunctionName(const TType &type, bool write) } nameSink << type.getNominalSize(); } - TString nameString = TFunction::mangleName(nameSink.c_str()); - TName name(nameString); - name.setInternal(true); - return name; + return nameSink.str(); } -TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier) +TIntermSymbol *CreateBaseSymbol(const TType &type, TQualifier qualifier, TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "base", type); + TIntermSymbol *symbol = new TIntermSymbol(symbolTable->nextUniqueId(), "base", type); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(qualifier); return symbol; } -TIntermSymbol *CreateIndexSymbol() +TIntermSymbol *CreateIndexSymbol(TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "index", TType(EbtInt, EbpHigh)); + TIntermSymbol *symbol = + new TIntermSymbol(symbolTable->nextUniqueId(), "index", TType(EbtInt, EbpHigh)); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(EvqIn); return symbol; } -TIntermSymbol *CreateValueSymbol(const TType &type) +TIntermSymbol *CreateValueSymbol(const TType &type, TSymbolTable *symbolTable) { - TIntermSymbol *symbol = new TIntermSymbol(0, "value", type); + TIntermSymbol *symbol = new TIntermSymbol(symbolTable->nextUniqueId(), "value", type); symbol->setInternal(true); symbol->getTypePointer()->setQualifier(EvqIn); return symbol; @@ -86,38 +90,14 @@ TIntermConstantUnion *CreateIntConstantNode(int 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; + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node); + return TIntermAggregate::CreateConstructor(TType(EbtInt), arguments); } TType GetFieldType(const TType &indexedType) @@ -177,7 +157,10 @@ TType GetFieldType(const TType &indexedType) // base[1] = value; // } // Note that else is not used in above functions to avoid the RewriteElseBlocks transformation. -TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) +TIntermFunctionDefinition *GetIndexFunctionDefinition(TType type, + bool write, + const TSymbolUniqueId &functionId, + TSymbolTable *symbolTable) { ASSERT(!type.isArray()); // Conservatively use highp here, even if the indexed type is not highp. That way the code can't @@ -185,11 +168,9 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) // 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; + int numCases = 0; if (type.isMatrix()) { numCases = type.getCols(); @@ -198,41 +179,43 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) { numCases = type.getNominalSize(); } - if (write) - { - indexingFunction->setType(TType(EbtVoid)); - } - else + + TType returnType(EbtVoid); + if (!write) { - indexingFunction->setType(fieldType); + returnType = fieldType; } - TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters); - TQualifier baseQualifier = EvqInOut; + std::string functionName = GetIndexFunctionName(type, write); + TIntermFunctionPrototype *prototypeNode = + CreateInternalFunctionPrototypeNode(returnType, functionName.c_str(), functionId); + + 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); + TIntermSymbol *baseParam = CreateBaseSymbol(type, baseQualifier, symbolTable); + prototypeNode->getSequence()->push_back(baseParam); + TIntermSymbol *indexParam = CreateIndexSymbol(symbolTable); + prototypeNode->getSequence()->push_back(indexParam); + TIntermSymbol *valueParam = nullptr; if (write) { - TIntermSymbol *valueParam = CreateValueSymbol(fieldType); - paramsNode->getSequence()->push_back(valueParam); + valueParam = CreateValueSymbol(fieldType, symbolTable); + prototypeNode->getSequence()->push_back(valueParam); } - indexingFunction->getSequence()->push_back(paramsNode); - TIntermAggregate *statementList = new TIntermAggregate(EOpSequence); + TIntermBlock *statementList = new TIntermBlock(); 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); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(i)); if (write) { - TIntermBinary *assignNode = CreateAssignValueSymbolNode(indexNode, fieldType); + TIntermBinary *assignNode = + new TIntermBinary(EOpAssign, indexNode, valueParam->deepCopy()); statementList->getSequence()->push_back(assignNode); TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); statementList->getSequence()->push_back(returnNode); @@ -250,32 +233,33 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermBranch *breakNode = new TIntermBranch(EOpBreak, nullptr); statementList->getSequence()->push_back(breakNode); - TIntermSwitch *switchNode = new TIntermSwitch(CreateIndexSymbol(), statementList); + TIntermSwitch *switchNode = new TIntermSwitch(indexParam->deepCopy(), statementList); - TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence); + TIntermBlock *bodyNode = new TIntermBlock(); bodyNode->getSequence()->push_back(switchNode); - TIntermBinary *cond = new TIntermBinary(EOpLessThan); + TIntermBinary *cond = + new TIntermBinary(EOpLessThan, indexParam->deepCopy(), CreateIntConstantNode(0)); 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); + TIntermBlock *useFirstBlock = new TIntermBlock(); + TIntermBlock *useLastBlock = new TIntermBlock(); TIntermBinary *indexFirstNode = - CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(0)); TIntermBinary *indexLastNode = - CreateIndexDirectBaseSymbolNode(type, fieldType, numCases - 1, baseQualifier); + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(numCases - 1)); if (write) { - TIntermBinary *assignFirstNode = CreateAssignValueSymbolNode(indexFirstNode, fieldType); + TIntermBinary *assignFirstNode = + new TIntermBinary(EOpAssign, indexFirstNode, valueParam->deepCopy()); useFirstBlock->getSequence()->push_back(assignFirstNode); TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); useFirstBlock->getSequence()->push_back(returnNode); - TIntermBinary *assignLastNode = CreateAssignValueSymbolNode(indexLastNode, fieldType); + TIntermBinary *assignLastNode = + new TIntermBinary(EOpAssign, indexLastNode, valueParam->deepCopy()); useLastBlock->getSequence()->push_back(assignLastNode); } else @@ -286,19 +270,21 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode); useLastBlock->getSequence()->push_back(returnLastNode); } - TIntermSelection *ifNode = new TIntermSelection(cond, useFirstBlock, nullptr); + TIntermIfElse *ifNode = new TIntermIfElse(cond, useFirstBlock, nullptr); bodyNode->getSequence()->push_back(ifNode); bodyNode->getSequence()->push_back(useLastBlock); - indexingFunction->getSequence()->push_back(bodyNode); - + TIntermFunctionDefinition *indexingFunction = + new TIntermFunctionDefinition(prototypeNode, bodyNode); return indexingFunction; } class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser { public: - RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, int shaderVersion); + RemoveDynamicIndexingTraverser(TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics); bool visitBinary(Visit visit, TIntermBinary *node) override; @@ -309,10 +295,11 @@ class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser 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; + // Maps of types that are indexed to the indexing function ids used for them. Note that these + // can not store multiple variants of the same type with different precisions - only one + // precision gets stored. + std::map mIndexedVecAndMatrixTypes; + std::map mWrittenVecAndMatrixTypes; bool mUsedTreeInsertion; @@ -321,62 +308,74 @@ class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser // V[j++][i]++. // where V is an array of vectors, j++ will only be evaluated once. bool mRemoveIndexSideEffectsInSubtree; + + PerformanceDiagnostics *mPerfDiagnostics; }; -RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser(const TSymbolTable &symbolTable, - int shaderVersion) +RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser( + TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics) : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion), mUsedTreeInsertion(false), - mRemoveIndexSideEffectsInSubtree(false) + mRemoveIndexSideEffectsInSubtree(false), + mPerfDiagnostics(perfDiagnostics) { } void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root) { - TIntermAggregate *rootAgg = root->getAsAggregate(); - ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence); + TIntermBlock *rootBlock = root->getAsBlock(); + ASSERT(rootBlock != nullptr); TIntermSequence insertions; - for (TType type : mIndexedVecAndMatrixTypes) + for (auto &type : mIndexedVecAndMatrixTypes) { - insertions.push_back(GetIndexFunctionDefinition(type, false)); + insertions.push_back( + GetIndexFunctionDefinition(type.first, false, *type.second, mSymbolTable)); } - for (TType type : mWrittenVecAndMatrixTypes) + for (auto &type : mWrittenVecAndMatrixTypes) { - insertions.push_back(GetIndexFunctionDefinition(type, true)); + insertions.push_back( + GetIndexFunctionDefinition(type.first, true, *type.second, mSymbolTable)); } - mInsertions.push_back(NodeInsertMultipleEntry(rootAgg, 0, insertions, TIntermSequence())); + rootBlock->insertChildNodes(0, insertions); } // Create a call to dyn_index_*() based on an indirect indexing op node TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node, - TIntermTyped *indexedNode, - TIntermTyped *index) + TIntermTyped *index, + const TSymbolUniqueId &functionId) { ASSERT(node->getOp() == EOpIndexIndirect); - TIntermAggregate *indexingCall = new TIntermAggregate(EOpFunctionCall); + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node->getLeft()); + arguments->push_back(index); + + TType fieldType = GetFieldType(node->getLeft()->getType()); + std::string functionName = GetIndexFunctionName(node->getLeft()->getType(), false); + TIntermAggregate *indexingCall = + CreateInternalFunctionCallNode(fieldType, functionName.c_str(), functionId, arguments); 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); + indexingCall->getFunctionSymbolInfo()->setKnownToNotHaveSideEffects(true); return indexingCall; } TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node, TIntermTyped *index, - TIntermTyped *writtenValue) + TIntermTyped *writtenValue, + const TSymbolUniqueId &functionId) { - // 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); + ASSERT(node->getOp() == EOpIndexIndirect); + TIntermSequence *arguments = new TIntermSequence(); + // Deep copy the child nodes so that two pointers to the same node don't end up in the tree. + arguments->push_back(node->getLeft()->deepCopy()); + arguments->push_back(index->deepCopy()); + arguments->push_back(writtenValue); + + std::string functionName = GetIndexFunctionName(node->getLeft()->getType(), true); TIntermAggregate *indexedWriteCall = - CreateIndexFunctionCall(node, leftCopy->getAsTyped(), index); - indexedWriteCall->setNameObj(GetIndexFunctionName(node->getLeft()->getType(), true)); - indexedWriteCall->setType(TType(EbtVoid)); - indexedWriteCall->getSequence()->push_back(writtenValue); + CreateInternalFunctionCallNode(TType(EbtVoid), functionName.c_str(), functionId, arguments); + indexedWriteCall->setLine(node->getLine()); return indexedWriteCall; } @@ -397,23 +396,40 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // 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); + TIntermDeclaration *initIndex = createTempInitDeclaration(node->getRight()); + insertStatementInParentBlock(initIndex); 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); + queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED); } - else if (!node->getLeft()->isArray() && node->getLeft()->getBasicType() != EbtStruct) + else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node)) { + mPerfDiagnostics->warning(node->getLine(), + "Performance: dynamic indexing of vectors and " + "matrices is emulated and can be slow.", + "[]"); bool write = isLValueRequiredHere(); - TType type = node->getLeft()->getType(); - mIndexedVecAndMatrixTypes.insert(type); +#if defined(ANGLE_ENABLE_ASSERTS) + // Make sure that IntermNodePatternMatcher is consistent with the slightly differently + // implemented checks in this traverser. + IntermNodePatternMatcher matcher( + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue); + ASSERT(matcher.match(node, getParentNode(), isLValueRequiredHere()) == write); +#endif + + const TType &type = node->getLeft()->getType(); + TSymbolUniqueId *indexingFunctionId = new TSymbolUniqueId(mSymbolTable); + if (mIndexedVecAndMatrixTypes.find(type) == mIndexedVecAndMatrixTypes.end()) + { + mIndexedVecAndMatrixTypes[type] = indexingFunctionId; + } + else + { + indexingFunctionId = mIndexedVecAndMatrixTypes[type]; + } if (write) { @@ -432,10 +448,30 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod mRemoveIndexSideEffectsInSubtree = true; return true; } + + TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode(); + if (leftBinary != nullptr && + IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(leftBinary)) + { + // This is a case like: + // mat2 m; + // m[a][b]++; + // Process the child node m[a] first. + 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); + TSymbolUniqueId *indexedWriteFunctionId = new TSymbolUniqueId(mSymbolTable); + if (mWrittenVecAndMatrixTypes.find(type) == mWrittenVecAndMatrixTypes.end()) + { + mWrittenVecAndMatrixTypes[type] = indexedWriteFunctionId; + } + else + { + indexedWriteFunctionId = mWrittenVecAndMatrixTypes[type]; + } TType fieldType = GetFieldType(type); TIntermSequence insertionsBefore; @@ -443,28 +479,26 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // Store the index in a temporary signed int variable. TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight()); - TIntermAggregate *initIndex = createTempInitDeclaration(indexInitializer); + TIntermDeclaration *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 + // Create a node for referring to the index after the nextTemporaryId() call // below. TIntermSymbol *tempIndex = createTempSymbol(indexInitializer->getType()); - nextTemporaryIndex(); // From now on, creating temporary symbols that refer to the - // field value. + TIntermAggregate *indexingCall = + CreateIndexFunctionCall(node, tempIndex, *indexingFunctionId); + + nextTemporaryId(); // From now on, creating temporary symbols that refer to the + // field value. insertionsBefore.push_back(createTempInitDeclaration(indexingCall)); - TIntermAggregate *indexedWriteCall = - CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType)); + TIntermAggregate *indexedWriteCall = CreateIndexedWriteFunctionCall( + node, tempIndex, createTempSymbol(fieldType), *indexedWriteFunctionId); insertionsAfter.push_back(indexedWriteCall); insertStatementsInParentBlock(insertionsBefore, insertionsAfter); - NodeUpdateEntry replaceIndex(getParentNode(), node, createTempSymbol(fieldType), - false); - mReplacements.push_back(replaceIndex); + queueReplacement(createTempSymbol(fieldType), OriginalNode::IS_DROPPED); mUsedTreeInsertion = true; } else @@ -476,9 +510,8 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // 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); + node, EnsureSignedInt(node->getRight()), *indexingFunctionId); + queueReplacement(indexingCall, OriginalNode::IS_DROPPED); } } } @@ -489,25 +522,29 @@ void RemoveDynamicIndexingTraverser::nextIteration() { mUsedTreeInsertion = false; mRemoveIndexSideEffectsInSubtree = false; - nextTemporaryIndex(); + nextTemporaryId(); } } // namespace void RemoveDynamicIndexing(TIntermNode *root, - unsigned int *temporaryIndex, - const TSymbolTable &symbolTable, - int shaderVersion) + TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics) { - RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion); - ASSERT(temporaryIndex != nullptr); - traverser.useTemporaryIndex(temporaryIndex); + RemoveDynamicIndexingTraverser traverser(symbolTable, shaderVersion, perfDiagnostics); do { traverser.nextIteration(); root->traverse(&traverser); traverser.updateTree(); } while (traverser.usedTreeInsertion()); + // TODO(oetuaho@nvidia.com): It might be nicer to add the helper definitions also in the middle + // of traversal. Now the tree ends up in an inconsistent state in the middle, since there are + // function call nodes with no corresponding definition nodes. This needs special handling in + // TIntermLValueTrackingTraverser, and creates intricacies that are not easily apparent from a + // superficial reading of the code. traverser.insertHelperDefinitions(root); - traverser.updateTree(); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h index ae3a93c9b1..543cf569a6 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h +++ b/src/3rdparty/angle/src/compiler/translator/RemoveDynamicIndexing.h @@ -10,12 +10,18 @@ #ifndef COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_ #define COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_ +namespace sh +{ + class TIntermNode; class TSymbolTable; +class PerformanceDiagnostics; void RemoveDynamicIndexing(TIntermNode *root, - unsigned int *temporaryIndex, - const TSymbolTable &symbolTable, - int shaderVersion); + TSymbolTable *symbolTable, + int shaderVersion, + PerformanceDiagnostics *perfDiagnostics); + +} // namespace sh #endif // COMPILER_TRANSLATOR_REMOVEDYNAMICINDEXING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.cpp new file mode 100644 index 0000000000..b39c912e9c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.cpp @@ -0,0 +1,56 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveEmptySwitchStatements.cpp: Remove switch statements that have an empty statement list. + +#include "compiler/translator/RemoveEmptySwitchStatements.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RemoveEmptySwitchStatementsTraverser : public TIntermTraverser +{ + public: + RemoveEmptySwitchStatementsTraverser() : TIntermTraverser(true, false, false) {} + + bool visitSwitch(Visit visit, TIntermSwitch *node); +}; + +bool RemoveEmptySwitchStatementsTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + if (node->getStatementList()->getSequence()->empty()) + { + // Just output the init statement. + if (node->getInit()->hasSideEffects()) + { + queueReplacement(node->getInit(), OriginalNode::IS_DROPPED); + } + else + { + TIntermSequence emptyReplacement; + ASSERT(getParentNode()->getAsBlock()); + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), + node, emptyReplacement)); + } + return false; // Nothing inside the child nodes to traverse. + } + return true; +} + +} // anonymous namespace + +void RemoveEmptySwitchStatements(TIntermBlock *root) +{ + RemoveEmptySwitchStatementsTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.h b/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.h new file mode 100644 index 0000000000..1018a50d82 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveEmptySwitchStatements.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveEmptySwitchStatements.h: Remove switch statements that have an empty statement list. + +#ifndef COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_ + +namespace sh +{ +class TIntermBlock; + +void RemoveEmptySwitchStatements(TIntermBlock *root); +} + +#endif // COMPILER_TRANSLATOR_REMOVEEMPTYSWITCHSTATEMENTS_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.cpp new file mode 100644 index 0000000000..4b533dc7b5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2016 The ANGLE Project 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/RemoveInvariantDeclaration.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that removes invariant declaration for input in fragment shader +// when GLSL >= 4.20 and for output in vertex shader when GLSL < 4.2. +class RemoveInvariantDeclarationTraverser : public TIntermTraverser +{ + public: + RemoveInvariantDeclarationTraverser() : TIntermTraverser(true, false, false) {} + + private: + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement)); + return false; + } +}; + +} // anonymous namespace + +void RemoveInvariantDeclaration(TIntermNode *root) +{ + RemoveInvariantDeclarationTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.h b/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.h new file mode 100644 index 0000000000..cf9d4aa4c2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveInvariantDeclaration.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2016 The ANGLE Project 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_REMOVEINVARIANTDECLARATION_H_ +#define COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_ + +class TIntermNode; +namespace sh +{ + +void RemoveInvariantDeclaration(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp new file mode 100644 index 0000000000..b86d64d7a3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveNoOpCasesFromEndOfSwitchStatements.cpp: Clean up cases from the end of a switch statement +// that only contain no-ops. + +#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +bool AreEmptyBlocks(TIntermSequence *statements, size_t i); + +bool IsEmptyBlock(TIntermNode *node) +{ + TIntermBlock *asBlock = node->getAsBlock(); + if (asBlock) + { + if (asBlock->getSequence()->empty()) + { + return true; + } + return AreEmptyBlocks(asBlock->getSequence(), 0u); + } + // Empty declarations should have already been pruned, otherwise they would need to be handled + // here. Note that declarations for struct types do contain a nameless child node. + ASSERT(node->getAsDeclarationNode() == nullptr || + !node->getAsDeclarationNode()->getSequence()->empty()); + // Pure literal statements should also already be pruned. + ASSERT(node->getAsConstantUnion() == nullptr); + return false; +} + +// Return true if all statements in "statements" starting from index i consist only of empty blocks +// and no-op statements. Returns true also if there are no statements. +bool AreEmptyBlocks(TIntermSequence *statements, size_t i) +{ + for (; i < statements->size(); ++i) + { + if (!IsEmptyBlock(statements->at(i))) + { + return false; + } + } + return true; +} + +void RemoveNoOpCasesFromEndOfStatementList(TIntermBlock *statementList, TSymbolTable *symbolTable) +{ + TIntermSequence *statements = statementList->getSequence(); + + bool foundDeadCase = false; + do + { + if (statements->empty()) + { + return; + } + + // Find the last case label. + size_t i = statements->size(); + while (i > 0u && !(*statements)[i - 1]->getAsCaseNode()) + { + --i; + } + // Now i is the index of the first statement following the last label inside the switch + // statement. + ASSERT(i > 0u); + + foundDeadCase = AreEmptyBlocks(statements, i); + if (foundDeadCase) + { + statements->erase(statements->begin() + (i - 1u), statements->end()); + } + } while (foundDeadCase); +} + +class RemoveNoOpCasesFromEndOfSwitchTraverser : public TIntermTraverser +{ + public: + RemoveNoOpCasesFromEndOfSwitchTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable) + { + } + + bool visitSwitch(Visit visit, TIntermSwitch *node) override; +}; + +bool RemoveNoOpCasesFromEndOfSwitchTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + // Here we may mutate the statement list, but it's safe since traversal has not yet reached + // there. + RemoveNoOpCasesFromEndOfStatementList(node->getStatementList(), mSymbolTable); + // Handle also nested switch statements. + return true; +} + +} // anonymous namespace + +void RemoveNoOpCasesFromEndOfSwitchStatements(TIntermBlock *root, TSymbolTable *symbolTable) +{ + RemoveNoOpCasesFromEndOfSwitchTraverser traverser(symbolTable); + root->traverse(&traverser); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h new file mode 100644 index 0000000000..ebd75eb774 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveNoOpCasesFromEndOfSwitchStatements.h: Clean up cases from the end of a switch statement +// that only contain no-ops. + +#ifndef COMPILER_TRANSLATOR_REMOVENOOPCASESFROMENDOFSWITCHSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_REMOVENOOPCASESFROMENDOFSWITCHSTATEMENTS_H_ + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; + +void RemoveNoOpCasesFromEndOfSwitchStatements(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REMOVENOOPCASESFROMENDOFSWITCHSTATEMENTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp b/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp index 6dbb48da9c..b2cdac55f0 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RemovePow.cpp @@ -11,7 +11,10 @@ #include "compiler/translator/RemovePow.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -43,8 +46,7 @@ class RemovePowTraverser : public TIntermTraverser }; RemovePowTraverser::RemovePowTraverser() - : TIntermTraverser(true, false, false), - mNeedAnotherIteration(false) + : TIntermTraverser(true, false, false), mNeedAnotherIteration(false) { } @@ -52,31 +54,20 @@ 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); + TIntermUnary *log = new TIntermUnary(EOpLog2, x); log->setLine(node->getLine()); - log->setType(x->getType()); - TIntermBinary *mul = new TIntermBinary(EOpMul); - mul->setLeft(y); - mul->setRight(log); + TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType()); + TIntermBinary *mul = new TIntermBinary(op, y, log); mul->setLine(node->getLine()); - bool valid = mul->promote(nullSink); - UNUSED_ASSERTION_VARIABLE(valid); - ASSERT(valid); - TIntermUnary *exp = new TIntermUnary(EOpExp2); - exp->setOperand(mul); + TIntermUnary *exp = new TIntermUnary(EOpExp2, mul); exp->setLine(node->getLine()); - exp->setType(node->getType()); - NodeUpdateEntry replacePow(getParentNode(), node, exp, false); - mReplacements.push_back(replacePow); + queueReplacement(exp, OriginalNode::IS_DROPPED); // 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(). @@ -89,7 +80,7 @@ bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node) return true; } -} // namespace +} // namespace void RemovePow(TIntermNode *root) { @@ -100,6 +91,7 @@ void RemovePow(TIntermNode *root) traverser.nextIteration(); root->traverse(&traverser); traverser.updateTree(); - } - while (traverser.needAnotherIteration()); + } while (traverser.needAnotherIteration()); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemovePow.h b/src/3rdparty/angle/src/compiler/translator/RemovePow.h index 40f9d672b2..3cd84988a9 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemovePow.h +++ b/src/3rdparty/angle/src/compiler/translator/RemovePow.h @@ -11,8 +11,11 @@ #ifndef COMPILER_TRANSLATOR_REMOVEPOW_H_ #define COMPILER_TRANSLATOR_REMOVEPOW_H_ +namespace sh +{ class TIntermNode; void RemovePow(TIntermNode *root); +} // namespace sh -#endif // COMPILER_TRANSLATOR_REMOVEPOW_H_ +#endif // COMPILER_TRANSLATOR_REMOVEPOW_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp index b278b53436..dea949f448 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp @@ -3,36 +3,91 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// RemoveSwitchFallThrough.cpp: Remove fall-through from switch statements. +// Note that it is unsafe to do further AST transformations on the AST generated +// by this function. It leaves duplicate nodes in the AST making replacements +// unreliable. #include "compiler/translator/RemoveSwitchFallThrough.h" -TIntermAggregate *RemoveSwitchFallThrough::removeFallThrough(TIntermAggregate *statementList) +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RemoveSwitchFallThroughTraverser : public TIntermTraverser +{ + public: + static TIntermBlock *removeFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); + + private: + RemoveSwitchFallThroughTraverser(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBinary(Visit, TIntermBinary *node) override; + bool visitUnary(Visit, TIntermUnary *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitSwizzle(Visit, TIntermSwizzle *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit, TIntermSwitch *node) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitBlock(Visit, TIntermBlock *node) override; + bool visitLoop(Visit, TIntermLoop *node) override; + bool visitBranch(Visit, TIntermBranch *node) override; + + void outputSequence(TIntermSequence *sequence, size_t startIndex); + void handlePreviousCase(); + + TIntermBlock *mStatementList; + TIntermBlock *mStatementListOut; + bool mLastStatementWasBreak; + TIntermBlock *mPreviousCase; + std::vector mCasesSharingBreak; + PerformanceDiagnostics *mPerfDiagnostics; +}; + +TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough( + TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) { - RemoveSwitchFallThrough rm(statementList); + RemoveSwitchFallThroughTraverser rm(statementList, perfDiagnostics); ASSERT(statementList); statementList->traverse(&rm); - bool lastStatementWasBreak = rm.mLastStatementWasBreak; - rm.mLastStatementWasBreak = true; - rm.handlePreviousCase(); - if (!lastStatementWasBreak) + ASSERT(rm.mPreviousCase || statementList->getSequence()->empty()); + if (!rm.mLastStatementWasBreak && rm.mPreviousCase) { + // Make sure that there's a branch at the end of the final case inside the switch statement. + // This also ensures that any cases that fall through to the final case will get the break. TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr); - rm.mStatementListOut->getSequence()->push_back(finalBreak); + rm.mPreviousCase->getSequence()->push_back(finalBreak); + rm.mLastStatementWasBreak = true; } + rm.handlePreviousCase(); return rm.mStatementListOut; } -RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermAggregate *statementList) +RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser( + TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) : TIntermTraverser(true, false, false), mStatementList(statementList), mLastStatementWasBreak(false), - mPreviousCase(nullptr) + mPreviousCase(nullptr), + mPerfDiagnostics(perfDiagnostics) { - mStatementListOut = new TIntermAggregate(); - mStatementListOut->setOp(EOpSequence); + mStatementListOut = new TIntermBlock(); } -void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node) +void RemoveSwitchFallThroughTraverser::visitSymbol(TIntermSymbol *node) { // Note that this assumes that switch statements which don't begin by a case statement // have already been weeded out in validation. @@ -40,36 +95,57 @@ void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node) mLastStatementWasBreak = false; } -void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node) +void RemoveSwitchFallThroughTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + // Conditions of case labels are not traversed, so this is a constant statement like "0;". + // These are no-ops so there's no need to add them back to the statement list. Should have + // already been pruned out of the AST, in fact. + UNREACHABLE(); +} + +bool RemoveSwitchFallThroughTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitBinary(Visit, TIntermBinary *node) { - // Conditions of case labels are not traversed, so this is some other constant - // Could be just a statement like "0;" mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; + return false; } -bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node) +bool RemoveSwitchFallThroughTraverser::visitUnary(Visit, TIntermUnary *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; return false; } -bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node) +bool RemoveSwitchFallThroughTraverser::visitTernary(Visit, TIntermTernary *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; return false; } -bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node) +bool RemoveSwitchFallThroughTraverser::visitSwizzle(Visit, TIntermSwizzle *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; return false; } -bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node) +bool RemoveSwitchFallThroughTraverser::visitIfElse(Visit, TIntermIfElse *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; @@ -77,7 +153,7 @@ bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node) return false; } -void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex) +void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex) { for (size_t i = startIndex; i < sequence->size(); ++i) { @@ -85,20 +161,16 @@ void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t s } } -void RemoveSwitchFallThrough::handlePreviousCase() +void RemoveSwitchFallThroughTraverser::handlePreviousCase() { if (mPreviousCase) mCasesSharingBreak.push_back(mPreviousCase); if (mLastStatementWasBreak) { - bool labelsWithNoStatements = true; for (size_t i = 0; i < mCasesSharingBreak.size(); ++i) { - if (mCasesSharingBreak.at(i)->getSequence()->size() > 1) - { - labelsWithNoStatements = false; - } - if (labelsWithNoStatements) + ASSERT(!mCasesSharingBreak.at(i)->getSequence()->empty()); + if (mCasesSharingBreak.at(i)->getSequence()->size() == 1) { // Fall-through is allowed in case the label has no statements. outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0); @@ -106,52 +178,93 @@ void RemoveSwitchFallThrough::handlePreviousCase() else { // Include all the statements that this case can fall through under the same label. + if (mCasesSharingBreak.size() > i + 1u) + { + mPerfDiagnostics->warning(mCasesSharingBreak.at(i)->getLine(), + "Performance: non-empty fall-through cases in " + "switch statements generate extra code.", + "switch"); + } for (size_t j = i; j < mCasesSharingBreak.size(); ++j) { - size_t startIndex = j > i ? 1 : 0; // Add the label only from the first sequence. + size_t startIndex = + j > i ? 1 : 0; // Add the label only from the first sequence. outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex); - } } } mCasesSharingBreak.clear(); } mLastStatementWasBreak = false; - mPreviousCase = nullptr; + mPreviousCase = nullptr; } -bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node) +bool RemoveSwitchFallThroughTraverser::visitCase(Visit, TIntermCase *node) { handlePreviousCase(); - mPreviousCase = new TIntermAggregate(); - mPreviousCase->setOp(EOpSequence); + mPreviousCase = new TIntermBlock(); mPreviousCase->getSequence()->push_back(node); + mPreviousCase->setLine(node->getLine()); // Don't traverse the condition of the case statement return false; } -bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node) +bool RemoveSwitchFallThroughTraverser::visitAggregate(Visit, TIntermAggregate *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool DoesBlockAlwaysBreak(TIntermBlock *node) +{ + if (node->getSequence()->empty()) + { + return false; + } + + TIntermBlock *lastStatementAsBlock = node->getSequence()->back()->getAsBlock(); + if (lastStatementAsBlock) + { + return DoesBlockAlwaysBreak(lastStatementAsBlock); + } + + TIntermBranch *lastStatementAsBranch = node->getSequence()->back()->getAsBranchNode(); + return lastStatementAsBranch != nullptr; +} + +bool RemoveSwitchFallThroughTraverser::visitBlock(Visit, TIntermBlock *node) { if (node != mStatementList) { mPreviousCase->getSequence()->push_back(node); - mLastStatementWasBreak = false; + mLastStatementWasBreak = DoesBlockAlwaysBreak(node); return false; } return true; } -bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node) +bool RemoveSwitchFallThroughTraverser::visitLoop(Visit, TIntermLoop *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; return false; } -bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node) +bool RemoveSwitchFallThroughTraverser::visitBranch(Visit, TIntermBranch *node) { mPreviousCase->getSequence()->push_back(node); // TODO: Verify that accepting return or continue statements here doesn't cause problems. mLastStatementWasBreak = true; return false; } + +} // anonymous namespace + +TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) +{ + return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList, perfDiagnostics); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h index db8699327c..7a3b1963f2 100644 --- a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h @@ -3,41 +3,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// RemoveSwitchFallThrough.h: Remove fall-through from switch statements. +// Note that it is unsafe to do further AST transformations on the AST generated +// by this function. It leaves duplicate nodes in the AST making replacements +// unreliable. #ifndef COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ #define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ -#include "compiler/translator/IntermNode.h" - -class RemoveSwitchFallThrough : public TIntermTraverser +namespace sh { - public: - // When given a statementList from a switch AST node, return an updated - // statementList that has fall-through removed. - static TIntermAggregate *removeFallThrough(TIntermAggregate *statementList); - - private: - RemoveSwitchFallThrough(TIntermAggregate *statementList); - void visitSymbol(TIntermSymbol *node) override; - void visitConstantUnion(TIntermConstantUnion *node) override; - bool visitBinary(Visit, TIntermBinary *node) override; - bool visitUnary(Visit, TIntermUnary *node) override; - bool visitSelection(Visit visit, TIntermSelection *node) override; - bool visitSwitch(Visit, TIntermSwitch *node) override; - bool visitCase(Visit, TIntermCase *node) override; - bool visitAggregate(Visit, TIntermAggregate *node) override; - bool visitLoop(Visit, TIntermLoop *node) override; - bool visitBranch(Visit, TIntermBranch *node) override; +class TIntermBlock; +class PerformanceDiagnostics; - void outputSequence(TIntermSequence *sequence, size_t startIndex); - void handlePreviousCase(); +// When given a statementList from a switch AST node, return an updated +// statementList that has fall-through removed. +TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); - TIntermAggregate *mStatementList; - TIntermAggregate *mStatementListOut; - bool mLastStatementWasBreak; - TIntermAggregate *mPreviousCase; - std::vector mCasesSharingBreak; -}; +} // namespace sh -#endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ +#endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.cpp new file mode 100644 index 0000000000..74b5e73f71 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.cpp @@ -0,0 +1,358 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveUnreferencedVariables.cpp: +// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary +// initialization code for them. Also removes unreferenced struct types. +// + +#include "compiler/translator/RemoveUnreferencedVariables.h" + +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +class CollectVariableRefCountsTraverser : public TIntermTraverser +{ + public: + CollectVariableRefCountsTraverser(); + + using RefCountMap = std::unordered_map; + RefCountMap &getSymbolIdRefCounts() { return mSymbolIdRefCounts; } + RefCountMap &getStructIdRefCounts() { return mStructIdRefCounts; } + + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override; + + private: + void incrementStructTypeRefCount(const TType &type); + + RefCountMap mSymbolIdRefCounts; + + // Structure reference counts are counted from symbols, constructors, function calls, function + // return values and from interface block and structure fields. We need to track both function + // calls and function return values since there's a compiler option not to prune unused + // functions. The type of a constant union may also be a struct, but statements that are just a + // constant union are always pruned, and if the constant union is used somehow it will get + // counted by something else. + RefCountMap mStructIdRefCounts; +}; + +CollectVariableRefCountsTraverser::CollectVariableRefCountsTraverser() + : TIntermTraverser(true, false, false) +{ +} + +void CollectVariableRefCountsTraverser::incrementStructTypeRefCount(const TType &type) +{ + if (type.isInterfaceBlock()) + { + const auto *block = type.getInterfaceBlock(); + ASSERT(block); + + // We can end up incrementing ref counts of struct types referenced from an interface block + // multiple times for the same block. This doesn't matter, because interface blocks can't be + // pruned so we'll never do the reverse operation. + for (const auto &field : block->fields()) + { + ASSERT(!field->type()->isInterfaceBlock()); + incrementStructTypeRefCount(*field->type()); + } + return; + } + + const auto *structure = type.getStruct(); + if (structure != nullptr) + { + auto structIter = mStructIdRefCounts.find(structure->uniqueId()); + if (structIter == mStructIdRefCounts.end()) + { + mStructIdRefCounts[structure->uniqueId()] = 1u; + + for (const auto &field : structure->fields()) + { + incrementStructTypeRefCount(*field->type()); + } + + return; + } + ++(structIter->second); + } +} + +void CollectVariableRefCountsTraverser::visitSymbol(TIntermSymbol *node) +{ + incrementStructTypeRefCount(node->getType()); + + auto iter = mSymbolIdRefCounts.find(node->getId()); + if (iter == mSymbolIdRefCounts.end()) + { + mSymbolIdRefCounts[node->getId()] = 1u; + return; + } + ++(iter->second); +} + +bool CollectVariableRefCountsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + // This tracks struct references in both function calls and constructors. + incrementStructTypeRefCount(node->getType()); + return true; +} + +bool CollectVariableRefCountsTraverser::visitFunctionPrototype(Visit visit, + TIntermFunctionPrototype *node) +{ + incrementStructTypeRefCount(node->getType()); + return true; +} + +// Traverser that removes all unreferenced variables on one traversal. +class RemoveUnreferencedVariablesTraverser : public TIntermTraverser +{ + public: + RemoveUnreferencedVariablesTraverser( + CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts, + CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts, + TSymbolTable *symbolTable); + + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + // Traverse loop and block nodes in reverse order. Note that this traverser does not track + // parent block positions, so insertStatementInParentBlock is unusable! + void traverseBlock(TIntermBlock *block) override; + void traverseLoop(TIntermLoop *loop) override; + + private: + void removeVariableDeclaration(TIntermDeclaration *node, TIntermTyped *declarator); + void decrementStructTypeRefCount(const TType &type); + + CollectVariableRefCountsTraverser::RefCountMap *mSymbolIdRefCounts; + CollectVariableRefCountsTraverser::RefCountMap *mStructIdRefCounts; + bool mRemoveReferences; +}; + +RemoveUnreferencedVariablesTraverser::RemoveUnreferencedVariablesTraverser( + CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts, + CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts, + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), + mSymbolIdRefCounts(symbolIdRefCounts), + mStructIdRefCounts(structIdRefCounts), + mRemoveReferences(false) +{ +} + +void RemoveUnreferencedVariablesTraverser::decrementStructTypeRefCount(const TType &type) +{ + auto *structure = type.getStruct(); + if (structure != nullptr) + { + ASSERT(mStructIdRefCounts->find(structure->uniqueId()) != mStructIdRefCounts->end()); + unsigned int structRefCount = --(*mStructIdRefCounts)[structure->uniqueId()]; + + if (structRefCount == 0) + { + for (const auto &field : structure->fields()) + { + decrementStructTypeRefCount(*field->type()); + } + } + } +} + +void RemoveUnreferencedVariablesTraverser::removeVariableDeclaration(TIntermDeclaration *node, + TIntermTyped *declarator) +{ + if (declarator->getType().isStructSpecifier() && !declarator->getType().isNamelessStruct()) + { + unsigned int structId = declarator->getType().getStruct()->uniqueId(); + if ((*mStructIdRefCounts)[structId] > 1u) + { + // If this declaration declares a named struct type that is used elsewhere, we need to + // keep it. We can still change the declarator though so that it doesn't declare an + // unreferenced variable. + + // Note that since we're not removing the entire declaration, the struct's reference + // count will end up being one less than the correct refcount. But since the struct + // declaration is kept, the incorrect refcount can't cause any other problems. + + if (declarator->getAsSymbolNode() && declarator->getAsSymbolNode()->getSymbol().empty()) + { + // Already an empty declaration - nothing to do. + return; + } + queueReplacementWithParent(node, declarator, + new TIntermSymbol(mSymbolTable->getEmptySymbolId(), + TString(""), declarator->getType()), + OriginalNode::IS_DROPPED); + return; + } + } + + if (getParentNode()->getAsBlock()) + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement)); + } + else + { + ASSERT(getParentNode()->getAsLoopNode()); + queueReplacement(nullptr, OriginalNode::IS_DROPPED); + } +} + +bool RemoveUnreferencedVariablesTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (visit == PreVisit) + { + // SeparateDeclarations should have already been run. + ASSERT(node->getSequence()->size() == 1u); + + TIntermTyped *declarator = node->getSequence()->back()->getAsTyped(); + ASSERT(declarator); + + // We can only remove variables that are not a part of the shader interface. + TQualifier qualifier = declarator->getQualifier(); + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + { + return true; + } + + bool canRemoveVariable = false; + TIntermSymbol *symbolNode = declarator->getAsSymbolNode(); + if (symbolNode != nullptr) + { + canRemoveVariable = + (*mSymbolIdRefCounts)[symbolNode->getId()] == 1u || symbolNode->getSymbol().empty(); + } + TIntermBinary *initNode = declarator->getAsBinaryNode(); + if (initNode != nullptr) + { + ASSERT(initNode->getLeft()->getAsSymbolNode()); + int symbolId = initNode->getLeft()->getAsSymbolNode()->getId(); + canRemoveVariable = + (*mSymbolIdRefCounts)[symbolId] == 1u && !initNode->getRight()->hasSideEffects(); + } + + if (canRemoveVariable) + { + removeVariableDeclaration(node, declarator); + mRemoveReferences = true; + } + return true; + } + ASSERT(visit == PostVisit); + mRemoveReferences = false; + return true; +} + +void RemoveUnreferencedVariablesTraverser::visitSymbol(TIntermSymbol *node) +{ + if (mRemoveReferences) + { + ASSERT(mSymbolIdRefCounts->find(node->getId()) != mSymbolIdRefCounts->end()); + --(*mSymbolIdRefCounts)[node->getId()]; + + decrementStructTypeRefCount(node->getType()); + } +} + +bool RemoveUnreferencedVariablesTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mRemoveReferences) + { + decrementStructTypeRefCount(node->getType()); + } + return true; +} + +void RemoveUnreferencedVariablesTraverser::traverseBlock(TIntermBlock *node) +{ + // We traverse blocks in reverse order. This way reference counts can be decremented when + // removing initializers, and variables that become unused when initializers are removed can be + // removed on the same traversal. + + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = visitBlock(PreVisit, node); + + if (visit) + { + for (auto iter = sequence->rbegin(); iter != sequence->rend(); ++iter) + { + (*iter)->traverse(this); + if (visit && inVisit) + { + if ((iter + 1) != sequence->rend()) + visit = visitBlock(InVisit, node); + } + } + } + + if (visit && postVisit) + visitBlock(PostVisit, node); +} + +void RemoveUnreferencedVariablesTraverser::traverseLoop(TIntermLoop *node) +{ + // We traverse loops in reverse order as well. The loop body gets traversed before the init + // node. + + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + if (preVisit) + visit = visitLoop(PreVisit, node); + + if (visit) + { + // We don't need to traverse loop expressions or conditions since they can't be declarations + // in the AST (loops which have a declaration in their condition get transformed in the + // parsing stage). + ASSERT(node->getExpression() == nullptr || + node->getExpression()->getAsDeclarationNode() == nullptr); + ASSERT(node->getCondition() == nullptr || + node->getCondition()->getAsDeclarationNode() == nullptr); + + if (node->getBody()) + node->getBody()->traverse(this); + + if (node->getInit()) + node->getInit()->traverse(this); + } + + if (visit && postVisit) + visitLoop(PostVisit, node); +} + +} // namespace + +void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable) +{ + CollectVariableRefCountsTraverser collector; + root->traverse(&collector); + RemoveUnreferencedVariablesTraverser traverser(&collector.getSymbolIdRefCounts(), + &collector.getStructIdRefCounts(), symbolTable); + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.h b/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.h new file mode 100644 index 0000000000..39c8327776 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveUnreferencedVariables.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RemoveUnreferencedVariables.h: +// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary +// initialization code for them. Also removes unreferenced struct types. +// + +#ifndef COMPILER_TRANSLATOR_REMOVEUNREFERENCEDVARIABLES_H_ +#define COMPILER_TRANSLATOR_REMOVEUNREFERENCEDVARIABLES_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REMOVEUNREFERENCEDVARIABLES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h deleted file mode 100644 index fd6a365fea..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h +++ /dev/null @@ -1,36 +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. -// - -#ifndef COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ -#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ - -#include "compiler/translator/IntermNode.h" - -// -// Renames a function, including its declaration and any calls to it. -// -class RenameFunction : public TIntermTraverser -{ -public: - RenameFunction(const TString& oldFunctionName, const TString& newFunctionName) - : TIntermTraverser(true, false, false) - , mOldFunctionName(oldFunctionName) - , mNewFunctionName(newFunctionName) {} - - bool visitAggregate(Visit visit, TIntermAggregate *node) override - { - TOperator op = node->getOp(); - if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName) - node->setName(mNewFunctionName); - return true; - } - -private: - const TString mOldFunctionName; - const TString mNewFunctionName; -}; - -#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp index 8347447546..dc3fb7a74e 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.cpp @@ -9,7 +9,10 @@ #include "compiler/translator/RewriteDoWhile.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -41,17 +44,15 @@ namespace class DoWhileRewriter : public TIntermTraverser { public: - DoWhileRewriter() : TIntermTraverser(true, false, false) {} + DoWhileRewriter(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable) + { + } - bool visitAggregate(Visit, TIntermAggregate *node) override + bool visitBlock(Visit, TIntermBlock *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; - } + // A well-formed AST can only have do-while inside TIntermBlock. 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. TIntermSequence *statements = node->getSequence(); @@ -68,10 +69,13 @@ class DoWhileRewriter : public TIntermTraverser continue; } + // Found a loop to change. + nextTemporaryId(); + TType boolType = TType(EbtBool); // bool temp = false; - TIntermAggregate *tempDeclaration = nullptr; + TIntermDeclaration *tempDeclaration = nullptr; { TConstantUnion *falseConstant = new TConstantUnion(); falseConstant->setBConst(false); @@ -95,23 +99,22 @@ class DoWhileRewriter : public TIntermTraverser // break; // } // } - TIntermSelection *breakIf = nullptr; + TIntermIfElse *breakIf = nullptr; { TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr); - TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence); + TIntermBlock *breakBlock = new TIntermBlock(); breakBlock->getSequence()->push_back(breakStatement); - TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot); - negatedCondition->setOperand(loop->getCondition()); + TIntermUnary *negatedCondition = + new TIntermUnary(EOpLogicalNot, loop->getCondition()); - TIntermSelection *innerIf = - new TIntermSelection(negatedCondition, breakBlock, nullptr); + TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr); - TIntermAggregate *innerIfBlock = new TIntermAggregate(EOpSequence); + TIntermBlock *innerIfBlock = new TIntermBlock(); innerIfBlock->getSequence()->push_back(innerIf); - breakIf = new TIntermSelection(createTempSymbol(boolType), innerIfBlock, nullptr); + breakIf = new TIntermIfElse(createTempSymbol(boolType), innerIfBlock, nullptr); } // Assemble the replacement loops, reusing the do-while loop's body and inserting our @@ -122,14 +125,10 @@ class DoWhileRewriter : public TIntermTraverser trueConstant->setBConst(true); TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType); - TIntermAggregate *body = nullptr; - if (loop->getBody() != nullptr) - { - body = loop->getBody()->getAsAggregate(); - } - else + TIntermBlock *body = loop->getBody(); + if (body == nullptr) { - body = new TIntermAggregate(EOpSequence); + body = new TIntermBlock(); } auto sequence = body->getSequence(); sequence->insert(sequence->begin(), assignTrue); @@ -143,8 +142,6 @@ class DoWhileRewriter : public TIntermTraverser replacement.push_back(newLoop); node->replaceChildNodeWithMultiple(loop, replacement); - - nextTemporaryIndex(); } return true; } @@ -152,12 +149,11 @@ class DoWhileRewriter : public TIntermTraverser } // anonymous namespace -void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex) +void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable) { - ASSERT(temporaryIndex != 0); - - DoWhileRewriter rewriter; - rewriter.useTemporaryIndex(temporaryIndex); + DoWhileRewriter rewriter(symbolTable); root->traverse(&rewriter); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h index f6ec1caf06..e83bfc4b56 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h +++ b/src/3rdparty/angle/src/compiler/translator/RewriteDoWhile.h @@ -10,7 +10,14 @@ #ifndef COMPILER_TRANSLATOR_REWRITEDOWHILE_H_ #define COMPILER_TRANSLATOR_REWRITEDOWHILE_H_ +namespace sh +{ + class TIntermNode; -void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex); +class TSymbolTable; + +void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh #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 52ede17434..ed1bfad8a8 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.cpp @@ -8,6 +8,9 @@ // #include "compiler/translator/RewriteElseBlocks.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" #include "compiler/translator/NodeSearch.h" #include "compiler/translator/SymbolTable.h" @@ -20,121 +23,98 @@ namespace class ElseBlockRewriter : public TIntermTraverser { public: - ElseBlockRewriter(); + ElseBlockRewriter(TSymbolTable *symbolTable); protected: - bool visitAggregate(Visit visit, TIntermAggregate *aggregate) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override; + bool visitBlock(Visit visit, TIntermBlock *block) override; private: - const TType *mFunctionType; + TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); - TIntermNode *rewriteSelection(TIntermSelection *selection); + const TType *mFunctionType; }; -TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) +ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr) { - TIntermUnary *unary = new TIntermUnary(op, operand->getType()); - unary->setOperand(operand); - return unary; } -ElseBlockRewriter::ElseBlockRewriter() - : TIntermTraverser(true, false, true), - mFunctionType(NULL) -{} +bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + // Store the current function context (see comment below) + mFunctionType = ((visit == PreVisit) ? &node->getFunctionPrototype()->getType() : nullptr); + return true; +} -bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) +bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node) { - switch (node->getOp()) + if (visit == PostVisit) { - case EOpSequence: - if (visit == PostVisit) + for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); + statementIndex++) { - for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++) + TIntermNode *statement = (*node->getSequence())[statementIndex]; + TIntermIfElse *ifElse = statement->getAsIfElseNode(); + if (ifElse && ifElse->getFalseBlock() != nullptr) { - TIntermNode *statement = (*node->getSequence())[statementIndex]; - TIntermSelection *selection = statement->getAsSelectionNode(); - if (selection && selection->getFalseBlock() != nullptr) - { - // Check for if / else if - TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); - if (elseIfBranch) - { - selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); - delete elseIfBranch; - } - - (*node->getSequence())[statementIndex] = rewriteSelection(selection); - delete selection; - } + (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse); } } - break; - - case EOpFunction: - // Store the current function context (see comment below) - mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL); - break; - - default: break; } - return true; } -TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) +TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse) { - ASSERT(selection != nullptr); + ASSERT(ifElse != nullptr); - nextTemporaryIndex(); + nextTemporaryId(); - TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); - TIntermAggregate *storeCondition = createTempInitDeclaration(typedCondition); + TIntermDeclaration *storeCondition = createTempInitDeclaration(ifElse->getCondition()); - TIntermSelection *falseBlock = nullptr; + TIntermBlock *falseBlock = nullptr; TType boolType(EbtBool, EbpUndefined, EvqTemporary); - if (selection->getFalseBlock()) + if (ifElse->getFalseBlock()) { - TIntermAggregate *negatedElse = nullptr; + TIntermBlock *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 // returns (that are unreachable) we can silence this compile error. if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) { - TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() : - mFunctionType->getBasicString(); - TString rawText = "return (" + typeString + ")0"; - TIntermRaw *returnNode = new TIntermRaw(*mFunctionType, rawText); - negatedElse = new TIntermAggregate(EOpSequence); - negatedElse->getSequence()->push_back(returnNode); + TIntermNode *returnNode = new TIntermBranch(EOpReturn, CreateZeroNode(*mFunctionType)); + negatedElse = new TIntermBlock(); + negatedElse->appendStatement(returnNode); } TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType); - TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse); - falseBlock = new TIntermSelection(negatedCondition, - selection->getFalseBlock(), negatedElse); + TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse); + TIntermIfElse *falseIfElse = + new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); + falseBlock = EnsureBlock(falseIfElse); } TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType); - TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel, selection->getTrueBlock(), falseBlock); + TIntermIfElse *newIfElse = + new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); - TIntermAggregate *block = new TIntermAggregate(EOpSequence); + TIntermBlock *block = new TIntermBlock(); block->getSequence()->push_back(storeCondition); - block->getSequence()->push_back(newSelection); + block->getSequence()->push_back(newIfElse); return block; } -} +} // anonymous namespace -void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex) +void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable) { - ElseBlockRewriter rewriter; - rewriter.useTemporaryIndex(temporaryIndex); + ElseBlockRewriter rewriter(symbolTable); node->traverse(&rewriter); } -} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h index 24a425e66d..2586b5405c 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h @@ -10,13 +10,13 @@ #ifndef COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ #define COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ -#include "compiler/translator/IntermNode.h" - namespace sh { -void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex); +class TIntermNode; +class TSymbolTable; +void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable); } -#endif // COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ +#endif // COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp new file mode 100644 index 0000000000..b602e0c923 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of texelFetchOffset translation issue workaround. +// See header for more info. + +#include "compiler/translator/RewriteTexelFetchOffset.h" + +#include "common/angleutils.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion); + + private: + Traverser(const TSymbolTable &symbolTable, int shaderVersion); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + const TSymbolTable *symbolTable; + const int shaderVersion; + bool mFound = false; +}; + +Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion) +{ +} + +// static +void Traverser::Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion) +{ + Traverser traverser(symbolTable, shaderVersion); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Decide if the node represents the call of texelFetchOffset. + if (node->getOp() != EOpCallBuiltInFunction) + { + return true; + } + + if (node->getFunctionSymbolInfo()->getName() != "texelFetchOffset") + { + return true; + } + + // Potential problem case detected, apply workaround. + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 4u); + + // Decide if the sampler is a 2DArray sampler. In that case position is ivec3 and offset is + // ivec2. + bool is2DArray = sequence->at(1)->getAsTyped()->getNominalSize() == 3 && + sequence->at(3)->getAsTyped()->getNominalSize() == 2; + + // Create new node that represents the call of function texelFetch. + // Its argument list will be: texelFetch(sampler, Position+offset, lod). + + TIntermSequence *texelFetchArguments = new TIntermSequence(); + + // sampler + texelFetchArguments->push_back(sequence->at(0)); + + // Position + TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped(); + ASSERT(texCoordNode); + + // offset + TIntermTyped *offsetNode = nullptr; + ASSERT(sequence->at(3)->getAsTyped()); + if (is2DArray) + { + // For 2DArray samplers, Position is ivec3 and offset is ivec2; + // So offset must be converted into an ivec3 before being added to Position. + TIntermSequence *constructOffsetIvecArguments = new TIntermSequence(); + constructOffsetIvecArguments->push_back(sequence->at(3)->getAsTyped()); + + TIntermTyped *zeroNode = CreateZeroNode(TType(EbtInt)); + constructOffsetIvecArguments->push_back(zeroNode); + + offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(), + constructOffsetIvecArguments); + offsetNode->setLine(texCoordNode->getLine()); + } + else + { + offsetNode = sequence->at(3)->getAsTyped(); + } + + // Position+offset + TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode); + add->setLine(texCoordNode->getLine()); + texelFetchArguments->push_back(add); + + // lod + texelFetchArguments->push_back(sequence->at(2)); + + ASSERT(texelFetchArguments->size() == 3u); + + TIntermTyped *texelFetchNode = CreateBuiltInFunctionCallNode("texelFetch", texelFetchArguments, + *symbolTable, shaderVersion); + texelFetchNode->setLine(node->getLine()); + + // Replace the old node by this new node. + queueReplacement(texelFetchNode, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion) +{ + // texelFetchOffset is only valid in GLSL 3.0 and later. + if (shaderVersion < 300) + return; + + Traverser::Apply(root, symbolTable, shaderVersion); +} + +} // namespace sh \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.h b/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.h new file mode 100644 index 0000000000..694d709f8e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteTexelFetchOffset.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2016 The ANGLE Project 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 mutating tree traversal works around an issue on the translation +// from texelFetchOffset into HLSL function Load on INTEL drivers. It +// works by translating texelFetchOffset into texelFetch: +// +// - From: texelFetchOffset(sampler, Position, lod, offset) +// - To: texelFetch(sampler, Position+offset, lod) +// +// See http://anglebug.com/1469 + +#ifndef COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_ +#define COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_ + +class TIntermNode; +class TSymbolTable; + +namespace sh +{ + +void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp new file mode 100644 index 0000000000..696a49536c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp @@ -0,0 +1,94 @@ +// +// Copyright (c) 2016 The ANGLE Project 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/RewriteUnaryMinusOperatorFloat.h" + +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root); + + private: + Traverser(); + bool visitUnary(Visit visit, TIntermUnary *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root) +{ + Traverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) +{ +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFound) + { + return false; + } + + // Detect if the current operator is unary minus operator. + if (node->getOp() != EOpNegative) + { + return true; + } + + // Detect if the current operand is a float variable. + TIntermTyped *fValue = node->getOperand(); + if (!fValue->getType().isScalarFloat()) + { + return true; + } + + // 0.0 - float + TIntermTyped *zero = CreateZeroNode(fValue->getType()); + zero->setLine(fValue->getLine()); + TIntermBinary *sub = new TIntermBinary(EOpSub, zero, fValue); + sub->setLine(fValue->getLine()); + + queueReplacement(sub, OriginalNode::IS_DROPPED); + + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteUnaryMinusOperatorFloat(TIntermNode *root) +{ + Traverser::Apply(root); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.h b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.h new file mode 100644 index 0000000000..ccbfbcbd9e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorFloat.h @@ -0,0 +1,19 @@ +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Rewrite "-float" to "0.0 - float" to work around unary minus operator on float issue on Intel Mac +// OSX 10.11. + +#ifndef COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORFLOAT_H_ +#define COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORFLOAT_H_ + +class TIntermNode; +namespace sh +{ + +void RewriteUnaryMinusOperatorFloat(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORFLOAT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp new file mode 100644 index 0000000000..fe2ef948b4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp @@ -0,0 +1,112 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Implementation of evaluating unary integer variable bug workaround. +// See header for more info. + +#include "compiler/translator/RewriteUnaryMinusOperatorInt.h" + +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root); + + private: + Traverser(); + bool visitUnary(Visit visit, TIntermUnary *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root) +{ + Traverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) +{ +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFound) + { + return false; + } + + // Decide if the current unary operator is unary minus. + if (node->getOp() != EOpNegative) + { + return true; + } + + // Decide if the current operand is an integer variable. + TIntermTyped *opr = node->getOperand(); + if (!opr->getType().isScalarInt()) + { + return true; + } + + // Potential problem case detected, apply workaround: -(int) -> ~(int) + 1. + // ~(int) + TIntermUnary *bitwiseNot = new TIntermUnary(EOpBitwiseNot, opr); + bitwiseNot->setLine(opr->getLine()); + + // Constant 1 (or 1u) + TConstantUnion *one = new TConstantUnion(); + if (opr->getType().getBasicType() == EbtInt) + { + one->setIConst(1); + } + else + { + one->setUConst(1u); + } + TIntermConstantUnion *oneNode = new TIntermConstantUnion(one, opr->getType()); + oneNode->getTypePointer()->setQualifier(EvqConst); + oneNode->setLine(opr->getLine()); + + // ~(int) + 1 + TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode); + add->setLine(opr->getLine()); + + queueReplacement(add, OriginalNode::IS_DROPPED); + + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteUnaryMinusOperatorInt(TIntermNode *root) +{ + Traverser::Apply(root); +} + +} // namespace sh \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h new file mode 100644 index 0000000000..50f0c442a7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h @@ -0,0 +1,20 @@ +// Copyright (c) 2016 The ANGLE Project 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 mutating tree traversal works around a bug on evaluating unary +// integer variable on Intel D3D driver. It works by rewriting -(int) to +// ~(int) + 1 when evaluating unary integer variables. + +#ifndef COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_ +#define COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_ + +class TIntermNode; +namespace sh +{ + +void RewriteUnaryMinusOperatorInt(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.cpp b/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.cpp new file mode 100644 index 0000000000..3c4209c539 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.cpp @@ -0,0 +1,112 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RunAtTheEndOfShader.cpp: Add code to be run at the end of the shader. In case main() contains a +// return statement, this is done by replacing the main() function with another function that calls +// the old main, like this: +// +// void main() { body } +// => +// void main0() { body } +// void main() +// { +// main0(); +// codeToRun +// } +// +// This way the code will get run even if the return statement inside main is executed. +// + +#include "compiler/translator/RunAtTheEndOfShader.h" + +#include "compiler/translator/FindMain.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +class ContainsReturnTraverser : public TIntermTraverser +{ + public: + ContainsReturnTraverser() : TIntermTraverser(true, false, false), mContainsReturn(false) {} + + bool visitBranch(Visit visit, TIntermBranch *node) override + { + if (node->getFlowOp() == EOpReturn) + { + mContainsReturn = true; + } + return false; + } + + bool containsReturn() { return mContainsReturn; } + + private: + bool mContainsReturn; +}; + +bool ContainsReturn(TIntermNode *node) +{ + ContainsReturnTraverser traverser; + node->traverse(&traverser); + return traverser.containsReturn(); +} + +void WrapMainAndAppend(TIntermBlock *root, + TIntermFunctionDefinition *main, + TIntermNode *codeToRun, + TSymbolTable *symbolTable) +{ + // Replace main() with main0() with the same body. + TSymbolUniqueId oldMainId(symbolTable); + std::stringstream oldMainName; + oldMainName << "main" << oldMainId.get(); + TIntermFunctionDefinition *oldMain = CreateInternalFunctionDefinitionNode( + TType(EbtVoid), oldMainName.str().c_str(), main->getBody(), oldMainId); + + bool replaced = root->replaceChildNode(main, oldMain); + ASSERT(replaced); + + // void main() + TIntermFunctionPrototype *newMainProto = new TIntermFunctionPrototype( + TType(EbtVoid), main->getFunctionPrototype()->getFunctionSymbolInfo()->getId()); + newMainProto->getFunctionSymbolInfo()->setName("main"); + + // { + // main0(); + // codeToRun + // } + TIntermBlock *newMainBody = new TIntermBlock(); + TIntermAggregate *oldMainCall = CreateInternalFunctionCallNode( + TType(EbtVoid), oldMainName.str().c_str(), oldMainId, new TIntermSequence()); + newMainBody->appendStatement(oldMainCall); + newMainBody->appendStatement(codeToRun); + + // Add the new main() to the root node. + TIntermFunctionDefinition *newMain = new TIntermFunctionDefinition(newMainProto, newMainBody); + root->appendStatement(newMain); +} + +} // anonymous namespace + +void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable) +{ + TIntermFunctionDefinition *main = FindMain(root); + if (!ContainsReturn(main)) + { + main->getBody()->appendStatement(codeToRun); + return; + } + + WrapMainAndAppend(root, main, codeToRun, symbolTable); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.h b/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.h new file mode 100644 index 0000000000..ed94c28dae --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RunAtTheEndOfShader.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RunAtTheEndOfShader.h: Add code to be run at the end of the shader. +// + +#ifndef COMPILER_TRANSLATOR_RUNATTHEENDOFSHADER_H_ +#define COMPILER_TRANSLATOR_RUNATTHEENDOFSHADER_H_ + +namespace sh +{ + +class TIntermBlock; +class TIntermNode; +class TSymbolTable; + +void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_RUNATTHEENDOFSHADER_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp index 775c5d8710..746c16e2e6 100644 --- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp @@ -3,6 +3,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// Scalarize vector and matrix constructor args, so that vectors built from components don't have +// matrix arguments, and matrices built from components don't have vector arguments. This avoids +// driver bugs around vector and matrix constructors. +// #include "common/debug.h" #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" @@ -11,6 +15,11 @@ #include "angle_gl.h" #include "common/angleutils.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -37,140 +46,93 @@ bool ContainsVectorNode(const TIntermSequence &sequence) return false; } -TIntermConstantUnion *ConstructIndexNode(int index) +TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) { - TConstantUnion *u = new TConstantUnion[1]; - u[0].setIConst(index); - - TType type(EbtInt, EbpUndefined, EvqConst, 1); - TIntermConstantUnion *node = new TIntermConstantUnion(u, type); - return node; + return new TIntermBinary(EOpIndexDirect, symbolNode, CreateIndexNode(index)); } -TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) +TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermSymbol *symbolNode, int colIndex, int rowIndex) { - TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); - binary->setLeft(symbolNode); - TIntermConstantUnion *indexNode = ConstructIndexNode(index); - binary->setRight(indexNode); - return binary; + TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex); + + return new TIntermBinary(EOpIndexDirect, colVectorNode, CreateIndexNode(rowIndex)); } -TIntermBinary *ConstructMatrixIndexBinaryNode( - TIntermSymbol *symbolNode, int colIndex, int rowIndex) +class ScalarizeArgsTraverser : public TIntermTraverser { - TIntermBinary *colVectorNode = - ConstructVectorIndexBinaryNode(symbolNode, colIndex); + public: + ScalarizeArgsTraverser(sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), + mShaderType(shaderType), + mFragmentPrecisionHigh(fragmentPrecisionHigh) + { + } - TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); - binary->setLeft(colVectorNode); - TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex); - binary->setRight(rowIndexNode); - return binary; -} + protected: + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; -} // namespace anonymous + private: + void scalarizeArgs(TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix); + + // If we have the following code: + // mat4 m(0); + // vec4 v(1, m); + // We will rewrite to: + // mat4 m(0); + // mat4 s0 = m; + // vec4 v(1, s0[0][0], s0[0][1], s0[0][2]); + // This function is to create nodes for "mat4 s0 = m;" and insert it to the code sequence. This + // way the possible side effects of the constructor argument will only be evaluated once. + void createTempVariable(TIntermTyped *original); -bool ScalarizeVecAndMatConstructorArgs::visitAggregate(Visit visit, TIntermAggregate *node) + std::vector mBlockStack; + + sh::GLenum mShaderType; + bool mFragmentPrecisionHigh; +}; + +bool ScalarizeArgsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) { - if (visit == PreVisit) + if (visit == PreVisit && node->getOp() == EOpConstruct) { - switch (node->getOp()) - { - case EOpSequence: - mSequenceStack.push_back(TIntermSequence()); - { - for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); - iter != node->getSequence()->end(); ++iter) - { - TIntermNode *child = *iter; - ASSERT(child != NULL); - child->traverse(this); - mSequenceStack.back().push_back(child); - } - } - if (mSequenceStack.back().size() > node->getSequence()->size()) - { - node->getSequence()->clear(); - *(node->getSequence()) = mSequenceStack.back(); - } - mSequenceStack.pop_back(); - return false; - case EOpConstructVec2: - case EOpConstructVec3: - case EOpConstructVec4: - case EOpConstructBVec2: - case EOpConstructBVec3: - case EOpConstructBVec4: - case EOpConstructIVec2: - case EOpConstructIVec3: - case EOpConstructIVec4: - if (ContainsMatrixNode(*(node->getSequence()))) - scalarizeArgs(node, false, true); - break; - case EOpConstructMat2: - case EOpConstructMat2x3: - case EOpConstructMat2x4: - case EOpConstructMat3x2: - case EOpConstructMat3: - case EOpConstructMat3x4: - case EOpConstructMat4x2: - case EOpConstructMat4x3: - case EOpConstructMat4: - if (ContainsVectorNode(*(node->getSequence()))) - scalarizeArgs(node, true, false); - break; - default: - break; - } + if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence()))) + scalarizeArgs(node, false, true); + else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence()))) + scalarizeArgs(node, true, false); } return true; } -void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( - TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix) +bool ScalarizeArgsTraverser::visitBlock(Visit visit, TIntermBlock *node) { - ASSERT(aggregate); - int size = 0; - switch (aggregate->getOp()) + mBlockStack.push_back(TIntermSequence()); + { + for (TIntermNode *child : *node->getSequence()) + { + ASSERT(child != nullptr); + child->traverse(this); + mBlockStack.back().push_back(child); + } + } + if (mBlockStack.back().size() > node->getSequence()->size()) { - case EOpConstructVec2: - case EOpConstructBVec2: - case EOpConstructIVec2: - size = 2; - break; - case EOpConstructVec3: - case EOpConstructBVec3: - case EOpConstructIVec3: - size = 3; - break; - case EOpConstructVec4: - case EOpConstructBVec4: - case EOpConstructIVec4: - case EOpConstructMat2: - size = 4; - break; - case 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; - default: - break; + node->getSequence()->clear(); + *(node->getSequence()) = mBlockStack.back(); } + mBlockStack.pop_back(); + return false; +} + +void ScalarizeArgsTraverser::scalarizeArgs(TIntermAggregate *aggregate, + bool scalarizeVector, + bool scalarizeMatrix) +{ + ASSERT(aggregate); + ASSERT(!aggregate->isArray()); + int size = static_cast(aggregate->getType().getObjectSize()); TIntermSequence *sequence = aggregate->getSequence(); TIntermSequence original(*sequence); sequence->clear(); @@ -179,12 +141,10 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( ASSERT(size > 0); TIntermTyped *node = original[ii]->getAsTyped(); ASSERT(node); - TString varName = createTempVariable(node); + createTempVariable(node); if (node->isScalar()) { - TIntermSymbol *symbolNode = - new TIntermSymbol(-1, varName, node->getType()); - sequence->push_back(symbolNode); + sequence->push_back(createTempSymbol(node->getType())); size--; } else if (node->isVector()) @@ -195,17 +155,14 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( size -= repeat; for (int index = 0; index < repeat; ++index) { - TIntermSymbol *symbolNode = - new TIntermSymbol(-1, varName, node->getType()); - TIntermBinary *newNode = ConstructVectorIndexBinaryNode( - symbolNode, index); + TIntermSymbol *symbolNode = createTempSymbol(node->getType()); + TIntermBinary *newNode = ConstructVectorIndexBinaryNode(symbolNode, index); sequence->push_back(newNode); } } else { - TIntermSymbol *symbolNode = - new TIntermSymbol(-1, varName, node->getType()); + TIntermSymbol *symbolNode = createTempSymbol(node->getType()); sequence->push_back(symbolNode); size -= node->getNominalSize(); } @@ -220,10 +177,9 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( size -= repeat; while (repeat > 0) { - TIntermSymbol *symbolNode = - new TIntermSymbol(-1, varName, node->getType()); - TIntermBinary *newNode = ConstructMatrixIndexBinaryNode( - symbolNode, colIndex, rowIndex); + TIntermSymbol *symbolNode = createTempSymbol(node->getType()); + TIntermBinary *newNode = + ConstructMatrixIndexBinaryNode(symbolNode, colIndex, rowIndex); sequence->push_back(newNode); rowIndex++; if (rowIndex >= node->getRows()) @@ -236,8 +192,7 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( } else { - TIntermSymbol *symbolNode = - new TIntermSymbol(-1, varName, node->getType()); + TIntermSymbol *symbolNode = createTempSymbol(node->getType()); sequence->push_back(symbolNode); size -= node->getCols() * node->getRows(); } @@ -245,51 +200,39 @@ void ScalarizeVecAndMatConstructorArgs::scalarizeArgs( } } -TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *original) +void ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original) { - TString tempVarName = "_webgl_tmp_"; - if (original->isScalar()) - { - tempVarName += "scalar_"; - } - else if (original->isVector()) - { - tempVarName += "vec_"; - } - else - { - ASSERT(original->isMatrix()); - tempVarName += "mat_"; - } - tempVarName += Str(mTempVarCount).c_str(); - mTempVarCount++; - ASSERT(original); - TType type = original->getType(); - type.setQualifier(EvqTemporary); + nextTemporaryId(); + TIntermDeclaration *decl = createTempInitDeclaration(original); - if (mShaderType == GL_FRAGMENT_SHADER && - type.getBasicType() == EbtFloat && + TType type = original->getType(); + if (mShaderType == GL_FRAGMENT_SHADER && type.getBasicType() == EbtFloat && type.getPrecision() == EbpUndefined) { // We use the highest available precision for the temporary variable // to avoid computing the actual precision using the rules defined // in GLSL ES 1.0 Section 4.5.2. - type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); + TIntermBinary *init = decl->getSequence()->at(0)->getAsBinaryNode(); + init->getTypePointer()->setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); + init->getLeft()->getTypePointer()->setPrecision(mFragmentPrecisionHigh ? EbpHigh + : EbpMedium); } - TIntermBinary *init = new TIntermBinary(EOpInitialize); - TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type); - init->setLeft(symbolNode); - init->setRight(original); - init->setType(type); - - TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration); - decl->getSequence()->push_back(init); - - ASSERT(mSequenceStack.size() > 0); - TIntermSequence &sequence = mSequenceStack.back(); + ASSERT(mBlockStack.size() > 0); + TIntermSequence &sequence = mBlockStack.back(); sequence.push_back(decl); +} + +} // namespace anonymous - return tempVarName; +void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root, + sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable) +{ + ScalarizeArgsTraverser scalarizer(shaderType, fragmentPrecisionHigh, symbolTable); + root->traverse(&scalarizer); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h index d7553be23b..b8f782d1ec 100644 --- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h @@ -3,46 +3,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// Scalarize vector and matrix constructor args, so that vectors built from components don't have +// matrix arguments, and matrices built from components don't have vector arguments. This avoids +// driver bugs around vector and matrix constructors. +// #ifndef COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ #define COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ -#include "compiler/translator/IntermNode.h" +#include "GLSLANG/ShaderLang.h" -class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser +namespace sh { - public: - ScalarizeVecAndMatConstructorArgs(sh::GLenum shaderType, - bool fragmentPrecisionHigh) - : TIntermTraverser(true, false, false), - mTempVarCount(0), - mShaderType(shaderType), - mFragmentPrecisionHigh(fragmentPrecisionHigh) {} - - protected: - bool visitAggregate(Visit visit, TIntermAggregate *node) override; - - private: - void scalarizeArgs(TIntermAggregate *aggregate, - bool scalarizeVector, bool scalarizeMatrix); - - // If we have the following code: - // mat4 m(0); - // vec4 v(1, m); - // We will rewrite to: - // mat4 m(0); - // mat4 _webgl_tmp_mat_0 = m; - // vec4 v(1, _webgl_tmp_mat_0[0][0], _webgl_tmp_mat_0[0][1], _webgl_tmp_mat_0[0][2]); - // This function is to create nodes for "mat4 _webgl_tmp_mat_0 = m;" and insert it to - // the code sequence. - // Return the temporary variable name. - TString createTempVariable(TIntermTyped *original); - - std::vector mSequenceStack; - int mTempVarCount; - - sh::GLenum mShaderType; - bool mFragmentPrecisionHigh; -}; +class TIntermBlock; +class TSymbolTable; + +void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root, + sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable); +} // namespace sh #endif // COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp index cccd4d3ff0..34c644d028 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp @@ -13,8 +13,7 @@ namespace sh { SearchSymbol::SearchSymbol(const TString &symbol) - : TIntermTraverser(true, false, false), - mSymbol(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 1e5e1700d1..b8379e041f 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h @@ -9,7 +9,7 @@ #ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ #define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/ParseContext.h" namespace sh @@ -30,4 +30,4 @@ class SearchSymbol : public TIntermTraverser }; } -#endif // COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ +#endif // COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp index de9050cd80..fe25823e38 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.cpp @@ -3,7 +3,8 @@ // 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. +// The SeparateArrayInitialization function splits each array initialization into a declaration and +// an assignment. // Example: // type[n] a = initializer; // will effectively become @@ -20,6 +21,9 @@ #include "compiler/translator/IntermNode.h" #include "compiler/translator/OutputHLSL.h" +namespace sh +{ + namespace { @@ -27,9 +31,10 @@ class SeparateArrayInitTraverser : private TIntermTraverser { public: static void apply(TIntermNode *root); + private: SeparateArrayInitTraverser(); - bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; }; void SeparateArrayInitTraverser::apply(TIntermNode *root) @@ -39,54 +44,49 @@ void SeparateArrayInitTraverser::apply(TIntermNode *root) separateInit.updateTree(); } -SeparateArrayInitTraverser::SeparateArrayInitTraverser() - : TIntermTraverser(true, false, false) +SeparateArrayInitTraverser::SeparateArrayInitTraverser() : TIntermTraverser(true, false, false) { } -bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node) +bool SeparateArrayInitTraverser::visitDeclaration(Visit, TIntermDeclaration *node) { - if (node->getOp() == EOpDeclaration) + TIntermSequence *sequence = node->getSequence(); + TIntermBinary *initNode = sequence->back()->getAsBinaryNode(); + if (initNode != nullptr && initNode->getOp() == EOpInitialize) { - 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)) { - 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)); - } + // We rely on that array declarations have been isolated to single declarations. + ASSERT(sequence->size() == 1); + TIntermTyped *symbol = initNode->getLeft(); + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + ASSERT(parentBlock != nullptr); + + TIntermSequence replacements; + + TIntermDeclaration *replacementDeclaration = new TIntermDeclaration(); + replacementDeclaration->appendDeclarator(symbol); + replacementDeclaration->setLine(symbol->getLine()); + replacements.push_back(replacementDeclaration); + + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, symbol, initializer); + replacementAssignment->setLine(symbol->getLine()); + replacements.push_back(replacementAssignment); + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); } - return false; } - return true; + return false; } -} // namespace +} // namespace void SeparateArrayInitialization(TIntermNode *root) { SeparateArrayInitTraverser::apply(root); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h index d16357a3af..3a9bb55dd1 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h +++ b/src/3rdparty/angle/src/compiler/translator/SeparateArrayInitialization.h @@ -3,7 +3,8 @@ // 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. +// The SeparateArrayInitialization function splits each array initialization into a declaration and +// an assignment. // Example: // type[n] a = initializer; // will effectively become @@ -18,8 +19,11 @@ #ifndef COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_ #define COMPILER_TRANSLATOR_SEPARATEARRAYINITIALIZATION_H_ +namespace sh +{ class TIntermNode; void SeparateArrayInitialization(TIntermNode *root); +} // namespace sh #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 index d33747f85b..9a066075c0 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.cpp @@ -5,8 +5,8 @@ // // 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. +// 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: @@ -15,7 +15,10 @@ #include "compiler/translator/SeparateDeclarations.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -24,9 +27,10 @@ class SeparateDeclarationsTraverser : private TIntermTraverser { public: static void apply(TIntermNode *root); + private: SeparateDeclarationsTraverser(); - bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; }; void SeparateDeclarationsTraverser::apply(TIntermNode *root) @@ -41,37 +45,35 @@ SeparateDeclarationsTraverser::SeparateDeclarationsTraverser() { } -bool SeparateDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node) +bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node) { - if (node->getOp() == EOpDeclaration) + TIntermSequence *sequence = node->getSequence(); + if (sequence->size() > 1) { - TIntermSequence *sequence = node->getSequence(); - if (sequence->size() > 1) - { - TIntermAggregate *parentAgg = getParentNode()->getAsAggregate(); - ASSERT(parentAgg != nullptr); + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + ASSERT(parentBlock != 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); - } + TIntermSequence replacementDeclarations; + for (size_t ii = 0; ii < sequence->size(); ++ii) + { + TIntermDeclaration *replacementDeclaration = new TIntermDeclaration(); - mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacementDeclarations)); + replacementDeclaration->appendDeclarator(sequence->at(ii)->getAsTyped()); + replacementDeclaration->setLine(sequence->at(ii)->getLine()); + replacementDeclarations.push_back(replacementDeclaration); } - return false; + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacementDeclarations)); } - return true; + return false; } -} // namespace +} // namespace void SeparateDeclarations(TIntermNode *root) { SeparateDeclarationsTraverser::apply(root); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h index 77913ab8bb..8142faea1c 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h +++ b/src/3rdparty/angle/src/compiler/translator/SeparateDeclarations.h @@ -5,8 +5,8 @@ // // 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. +// 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: @@ -16,8 +16,11 @@ #ifndef COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_ #define COMPILER_TRANSLATOR_SEPARATEDECLARATIONS_H_ +namespace sh +{ class TIntermNode; void SeparateDeclarations(TIntermNode *root); +} // namespace sh #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 index e8e1a21d9c..01d627937c 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp @@ -3,15 +3,19 @@ // 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#. +// 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" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -20,7 +24,7 @@ namespace class SeparateExpressionsTraverser : public TIntermTraverser { public: - SeparateExpressionsTraverser(); + SeparateExpressionsTraverser(TSymbolTable *symbolTable); bool visitBinary(Visit visit, TIntermBinary *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override; @@ -29,14 +33,17 @@ class SeparateExpressionsTraverser : public TIntermTraverser 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. + // 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; + + IntermNodePatternMatcher mPatternToSeparateMatcher; }; -SeparateExpressionsTraverser::SeparateExpressionsTraverser() - : TIntermTraverser(true, false, false), - mFoundArrayExpression(false) +SeparateExpressionsTraverser::SeparateExpressionsTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), + mFoundArrayExpression(false), + mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray) { } @@ -45,27 +52,7 @@ SeparateExpressionsTraverser::SeparateExpressionsTraverser() // 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; + return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight()); } bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node) @@ -73,90 +60,59 @@ 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 if the expression is not an array or if we're not inside a complex expression. + if (!mPatternToSeparateMatcher.match(node, getParentNode())) 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; - } + ASSERT(node->getOp() == 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); + + queueReplacement(createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); + + return false; } 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; + return false; // No need to traverse further - TIntermSequence insertions; - insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node))); - insertStatementsInParentBlock(insertions); + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false); - mReplacements.push_back(replaceVariable); + ASSERT(node->isConstructor() || node->getOp() == EOpCallFunctionInAST); - return false; - } - else if (node->getOp() == EOpFunctionCall) - { - mFoundArrayExpression = true; + mFoundArrayExpression = true; - TIntermSequence insertions; - insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node))); - insertStatementsInParentBlock(insertions); + TIntermSequence insertions; + insertions.push_back(createTempInitDeclaration(node->shallowCopy())); + insertStatementsInParentBlock(insertions); - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false); - mReplacements.push_back(replaceVariable); + queueReplacement(createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); - return false; - } - } - return true; + return false; } void SeparateExpressionsTraverser::nextIteration() { mFoundArrayExpression = false; - nextTemporaryIndex(); + nextTemporaryId(); } -} // namespace +} // namespace -void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex) +void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable) { - SeparateExpressionsTraverser traverser; - ASSERT(temporaryIndex != nullptr); - traverser.useTemporaryIndex(temporaryIndex); + SeparateExpressionsTraverser traverser(symbolTable); // Separate one expression at a time, and reset the traverser between iterations. do { @@ -164,6 +120,7 @@ void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *tempora root->traverse(&traverser); if (traverser.foundArrayExpression()) traverser.updateTree(); - } - while (traverser.foundArrayExpression()); + } while (traverser.foundArrayExpression()); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h index b178ebb3ec..f8eb438748 100644 --- a/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h +++ b/src/3rdparty/angle/src/compiler/translator/SeparateExpressionsReturningArrays.h @@ -3,8 +3,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names from more complex -// expressions, assigning them to a temporary variable a#. +// 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]; @@ -12,8 +12,12 @@ #ifndef COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ #define COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ +namespace sh +{ class TIntermNode; +class TSymbolTable; -void SeparateExpressionsReturningArrays(TIntermNode *root, unsigned int *temporaryIndex); +void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh -#endif // COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ +#endif // COMPILER_TRANSLATOR_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Severity.h b/src/3rdparty/angle/src/compiler/translator/Severity.h new file mode 100644 index 0000000000..47808a16a7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Severity.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2016 The ANGLE Project 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_SEVERITY_H_ +#define COMPILER_TRANSLATOR_SEVERITY_H_ + +namespace sh +{ + +// Severity is used to classify info log messages. +enum Severity +{ + SH_WARNING, + SH_ERROR +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SEVERITY_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp index e257f93e48..eeb13f2ec0 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp @@ -16,10 +16,13 @@ #include "compiler/translator/length_limits.h" #ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" -#endif // ANGLE_ENABLE_HLSL +#endif // ANGLE_ENABLE_HLSL #include "compiler/translator/VariablePacker.h" #include "angle_gl.h" +namespace sh +{ + namespace { @@ -34,70 +37,109 @@ template const std::vector *GetVariableList(const TCompiler *compiler); template <> -const std::vector *GetVariableList(const TCompiler *compiler) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getUniforms(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler) +const std::vector *GetVariableList(const TCompiler *compiler) { - return &compiler->getVaryings(); + switch (compiler->getShaderType()) + { + case GL_VERTEX_SHADER: + return &compiler->getOutputVaryings(); + case GL_FRAGMENT_SHADER: + return &compiler->getInputVaryings(); + case GL_COMPUTE_SHADER: + ASSERT(compiler->getOutputVaryings().empty() && compiler->getInputVaryings().empty()); + return &compiler->getOutputVaryings(); + // Since geometry shaders have both input and output varyings, we shouldn't call GetVaryings + // on a geometry shader. + default: + return nullptr; + } } template <> -const std::vector *GetVariableList(const TCompiler *compiler) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getAttributes(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getOutputVariables(); } template <> -const std::vector *GetVariableList(const TCompiler *compiler) +const std::vector *GetVariableList(const TCompiler *compiler) { return &compiler->getInterfaceBlocks(); } -template -const std::vector *GetShaderVariables(const ShHandle handle) +TCompiler *GetCompilerFromHandle(ShHandle handle) { if (!handle) { - return NULL; + return nullptr; } - TShHandleBase* base = static_cast(handle); - TCompiler* compiler = base->getAsCompiler(); + TShHandleBase *base = static_cast(handle); + return base->getAsCompiler(); +} + +template +const std::vector *GetShaderVariables(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); if (!compiler) { - return NULL; + return nullptr; } return GetVariableList(compiler); } -TCompiler *GetCompilerFromHandle(ShHandle handle) -{ - if (!handle) - return NULL; - TShHandleBase *base = static_cast(handle); - return base->getAsCompiler(); -} - #ifdef ANGLE_ENABLE_HLSL TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) { if (!handle) - return NULL; + return nullptr; TShHandleBase *base = static_cast(handle); return base->getAsTranslatorHLSL(); } -#endif // ANGLE_ENABLE_HLSL +#endif // ANGLE_ENABLE_HLSL + +GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) + { + case EptPoints: + return GL_POINTS; + case EptLines: + return GL_LINES; + case EptLinesAdjacency: + return GL_LINES_ADJACENCY_EXT; + case EptTriangles: + return GL_TRIANGLES; + case EptTrianglesAdjacency: + return GL_TRIANGLES_ADJACENCY_EXT; + + case EptLineStrip: + return GL_LINE_STRIP; + case EptTriangleStrip: + return GL_TRIANGLE_STRIP; + + case EptUndefined: + return GL_INVALID_VALUE; + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} } // anonymous namespace @@ -105,7 +147,7 @@ TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) // Driver must call this first, once, before doing any other compiler operations. // Subsequent calls to this function are no-op. // -bool ShInitialize() +bool Initialize() { if (!isInitialized) { @@ -117,7 +159,7 @@ bool ShInitialize() // // Cleanup symbol tables // -bool ShFinalize() +bool Finalize() { if (isInitialized) { @@ -130,33 +172,38 @@ bool ShFinalize() // // Initialize built-in resources with minimum expected values. // -void ShInitBuiltInResources(ShBuiltInResources* resources) +void InitBuiltInResources(ShBuiltInResources *resources) { // Make comparable. memset(resources, 0, sizeof(*resources)); // Constants. - resources->MaxVertexAttribs = 8; - resources->MaxVertexUniformVectors = 128; - resources->MaxVaryingVectors = 8; - resources->MaxVertexTextureImageUnits = 0; + resources->MaxVertexAttribs = 8; + resources->MaxVertexUniformVectors = 128; + resources->MaxVaryingVectors = 8; + resources->MaxVertexTextureImageUnits = 0; resources->MaxCombinedTextureImageUnits = 8; - resources->MaxTextureImageUnits = 8; - resources->MaxFragmentUniformVectors = 16; - resources->MaxDrawBuffers = 1; + resources->MaxTextureImageUnits = 8; + resources->MaxFragmentUniformVectors = 16; + resources->MaxDrawBuffers = 1; // Extensions. - 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; - resources->WEBGL_debug_shader_precision = 0; - resources->EXT_shader_framebuffer_fetch = 0; - resources->NV_shader_framebuffer_fetch = 0; - resources->ARM_shader_framebuffer_fetch = 0; + resources->OES_standard_derivatives = 0; + resources->OES_EGL_image_external = 0; + resources->OES_EGL_image_external_essl3 = 0; + resources->NV_EGL_stream_consumer_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; + resources->WEBGL_debug_shader_precision = 0; + resources->EXT_shader_framebuffer_fetch = 0; + resources->NV_shader_framebuffer_fetch = 0; + resources->ARM_shader_framebuffer_fetch = 0; + resources->OVR_multiview = 0; + resources->EXT_YUV_target = 0; + resources->OES_geometry_shader = 0; resources->NV_draw_buffers = 0; @@ -164,63 +211,125 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->FragmentPrecisionHigh = 0; // GLSL ES 3.0 constants. - resources->MaxVertexOutputVectors = 16; + resources->MaxVertexOutputVectors = 16; resources->MaxFragmentInputVectors = 15; - resources->MinProgramTexelOffset = -8; - resources->MaxProgramTexelOffset = 7; + resources->MinProgramTexelOffset = -8; + resources->MaxProgramTexelOffset = 7; // Extensions constants. resources->MaxDualSourceDrawBuffers = 0; + resources->MaxViewsOVR = 4; + // Disable name hashing by default. - resources->HashFunction = NULL; + resources->HashFunction = nullptr; resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; resources->MaxExpressionComplexity = 256; - resources->MaxCallStackDepth = 256; + resources->MaxCallStackDepth = 256; + resources->MaxFunctionParameters = 1024; + + // ES 3.1 Revision 4, 7.2 Built-in Constants + + // ES 3.1, Revision 4, 8.13 Texture minification + // "The value of MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be less than or equal to the value of + // MIN_PROGRAM_TEXEL_OFFSET. The value of MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be greater than + // or equal to the value of MAX_PROGRAM_TEXEL_OFFSET" + resources->MinProgramTextureGatherOffset = -8; + resources->MaxProgramTextureGatherOffset = 7; + + resources->MaxImageUnits = 4; + resources->MaxVertexImageUniforms = 0; + resources->MaxFragmentImageUniforms = 0; + resources->MaxComputeImageUniforms = 4; + resources->MaxCombinedImageUniforms = 4; + + resources->MaxUniformLocations = 1024; + + resources->MaxCombinedShaderOutputResources = 4; + + resources->MaxComputeWorkGroupCount[0] = 65535; + resources->MaxComputeWorkGroupCount[1] = 65535; + resources->MaxComputeWorkGroupCount[2] = 65535; + resources->MaxComputeWorkGroupSize[0] = 128; + resources->MaxComputeWorkGroupSize[1] = 128; + resources->MaxComputeWorkGroupSize[2] = 64; + resources->MaxComputeUniformComponents = 512; + resources->MaxComputeTextureImageUnits = 16; + + resources->MaxComputeAtomicCounters = 8; + resources->MaxComputeAtomicCounterBuffers = 1; + + resources->MaxVertexAtomicCounters = 0; + resources->MaxFragmentAtomicCounters = 0; + resources->MaxCombinedAtomicCounters = 8; + resources->MaxAtomicCounterBindings = 1; + + resources->MaxVertexAtomicCounterBuffers = 0; + resources->MaxFragmentAtomicCounterBuffers = 0; + resources->MaxCombinedAtomicCounterBuffers = 1; + resources->MaxAtomicCounterBufferSize = 32; + + resources->MaxUniformBufferBindings = 32; + resources->MaxShaderStorageBufferBindings = 4; + + resources->MaxGeometryUniformComponents = 1024; + resources->MaxGeometryUniformBlocks = 12; + resources->MaxGeometryInputComponents = 64; + resources->MaxGeometryOutputComponents = 64; + resources->MaxGeometryOutputVertices = 256; + resources->MaxGeometryTotalOutputComponents = 1024; + resources->MaxGeometryTextureImageUnits = 16; + resources->MaxGeometryAtomicCounterBuffers = 0; + resources->MaxGeometryAtomicCounters = 0; + resources->MaxGeometryShaderStorageBlocks = 0; + resources->MaxGeometryShaderInvocations = 32; + resources->MaxGeometryImageUniforms = 0; } // // Driver calls these to create and destroy compiler objects. // -ShHandle ShConstructCompiler(sh::GLenum type, ShShaderSpec spec, - ShShaderOutput output, - const ShBuiltInResources* resources) +ShHandle ConstructCompiler(sh::GLenum type, + ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources *resources) { - TShHandleBase* base = static_cast(ConstructCompiler(type, spec, output)); + TShHandleBase *base = static_cast(ConstructCompiler(type, spec, output)); if (base == nullptr) { return 0; } - TCompiler* compiler = base->getAsCompiler(); + TCompiler *compiler = base->getAsCompiler(); if (compiler == nullptr) { return 0; } // Generate built-in symbol table. - if (!compiler->Init(*resources)) { - ShDestruct(base); + if (!compiler->Init(*resources)) + { + Destruct(base); return 0; } - return reinterpret_cast(base); + return reinterpret_cast(base); } -void ShDestruct(ShHandle handle) +void Destruct(ShHandle handle) { if (handle == 0) return; - TShHandleBase* base = static_cast(handle); + TShHandleBase *base = static_cast(handle); if (base->getAsCompiler()) DeleteCompiler(base->getAsCompiler()); } -const std::string &ShGetBuiltInResourcesString(const ShHandle handle) +const std::string &GetBuiltInResourcesString(const ShHandle handle) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); @@ -234,11 +343,10 @@ const std::string &ShGetBuiltInResourcesString(const ShHandle handle) // Return: The return value of ShCompile is really boolean, indicating // success or failure. // -bool ShCompile( - const ShHandle handle, - const char *const shaderStrings[], - size_t numStrings, - int compileOptions) +bool Compile(const ShHandle handle, + const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); @@ -246,23 +354,23 @@ bool ShCompile( return compiler->compile(shaderStrings, numStrings, compileOptions); } -void ShClearResults(const ShHandle handle) +void ClearResults(const ShHandle handle) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); compiler->clearResults(); } -int ShGetShaderVersion(const ShHandle handle) +int GetShaderVersion(const ShHandle handle) { - TCompiler* compiler = GetCompilerFromHandle(handle); + TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); return compiler->getShaderVersion(); } -ShShaderOutput ShGetShaderOutputType(const ShHandle handle) +ShShaderOutput GetShaderOutputType(const ShHandle handle) { - TCompiler* compiler = GetCompilerFromHandle(handle); + TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); return compiler->getOutputType(); } @@ -270,7 +378,7 @@ ShShaderOutput ShGetShaderOutputType(const ShHandle handle) // // Return any compiler log of messages for the application. // -const std::string &ShGetInfoLog(const ShHandle handle) +const std::string &GetInfoLog(const ShHandle handle) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); @@ -282,7 +390,7 @@ const std::string &ShGetInfoLog(const ShHandle handle) // // Return any object code. // -const std::string &ShGetObjectCode(const ShHandle handle) +const std::string &GetObjectCode(const ShHandle handle) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); @@ -291,58 +399,107 @@ const std::string &ShGetObjectCode(const ShHandle handle) return infoSink.obj.str(); } -const std::map *ShGetNameHashingMap( - const ShHandle handle) +const std::map *GetNameHashingMap(const ShHandle handle) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); return &(compiler->getNameMap()); } -const std::vector *ShGetUniforms(const ShHandle handle) +const std::vector *GetUniforms(const ShHandle handle) { - return GetShaderVariables(handle); + return GetShaderVariables(handle); } -const std::vector *ShGetVaryings(const ShHandle handle) +const std::vector *GetInputVaryings(const ShHandle handle) { - return GetShaderVariables(handle); + TCompiler *compiler = GetCompilerFromHandle(handle); + if (compiler == nullptr) + { + return nullptr; + } + return &compiler->getInputVaryings(); } -const std::vector *ShGetAttributes(const ShHandle handle) +const std::vector *GetOutputVaryings(const ShHandle handle) { - return GetShaderVariables(handle); + TCompiler *compiler = GetCompilerFromHandle(handle); + if (compiler == nullptr) + { + return nullptr; + } + return &compiler->getOutputVaryings(); } -const std::vector *ShGetOutputVariables(const ShHandle handle) +const std::vector *GetVaryings(const ShHandle handle) { - return GetShaderVariables(handle); + return GetShaderVariables(handle); } -const std::vector *ShGetInterfaceBlocks(const ShHandle handle) +const std::vector *GetAttributes(const ShHandle handle) { - return GetShaderVariables(handle); + return GetShaderVariables(handle); } -bool ShCheckVariablesWithinPackingLimits( - int maxVectors, ShVariableInfo *varInfoArray, size_t varInfoArraySize) +const std::vector *GetOutputVariables(const ShHandle handle) { - if (varInfoArraySize == 0) - return true; - ASSERT(varInfoArray); - std::vector variables; - for (size_t ii = 0; ii < varInfoArraySize; ++ii) - { - sh::ShaderVariable var(varInfoArray[ii].type, varInfoArray[ii].size); - variables.push_back(var); - } - VariablePacker packer; - return packer.CheckVariablesWithinPackingLimits(maxVectors, variables); + return GetShaderVariables(handle); } -bool ShGetInterfaceBlockRegister(const ShHandle handle, - const std::string &interfaceBlockName, - unsigned int *indexOut) +const std::vector *GetInterfaceBlocks(const ShHandle handle) +{ + return GetShaderVariables(handle); +} + +const std::vector *GetUniformBlocks(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return &compiler->getUniformBlocks(); +} + +const std::vector *GetShaderStorageBlocks(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return &compiler->getShaderStorageBlocks(); +} + +WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getComputeShaderLocalSize(); +} + +int GetVertexShaderNumViews(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getNumViews(); +} + +bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector &variables) +{ + return CheckVariablesInPackingLimits(maxVectors, variables); +} + +bool GetUniformBlockRegister(const ShHandle handle, + const std::string &uniformBlockName, + unsigned int *indexOut) { #ifdef ANGLE_ENABLE_HLSL ASSERT(indexOut); @@ -350,35 +507,72 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); ASSERT(translator); - if (!translator->hasInterfaceBlock(interfaceBlockName)) + if (!translator->hasUniformBlock(uniformBlockName)) { return false; } - *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName); + *indexOut = translator->getUniformBlockRegister(uniformBlockName); return true; #else return false; -#endif // ANGLE_ENABLE_HLSL +#endif // ANGLE_ENABLE_HLSL } -bool ShGetUniformRegister(const ShHandle handle, - const std::string &uniformName, - unsigned int *indexOut) +const std::map *GetUniformRegisterMap(const ShHandle handle) { #ifdef ANGLE_ENABLE_HLSL - ASSERT(indexOut); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); ASSERT(translator); - if (!translator->hasUniform(uniformName)) - { - return false; - } - - *indexOut = translator->getUniformRegister(uniformName); - return true; + return translator->getUniformRegisterMap(); #else - return false; -#endif // ANGLE_ENABLE_HLSL + return nullptr; +#endif // ANGLE_ENABLE_HLSL +} + +GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderInputPrimitiveType()); +} + +GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderOutputPrimitiveType()); } + +int GetGeometryShaderInvocations(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderInvocations(); +} + +int GetGeometryShaderMaxVertices(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderMaxVertices(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp index 8f931b9bdd..4ab574e935 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp @@ -10,6 +10,7 @@ #include #include "common/debug.h" +#include "common/utilities.h" namespace sh { @@ -21,7 +22,6 @@ InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolati { return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation); } - } // The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion // on Khronos.org, clarifies that a smooth/flat mismatch produces a link error, @@ -32,55 +32,58 @@ bool InterpolationTypesMatch(InterpolationType a, InterpolationType b) } ShaderVariable::ShaderVariable() - : type(0), - precision(0), - arraySize(0), - staticUse(false) -{} + : type(0), precision(0), flattenedOffsetInParentArrays(0), staticUse(false) +{ +} + +ShaderVariable::ShaderVariable(GLenum typeIn) + : type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false) +{ +} ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) - : type(typeIn), - precision(0), - arraySize(arraySizeIn), - staticUse(false) -{} + : type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false) +{ + ASSERT(arraySizeIn != 0); + arraySizes.push_back(arraySizeIn); +} ShaderVariable::~ShaderVariable() -{} +{ +} ShaderVariable::ShaderVariable(const ShaderVariable &other) : type(other.type), precision(other.precision), name(other.name), mappedName(other.mappedName), - arraySize(other.arraySize), + arraySizes(other.arraySizes), + flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays), staticUse(other.staticUse), fields(other.fields), structName(other.structName) -{} +{ +} ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) { - type = other.type; - precision = other.precision; - name = other.name; + type = other.type; + precision = other.precision; + name = other.name; mappedName = other.mappedName; - arraySize = other.arraySize; - staticUse = other.staticUse; - fields = other.fields; + arraySizes = other.arraySizes; + staticUse = other.staticUse; + flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays; + fields = other.fields; structName = other.structName; return *this; } bool ShaderVariable::operator==(const ShaderVariable &other) const { - if (type != other.type || - precision != other.precision || - name != other.name || - mappedName != other.mappedName || - arraySize != other.arraySize || - staticUse != other.staticUse || - fields.size() != other.fields.size() || + if (type != other.type || precision != other.precision || name != other.name || + mappedName != other.mappedName || arraySizes != other.arraySizes || + staticUse != other.staticUse || fields.size() != other.fields.size() || structName != other.structName) { return false; @@ -93,9 +96,52 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const return true; } -bool ShaderVariable::findInfoByMappedName( - const std::string &mappedFullName, - const ShaderVariable **leafVar, std::string *originalFullName) const +void ShaderVariable::setArraySize(unsigned int size) +{ + arraySizes.clear(); + if (size != 0) + { + arraySizes.push_back(size); + } +} + +unsigned int ShaderVariable::getArraySizeProduct() const +{ + return gl::ArraySizeProduct(arraySizes); +} + +void ShaderVariable::indexIntoArray(unsigned int arrayIndex) +{ + ASSERT(isArray()); + flattenedOffsetInParentArrays = + arrayIndex + getOutermostArraySize() * flattenedOffsetInParentArrays; + arraySizes.pop_back(); +} + +unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const +{ + ASSERT(arraySizes.size() > arrayNestingIndex); + return arraySizes[arraySizes.size() - 1u - arrayNestingIndex]; +} + +unsigned int ShaderVariable::getBasicTypeElementCount() const +{ + // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated + // for each array element when dealing with an array of arrays or an array of structs. + ASSERT(!isArrayOfArrays()); + ASSERT(!isStruct() || !isArray()); + + // GLES 3.1 Nov 2016 page 82. + if (isArray()) + { + return getOutermostArraySize(); + } + return 1u; +} + +bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName, + const ShaderVariable **leafVar, + std::string *originalFullName) const { ASSERT(leafVar && originalFullName); // There are three cases: @@ -110,7 +156,7 @@ bool ShaderVariable::findInfoByMappedName( if (mappedFullName != this->mappedName) return false; *originalFullName = this->name; - *leafVar = this; + *leafVar = this; return true; } else @@ -131,13 +177,13 @@ bool ShaderVariable::findInfoByMappedName( if (closePos + 1 == mappedFullName.size()) { *originalFullName = originalName; - *leafVar = this; + *leafVar = this; return true; } else { // In the form of 'a[0].b', so after ']', '.' is expected. - if (mappedFullName[closePos + 1] != '.') + if (mappedFullName[closePos + 1] != '.') return false; remaining = mappedFullName.substr(closePos + 2); // Skip "]." } @@ -149,14 +195,13 @@ bool ShaderVariable::findInfoByMappedName( } for (size_t ii = 0; ii < this->fields.size(); ++ii) { - const ShaderVariable *fieldVar = NULL; + const ShaderVariable *fieldVar = nullptr; std::string originalFieldName; - bool found = fields[ii].findInfoByMappedName( - remaining, &fieldVar, &originalFieldName); + bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName); if (found) { *originalFullName = originalName + "." + originalFieldName; - *leafVar = fieldVar; + *leafVar = fieldVar; return true; } } @@ -164,24 +209,33 @@ bool ShaderVariable::findInfoByMappedName( } } -bool ShaderVariable::isSameVariableAtLinkTime( - const ShaderVariable &other, bool matchPrecision) const +bool ShaderVariable::isBuiltIn() const +{ + return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_'); +} + +bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other, + bool matchPrecision, + bool matchName) const { if (type != other.type) return false; if (matchPrecision && precision != other.precision) return false; - if (name != other.name) + if (matchName && name != other.name) return false; - ASSERT(mappedName == other.mappedName); - if (arraySize != other.arraySize) + ASSERT(!matchName || mappedName == other.mappedName); + if (arraySizes != other.arraySizes) return false; if (fields.size() != other.fields.size()) return false; + + // [OpenGL ES 3.1 SPEC Chapter 7.4.1] + // Variables declared as structures are considered to match in type if and only if structure + // members match in name, type, qualification, and declaration order. for (size_t ii = 0; ii < fields.size(); ++ii) { - if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], - matchPrecision)) + if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true)) { return false; } @@ -191,53 +245,75 @@ bool ShaderVariable::isSameVariableAtLinkTime( return true; } -Uniform::Uniform() -{} +Uniform::Uniform() : binding(-1), offset(-1) +{ +} Uniform::~Uniform() -{} +{ +} Uniform::Uniform(const Uniform &other) - : ShaderVariable(other) -{} + : VariableWithLocation(other), binding(other.binding), offset(other.offset) +{ +} Uniform &Uniform::operator=(const Uniform &other) { - ShaderVariable::operator=(other); + VariableWithLocation::operator=(other); + binding = other.binding; + offset = other.offset; return *this; } bool Uniform::operator==(const Uniform &other) const { - return ShaderVariable::operator==(other); + return VariableWithLocation::operator==(other) && binding == other.binding && + offset == other.offset; } bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const { - return ShaderVariable::isSameVariableAtLinkTime(other, true); + // Enforce a consistent match. + // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261 + if (binding != -1 && other.binding != -1 && binding != other.binding) + { + return false; + } + if (location != -1 && other.location != -1 && location != other.location) + { + return false; + } + if (offset != other.offset) + { + return false; + } + return VariableWithLocation::isSameVariableAtLinkTime(other, true, true); } -InterfaceVariable::InterfaceVariable() : location(-1) -{} +VariableWithLocation::VariableWithLocation() : location(-1) +{ +} -InterfaceVariable::~InterfaceVariable() -{} +VariableWithLocation::~VariableWithLocation() +{ +} -InterfaceVariable::InterfaceVariable(const InterfaceVariable &other) +VariableWithLocation::VariableWithLocation(const VariableWithLocation &other) : ShaderVariable(other), location(other.location) -{} +{ +} -InterfaceVariable &InterfaceVariable::operator=(const InterfaceVariable &other) +VariableWithLocation &VariableWithLocation::operator=(const VariableWithLocation &other) { ShaderVariable::operator=(other); - location = other.location; + location = other.location; return *this; } -bool InterfaceVariable::operator==(const InterfaceVariable &other) const +bool VariableWithLocation::operator==(const VariableWithLocation &other) const { - return (ShaderVariable::operator==(other) && - location == other.location); + return (ShaderVariable::operator==(other) && location == other.location); } Attribute::Attribute() @@ -248,19 +324,19 @@ Attribute::~Attribute() { } -Attribute::Attribute(const Attribute &other) : InterfaceVariable(other) +Attribute::Attribute(const Attribute &other) : VariableWithLocation(other) { } Attribute &Attribute::operator=(const Attribute &other) { - InterfaceVariable::operator=(other); + VariableWithLocation::operator=(other); return *this; } bool Attribute::operator==(const Attribute &other) const { - return InterfaceVariable::operator==(other); + return VariableWithLocation::operator==(other); } OutputVariable::OutputVariable() @@ -271,79 +347,79 @@ OutputVariable::~OutputVariable() { } -OutputVariable::OutputVariable(const OutputVariable &other) : InterfaceVariable(other) +OutputVariable::OutputVariable(const OutputVariable &other) : VariableWithLocation(other) { } OutputVariable &OutputVariable::operator=(const OutputVariable &other) { - InterfaceVariable::operator=(other); + VariableWithLocation::operator=(other); return *this; } bool OutputVariable::operator==(const OutputVariable &other) const { - return InterfaceVariable::operator==(other); + return VariableWithLocation::operator==(other); } -InterfaceBlockField::InterfaceBlockField() - : isRowMajorLayout(false) -{} +InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) +{ +} InterfaceBlockField::~InterfaceBlockField() -{} +{ +} InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) - : ShaderVariable(other), - isRowMajorLayout(other.isRowMajorLayout) -{} + : ShaderVariable(other), isRowMajorLayout(other.isRowMajorLayout) +{ +} InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other) { ShaderVariable::operator=(other); - isRowMajorLayout = other.isRowMajorLayout; + isRowMajorLayout = other.isRowMajorLayout; return *this; } bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const { - return (ShaderVariable::operator==(other) && - isRowMajorLayout == other.isRowMajorLayout); + return (ShaderVariable::operator==(other) && isRowMajorLayout == other.isRowMajorLayout); } bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime( const InterfaceBlockField &other) const { - return (ShaderVariable::isSameVariableAtLinkTime(other, true) && + return (ShaderVariable::isSameVariableAtLinkTime(other, true, true) && isRowMajorLayout == other.isRowMajorLayout); } -Varying::Varying() - : interpolation(INTERPOLATION_SMOOTH), - isInvariant(false) -{} +Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) +{ +} Varying::~Varying() -{} +{ +} Varying::Varying(const Varying &other) - : ShaderVariable(other), + : VariableWithLocation(other), interpolation(other.interpolation), isInvariant(other.isInvariant) -{} +{ +} Varying &Varying::operator=(const Varying &other) { - ShaderVariable::operator=(other); - interpolation = other.interpolation; - isInvariant = other.isInvariant; + VariableWithLocation::operator=(other); + interpolation = other.interpolation; + isInvariant = other.isInvariant; return *this; } bool Varying::operator==(const Varying &other) const { - return (ShaderVariable::operator==(other) && - interpolation == other.interpolation && + return (VariableWithLocation::operator==(other) && interpolation == other.interpolation && isInvariant == other.isInvariant); } @@ -354,20 +430,26 @@ bool Varying::isSameVaryingAtLinkTime(const Varying &other) const bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const { - return (ShaderVariable::isSameVariableAtLinkTime(other, false) && - interpolation == other.interpolation && - (shaderVersion >= 300 || isInvariant == other.isInvariant)); + return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) && + InterpolationTypesMatch(interpolation, other.interpolation) && + (shaderVersion >= 300 || isInvariant == other.isInvariant) && + (location == other.location) && + (name == other.name || (shaderVersion >= 310 && location >= 0))); } InterfaceBlock::InterfaceBlock() : arraySize(0), layout(BLOCKLAYOUT_PACKED), isRowMajorLayout(false), - staticUse(false) -{} + binding(-1), + staticUse(false), + blockType(BlockType::BLOCK_UNIFORM) +{ +} InterfaceBlock::~InterfaceBlock() -{} +{ +} InterfaceBlock::InterfaceBlock(const InterfaceBlock &other) : name(other.name), @@ -376,20 +458,25 @@ InterfaceBlock::InterfaceBlock(const InterfaceBlock &other) arraySize(other.arraySize), layout(other.layout), isRowMajorLayout(other.isRowMajorLayout), + binding(other.binding), staticUse(other.staticUse), + blockType(other.blockType), fields(other.fields) -{} +{ +} InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other) { - name = other.name; - mappedName = other.mappedName; - instanceName = other.instanceName; - arraySize = other.arraySize; - layout = other.layout; + name = other.name; + mappedName = other.mappedName; + instanceName = other.instanceName; + arraySize = other.arraySize; + layout = other.layout; isRowMajorLayout = other.isRowMajorLayout; - staticUse = other.staticUse; - fields = other.fields; + binding = other.binding; + staticUse = other.staticUse; + blockType = other.blockType; + fields = other.fields; return *this; } @@ -398,4 +485,102 @@ std::string InterfaceBlock::fieldPrefix() const return instanceName.empty() ? "" : name; } +std::string InterfaceBlock::fieldMappedPrefix() const +{ + return instanceName.empty() ? "" : mappedName; +} + +bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const +{ + if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize || + layout != other.layout || isRowMajorLayout != other.isRowMajorLayout || + binding != other.binding || blockType != other.blockType || + fields.size() != other.fields.size()) + { + return false; + } + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex) + { + if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex])) + { + return false; + } + } + + return true; +} + +bool InterfaceBlock::isBuiltIn() const +{ + return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_'); +} + +void WorkGroupSize::fill(int fillValue) +{ + localSizeQualifiers[0] = fillValue; + localSizeQualifiers[1] = fillValue; + localSizeQualifiers[2] = fillValue; +} + +void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ) +{ + localSizeQualifiers[0] = localSizeX; + localSizeQualifiers[1] = localSizeY; + localSizeQualifiers[2] = localSizeZ; +} + +// check that if one of them is less than 1, then all of them are. +// Or if one is positive, then all of them are positive. +bool WorkGroupSize::isLocalSizeValid() const +{ + return ( + (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) || + (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0)); +} + +bool WorkGroupSize::isAnyValueSet() const +{ + return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0; +} + +bool WorkGroupSize::isDeclared() const +{ + bool localSizeDeclared = localSizeQualifiers[0] > 0; + ASSERT(isLocalSizeValid()); + return localSizeDeclared; +} + +bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const +{ + for (size_t i = 0u; i < size(); ++i) + { + bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] || + (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) || + (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1)); + if (!result) + { + return false; + } + } + return true; +} + +int &WorkGroupSize::operator[](size_t index) +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +int WorkGroupSize::operator[](size_t index) const +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +size_t WorkGroupSize::size() const +{ + return 3u; +} + } // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp deleted file mode 100644 index ac5eb67070..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/SimplifyArrayAssignment.h" - -bool SimplifyArrayAssignment::visitBinary(Visit visit, TIntermBinary *node) -{ - switch (node->getOp()) - { - case EOpAssign: - { - TIntermNode *parent = getParentNode(); - if (node->getLeft()->isArray() && parent != nullptr) - { - TIntermAggregate *parentAgg = parent->getAsAggregate(); - if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence) - { - // This case is fine, the result of the assignment is not used. - break; - } - - // The result of the assignment needs to be stored into a temporary variable, - // the assignment needs to be replaced with a reference to the temporary variable, - // and the temporary variable needs to finally be assigned to the target variable. - - // This also needs to interact correctly with unfolding short circuiting operators. - UNIMPLEMENTED(); - } - } - break; - default: - break; - } - return true; -} diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h deleted file mode 100644 index 247eb88d72..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// SimplifyArrayAssignment is an AST traverser to replace statements where -// the return value of array assignment is used with statements where -// the return value of array assignment is not used. -// - -#ifndef COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ -#define COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ - -#include "common/angleutils.h" -#include "compiler/translator/IntermNode.h" - -class SimplifyArrayAssignment : public TIntermTraverser -{ - public: - SimplifyArrayAssignment() { } - - virtual bool visitBinary(Visit visit, TIntermBinary *node); -}; - -#endif // COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.cpp b/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.cpp new file mode 100644 index 0000000000..9704046839 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.cpp @@ -0,0 +1,300 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#include "compiler/translator/SimplifyLoopConditions.h" + +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser +{ + public: + SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable, + int shaderVersion); + + void traverseLoop(TIntermLoop *node) override; + + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + + bool foundLoopToChange() const { return mFoundLoopToChange; } + + protected: + // Marked to true once an operation that needs to be hoisted out of a loop expression has been + // found. + bool mFoundLoopToChange; + bool mInsideLoopInitConditionOrExpression; + IntermNodePatternMatcher mConditionsToSimplify; +}; + +SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser( + unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable, + int shaderVersion) + : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion), + mFoundLoopToChange(false), + mInsideLoopInitConditionOrExpression(false), + mConditionsToSimplify(conditionsToSimplifyMask) +{ +} + +// If we're inside a loop initialization, condition, or expression, we check for expressions that +// should be moved out of the loop condition or expression. If one is found, the loop is +// transformed. +// If we're not inside loop initialization, condition, or expression, we only need to traverse nodes +// that may contain loops. + +bool SimplifyLoopConditionsTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) +{ + // Mark that we're inside a loop condition or expression, and determine if the loop needs to be + // transformed. + + ScopedNodeInTraversalPath addToPath(this, node); + + mInsideLoopInitConditionOrExpression = true; + mFoundLoopToChange = false; + + if (!mFoundLoopToChange && node->getInit()) + { + node->getInit()->traverse(this); + } + + if (!mFoundLoopToChange && node->getCondition()) + { + node->getCondition()->traverse(this); + } + + if (!mFoundLoopToChange && node->getExpression()) + { + node->getExpression()->traverse(this); + } + + mInsideLoopInitConditionOrExpression = false; + + if (mFoundLoopToChange) + { + nextTemporaryId(); + + // Replace the loop condition with a boolean variable that's updated on each iteration. + TLoopType loopType = node->getType(); + if (loopType == ELoopWhile) + { + // Transform: + // while (expr) { body; } + // into + // bool s0 = expr; + // while (s0) { { body; } s0 = expr; } + TIntermSequence tempInitSeq; + tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy())); + insertStatementsInParentBlock(tempInitSeq); + + TIntermBlock *newBody = new TIntermBlock(); + if (node->getBody()) + { + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - the new body will still be + // traversed, but that won't create any problems. + node->setBody(newBody); + node->setCondition(createTempSymbol(node->getCondition()->getType())); + } + else if (loopType == ELoopDoWhile) + { + // Transform: + // do { + // body; + // } while (expr); + // into + // bool s0 = true; + // do { + // { body; } + // s0 = expr; + // } while (s0); + TIntermSequence tempInitSeq; + tempInitSeq.push_back(createTempInitDeclaration(CreateBoolNode(true))); + insertStatementsInParentBlock(tempInitSeq); + + TIntermBlock *newBody = new TIntermBlock(); + if (node->getBody()) + { + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - the new body will still be + // traversed, but that won't create any problems. + node->setBody(newBody); + node->setCondition(createTempSymbol(node->getCondition()->getType())); + } + else if (loopType == ELoopFor) + { + // Move the loop condition inside the loop. + // Transform: + // for (init; expr; exprB) { body; } + // into + // { + // init; + // bool s0 = expr; + // while (s0) { + // { body; } + // exprB; + // s0 = expr; + // } + // } + TIntermBlock *loopScope = new TIntermBlock(); + TIntermSequence *loopScopeSequence = loopScope->getSequence(); + + // Insert "init;" + if (node->getInit()) + { + loopScopeSequence->push_back(node->getInit()); + } + + // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise + TIntermTyped *conditionInitializer = nullptr; + if (node->getCondition()) + { + conditionInitializer = node->getCondition()->deepCopy(); + } + else + { + conditionInitializer = CreateBoolNode(true); + } + loopScopeSequence->push_back(createTempInitDeclaration(conditionInitializer)); + + // Insert "{ body; }" in the while loop + TIntermBlock *whileLoopBody = new TIntermBlock(); + if (node->getBody()) + { + whileLoopBody->getSequence()->push_back(node->getBody()); + } + // Insert "exprB;" in the while loop + if (node->getExpression()) + { + whileLoopBody->getSequence()->push_back(node->getExpression()); + } + // Insert "s0 = expr;" in the while loop + if (node->getCondition()) + { + whileLoopBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + } + + // Create "while(s0) { whileLoopBody }" + TIntermLoop *whileLoop = new TIntermLoop( + ELoopWhile, nullptr, createTempSymbol(conditionInitializer->getType()), nullptr, + whileLoopBody); + loopScope->getSequence()->push_back(whileLoop); + queueReplacement(loopScope, OriginalNode::IS_DROPPED); + + // After this the old body node will be traversed and loops inside it may be + // transformed. This is fine, since the old body node will still be in the AST after the + // transformation that's queued here, and transforming loops inside it doesn't need to + // know the exact post-transform path to it. + } + } + + mFoundLoopToChange = false; + + // We traverse the body of the loop even if the loop is transformed. + if (node->getBody()) + node->getBody()->traverse(this); +} + +} // namespace + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable, + int shaderVersion) +{ + SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable, shaderVersion); + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.h b/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.h new file mode 100644 index 0000000000..d8f95cd2c8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyLoopConditions.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#ifndef COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ +#define COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplify, + TSymbolTable *symbolTable, + int shaderVersion); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.cpp b/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.cpp new file mode 100644 index 0000000000..5df3154560 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.cpp @@ -0,0 +1,171 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#include "compiler/translator/SplitSequenceOperator.h" + +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser +{ + public: + SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, + TSymbolTable *symbolTable, + int shaderVersion); + + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + + void nextIteration(); + bool foundExpressionToSplit() const { return mFoundExpressionToSplit; } + + 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 mFoundExpressionToSplit; + int mInsideSequenceOperator; + + IntermNodePatternMatcher mPatternToSplitMatcher; +}; + +SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, + TSymbolTable *symbolTable, + int shaderVersion) + : TLValueTrackingTraverser(true, false, true, symbolTable, shaderVersion), + mFoundExpressionToSplit(false), + mInsideSequenceOperator(0), + mPatternToSplitMatcher(patternsToSplitMask) +{ +} + +void SplitSequenceOperatorTraverser::nextIteration() +{ + mFoundExpressionToSplit = false; + mInsideSequenceOperator = 0; + nextTemporaryId(); +} + +bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (node->getOp() == EOpComma) + { + if (visit == PreVisit) + { + if (mFoundExpressionToSplit) + { + return false; + } + mInsideSequenceOperator++; + } + else if (visit == PostVisit) + { + // Split sequence operators starting from the outermost one to preserve correct + // execution order. + if (mFoundExpressionToSplit && mInsideSequenceOperator == 1) + { + // Move the left side operand into a separate statement in the parent block. + TIntermSequence insertions; + insertions.push_back(node->getLeft()); + insertStatementsInParentBlock(insertions); + // Replace the comma node with its right side operand. + queueReplacement(node->getRight(), OriginalNode::IS_DROPPED); + } + mInsideSequenceOperator--; + } + return true; + } + + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = + mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); + return !mFoundExpressionToSplit; + } + + return true; +} + +} // namespace + +void SplitSequenceOperator(TIntermNode *root, + int patternsToSplitMask, + TSymbolTable *symbolTable, + int shaderVersion) +{ + SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable, shaderVersion); + // Separate one expression at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundExpressionToSplit()) + traverser.updateTree(); + } while (traverser.foundExpressionToSplit()); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.h b/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.h new file mode 100644 index 0000000000..8f1a766775 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SplitSequenceOperator.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#ifndef COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ +#define COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void SplitSequenceOperator(TIntermNode *root, + int patternsToSplitMask, + TSymbolTable *symbolTable, + int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp index fd1a29c1cd..61a9431ceb 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // // StructureHLSL.cpp: -// Definitions of methods for HLSL translation of GLSL structures. +// HLSL translation of GLSL constructors and structures. // #include "compiler/translator/StructureHLSL.h" @@ -17,23 +17,94 @@ namespace sh { +namespace +{ + +TString Define(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing, + Std140PaddingHelper *padHelper) +{ + const TFieldList &fields = structure.fields(); + const bool isNameless = (structure.name() == ""); + const TString &structName = + QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing); + const TString declareString = (isNameless ? "struct" : "struct " + structName); + + TString string; + string += declareString + + "\n" + "{\n"; + + for (const TField *field : fields) + { + const TType &fieldType = *field->type(); + if (!IsSampler(fieldType.getBasicType())) + { + const TStructure *fieldStruct = fieldType.getStruct(); + const TString &fieldTypeString = + fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, + useStd140Packing) + : TypeString(fieldType); + + if (padHelper) + { + string += padHelper->prePaddingString(fieldType); + } + + string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) + + ArrayString(fieldType) + ";\n"; + + if (padHelper) + { + string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + } + + // Nameless structs do not finish with a semicolon and newline, to leave room for an instance + // variable + string += (isNameless ? "} " : "};\n"); + + return string; +} + +TString WriteParameterList(const std::vector ¶meters) +{ + TString parameterList; + for (size_t parameter = 0u; parameter < parameters.size(); parameter++) + { + const TType ¶mType = parameters[parameter]; + + parameterList += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType); + + if (parameter < parameters.size() - 1u) + { + parameterList += ", "; + } + } + return parameterList; +} + +} // anonymous namespace + Std140PaddingHelper::Std140PaddingHelper(const std::map &structElementIndexes, unsigned *uniqueCounter) - : mPaddingCounter(uniqueCounter), - mElementIndex(0), - mStructElementIndexes(&structElementIndexes) -{} + : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes) +{ +} Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other) : mPaddingCounter(other.mPaddingCounter), mElementIndex(other.mElementIndex), mStructElementIndexes(other.mStructElementIndexes) -{} +{ +} Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other) { - mPaddingCounter = other.mPaddingCounter; - mElementIndex = other.mElementIndex; + mPaddingCounter = other.mPaddingCounter; + mElementIndex = other.mElementIndex; mStructElementIndexes = other.mStructElementIndexes; return *this; } @@ -53,7 +124,7 @@ int Std140PaddingHelper::prePadding(const TType &type) return 0; } - const GLenum glType = GLVariableType(type); + const GLenum glType = GLVariableType(type); const int numComponents = gl::VariableComponentCount(glType); if (numComponents >= 4) @@ -70,9 +141,9 @@ int Std140PaddingHelper::prePadding(const TType &type) return 0; } - const int alignment = numComponents == 3 ? 4 : numComponents; + const int alignment = numComponents == 3 ? 4 : numComponents; const int paddingOffset = (mElementIndex % alignment); - const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0); + const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0); mElementIndex += paddingCount; mElementIndex += numComponents; @@ -102,25 +173,26 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo return ""; } - int numComponents = 0; - TStructure *structure = type.getStruct(); + int numComponents = 0; + const TStructure *structure = type.getStruct(); if (type.isMatrix()) { - // This method can also be called from structureString, which does not use layout qualifiers. + // This method can also be called from structureString, which does not use layout + // qualifiers. // Thus, use the method parameter for determining the matrix packing. // // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we // wish to always transpose GL matrices to play well with HLSL's matrix array indexing. // const bool isRowMajorMatrix = !useHLSLRowMajorPacking; - const GLenum glType = GLVariableType(type); - numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); + const GLenum glType = GLVariableType(type); + numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); } else if (structure) { - const TString &structName = QualifiedStructNameString(*structure, - useHLSLRowMajorPacking, true); + const TString &structName = + QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true); numComponents = mStructElementIndexes->find(structName)->second; if (numComponents == 0) @@ -131,7 +203,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo else { const GLenum glType = GLVariableType(type); - numComponents = gl::VariableComponentCount(glType); + numComponents = gl::VariableComponentCount(glType); } TString padding; @@ -142,178 +214,183 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo return padding; } -StructureHLSL::StructureHLSL() - : mUniquePaddingCounter(0) -{} +StructureHLSL::StructureHLSL() : mUniquePaddingCounter(0) +{ +} Std140PaddingHelper StructureHLSL::getPaddingHelper() { return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter); } -TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing) +TString StructureHLSL::defineQualified(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing) { if (useStd140Packing) { Std140PaddingHelper padHelper = getPaddingHelper(); - return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); + return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); } else { - return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL); + return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr); } } TString StructureHLSL::defineNameless(const TStructure &structure) { - return define(structure, false, false, NULL); + return Define(structure, false, false, nullptr); } -TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking, - bool useStd140Packing, Std140PaddingHelper *padHelper) +StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure, + const TString &name) { - const TFieldList &fields = structure.fields(); - const bool isNameless = (structure.name() == ""); - const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, - useStd140Packing); - const TString declareString = (isNameless ? "struct" : "struct " + structName); + ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end()); - TString string; - string += declareString + "\n" - "{\n"; - - for (unsigned int i = 0; i < fields.size(); i++) + for (const TField *field : structure.fields()) { - const TField &field = *fields[i]; - const TType &fieldType = *field.type(); - const TStructure *fieldStruct = fieldType.getStruct(); - const TString &fieldTypeString = fieldStruct ? - QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, - useStd140Packing) : - TypeString(fieldType); - - if (padHelper) + const TType *fieldType = field->type(); + if (fieldType->getBasicType() == EbtStruct) { - string += padHelper->prePaddingString(fieldType); - } - - string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n"; - - if (padHelper) - { - string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); + ensureStructDefined(*fieldType->getStruct()); } } - // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable - string += (isNameless ? "} " : "};\n"); - - return string; + DefinedStructs::iterator addedStruct = + mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first; + // Add element index + storeStd140ElementIndex(structure, false); + storeStd140ElementIndex(structure, true); + + const TString &structString = defineQualified(structure, false, false); + + ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == + mStructDeclarations.end()); + // Add row-major packed struct for interface blocks + TString rowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(structure, true, false) + + "#pragma pack_matrix(column_major)\n"; + + TString std140String = defineQualified(structure, false, true); + TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(structure, true, true) + + "#pragma pack_matrix(column_major)\n"; + + mStructDeclarations.push_back(structString); + mStructDeclarations.push_back(rowMajorString); + mStructDeclarations.push_back(std140String); + mStructDeclarations.push_back(std140RowMajorString); + return addedStruct; } -void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) +void StructureHLSL::ensureStructDefined(const TStructure &structure) { + const TString name = StructNameString(structure); if (name == "") { - return; // Nameless structures don't have constructors + return; // Nameless structures are not defined } - - if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) + if (mDefinedStructs.find(name) == mDefinedStructs.end()) { - return; // Already added + defineVariants(structure, name); } +} - TType ctorType = type; - ctorType.clearArrayness(); - ctorType.setPrecision(EbpHigh); - ctorType.setQualifier(EvqTemporary); - - typedef std::vector ParameterArray; - ParameterArray ctorParameters; - - const TStructure* structure = type.getStruct(); - if (structure) - { - mStructNames.insert(name); - - // Add element index - storeStd140ElementIndex(*structure, false); - storeStd140ElementIndex(*structure, true); - - const TString &structString = defineQualified(*structure, false, false); - - if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end()) - { - // Add row-major packed struct for interface blocks - TString rowMajorString = "#pragma pack_matrix(row_major)\n" + - defineQualified(*structure, true, false) + - "#pragma pack_matrix(column_major)\n"; - - TString std140String = defineQualified(*structure, false, true); - TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + - defineQualified(*structure, true, true) + - "#pragma pack_matrix(column_major)\n"; - - mStructDeclarations.push_back(structString); - mStructDeclarations.push_back(rowMajorString); - mStructDeclarations.push_back(std140String); - mStructDeclarations.push_back(std140RowMajorString); - } +TString StructureHLSL::addStructConstructor(const TStructure &structure) +{ + const TString name = StructNameString(structure); - const TFieldList &fields = structure->fields(); - for (unsigned int i = 0; i < fields.size(); i++) - { - ctorParameters.push_back(*fields[i]->type()); - } - } - else if (parameters) + if (name == "") { - for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) - { - ctorParameters.push_back((*parameter)->getAsTyped()->getType()); - } + return TString(); // Nameless structures don't have constructors } - else UNREACHABLE(); - - TString constructor; - if (ctorType.getStruct()) + auto definedStruct = mDefinedStructs.find(name); + if (definedStruct == mDefinedStructs.end()) { - constructor += name + " " + name + "_ctor("; + definedStruct = defineVariants(structure, name); } - else // Built-in type + const TString constructorFunctionName = TString(name) + "_ctor"; + TString *constructor = &definedStruct->second->constructor; + if (!constructor->empty()) { - constructor += TypeString(ctorType) + " " + name + "("; + return constructorFunctionName; // Already added } + *constructor += name + " " + constructorFunctionName + "("; - for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) + std::vector ctorParameters; + const TFieldList &fields = structure.fields(); + for (const TField *field : fields) { - const TType ¶mType = ctorParameters[parameter]; - - constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType); - - if (parameter < ctorParameters.size() - 1) + const TType *fieldType = field->type(); + if (!IsSampler(fieldType->getBasicType())) { - constructor += ", "; + ctorParameters.push_back(*fieldType); } } + // Structs that have sampler members should not have constructor calls, and otherwise structs + // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations + // either. + ASSERT(!ctorParameters.empty()); + + *constructor += WriteParameterList(ctorParameters); - constructor += ")\n" - "{\n"; + *constructor += + ")\n" + "{\n" + " " + + name + " structure = { "; - if (ctorType.getStruct()) + for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex) { - constructor += " " + name + " structure = {"; + *constructor += "x" + str(parameterIndex); + if (parameterIndex < ctorParameters.size() - 1u) + { + *constructor += ", "; + } } - else + *constructor += + "};\n" + " return structure;\n" + "}\n"; + + return constructorFunctionName; +} + +TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters) +{ + ASSERT(!type.isArray()); + ASSERT(type.getStruct() == nullptr); + ASSERT(parameters); + + TType ctorType = type; + ctorType.setPrecision(EbpHigh); + ctorType.setQualifier(EvqTemporary); + + const TString constructorFunctionName = + TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters); + TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "("; + + std::vector ctorParameters; + for (auto parameter : *parameters) { - constructor += " return " + TypeString(ctorType) + "("; + const TType ¶mType = parameter->getAsTyped()->getType(); + ASSERT(!paramType.isArray()); + ctorParameters.push_back(paramType); } + constructor += WriteParameterList(ctorParameters); + + constructor += + ")\n" + "{\n" + " return " + + TypeString(ctorType) + "("; if (ctorType.isMatrix() && ctorParameters.size() == 1) { - int rows = ctorType.getRows(); - int cols = ctorType.getCols(); + int rows = ctorType.getRows(); + int cols = ctorType.getCols(); const TType ¶meter = ctorParameters[0]; if (parameter.isScalar()) @@ -355,7 +432,8 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const } else { - ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4); + ASSERT(rows == 2 && cols == 2 && parameter.isVector() && + parameter.getNominalSize() == 4); constructor += "x0"; } @@ -367,20 +445,13 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const while (remainingComponents > 0) { - const TType ¶meter = ctorParameters[parameterIndex]; + const TType ¶meter = ctorParameters[parameterIndex]; const size_t parameterSize = parameter.getObjectSize(); - bool moreParameters = parameterIndex + 1 < ctorParameters.size(); + bool moreParameters = parameterIndex + 1 < ctorParameters.size(); constructor += "x" + str(parameterIndex); - if (ctorType.getStruct()) - { - ASSERT(remainingComponents == parameterSize || moreParameters); - ASSERT(parameterSize <= remainingComponents); - - remainingComponents -= parameterSize; - } - else if (parameter.isScalar()) + if (parameter.isScalar()) { remainingComponents -= parameter.getObjectSize(); } @@ -395,16 +466,26 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const { switch (remainingComponents) { - case 1: constructor += ".x"; break; - case 2: constructor += ".xy"; break; - case 3: constructor += ".xyz"; break; - case 4: constructor += ".xyzw"; break; - default: UNREACHABLE(); + case 1: + constructor += ".x"; + break; + case 2: + constructor += ".xy"; + break; + case 3: + constructor += ".xyz"; + break; + case 4: + constructor += ".xyzw"; + break; + default: + UNREACHABLE(); } remainingComponents = 0; } - else UNREACHABLE(); + else + UNREACHABLE(); } else if (parameter.isMatrix()) { @@ -417,10 +498,17 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const { switch (remainingComponents) { - case 1: constructor += ".x"; break; - case 2: constructor += ".xy"; break; - case 3: constructor += ".xyz"; break; - default: UNREACHABLE(); + case 1: + constructor += ".x"; + break; + case 2: + constructor += ".xy"; + break; + case 3: + constructor += ".xyz"; + break; + default: + UNREACHABLE(); } remainingComponents = 0; @@ -438,7 +526,10 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const column++; } } - else UNREACHABLE(); + else + { + UNREACHABLE(); + } if (moreParameters) { @@ -452,53 +543,52 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const } } - if (ctorType.getStruct()) - { - constructor += "};\n" - " return structure;\n" - "}\n"; - } - else - { - constructor += ");\n" - "}\n"; - } + constructor += + ");\n" + "}\n"; - mConstructors.insert(constructor); + mBuiltInConstructors.insert(constructor); + + return constructorFunctionName; } std::string StructureHLSL::structsHeader() const { TInfoSinkBase out; - for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++) + for (auto &declaration : mStructDeclarations) + { + out << declaration; + } + + for (auto &structure : mDefinedStructs) { - out << mStructDeclarations[structIndex]; + out << structure.second->constructor; } - for (Constructors::const_iterator constructor = mConstructors.begin(); - constructor != mConstructors.end(); - constructor++) + for (auto &constructor : mBuiltInConstructors) { - out << *constructor; + out << constructor; } return out.str(); } -void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking) +void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, + bool useHLSLRowMajorPacking) { Std140PaddingHelper padHelper = getPaddingHelper(); - const TFieldList &fields = structure.fields(); + const TFieldList &fields = structure.fields(); - for (unsigned int i = 0; i < fields.size(); i++) + for (const TField *field : fields) { - padHelper.prePadding(*fields[i]->type()); + padHelper.prePadding(*field->type()); } - // Add remaining element index to the global map, for use with nested structs in standard layouts + // Add remaining element index to the global map, for use with nested structs in standard + // layouts const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true); mStd140StructElementIndexes[structName] = padHelper.elementIndex(); } -} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h index cffe2a41ae..daced8f8d1 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // // StructureHLSL.h: -// Interfaces of methods for HLSL translation of GLSL structures. +// HLSL translation of GLSL constructors and structures. // #ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ @@ -49,11 +49,14 @@ class StructureHLSL : angle::NonCopyable public: StructureHLSL(); - void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); - std::string structsHeader() const; + // Returns the name of the constructor function. + TString addStructConstructor(const TStructure &structure); + TString addBuiltInConstructor(const TType &type, const TIntermSequence *parameters); - TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing); static TString defineNameless(const TStructure &structure); + void ensureStructDefined(const TStructure &structure); + + std::string structsHeader() const; Std140PaddingHelper getPaddingHelper(); @@ -62,20 +65,34 @@ class StructureHLSL : angle::NonCopyable std::map mStd140StructElementIndexes; - typedef std::set StructNames; - StructNames mStructNames; + struct TStructProperties : public angle::NonCopyable + { + POOL_ALLOCATOR_NEW_DELETE(); + + TStructProperties() {} - typedef std::set Constructors; - Constructors mConstructors; + // Constructor is an empty string in case the struct doesn't have a constructor yet. + TString constructor; + }; + // Map from struct name to struct properties. + typedef std::map DefinedStructs; + DefinedStructs mDefinedStructs; + + // Struct declarations need to be kept in a vector instead of having them inside mDefinedStructs + // since maintaining the original order is necessary for nested structs. typedef std::vector StructDeclarations; StructDeclarations mStructDeclarations; + typedef std::set BuiltInConstructors; + BuiltInConstructors mBuiltInConstructors; + void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking); - static TString define(const TStructure &structure, bool useHLSLRowMajorPacking, - bool useStd140Packing, Std140PaddingHelper *padHelper); + TString defineQualified(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing); + DefinedStructs::iterator defineVariants(const TStructure &structure, const TString &name); }; - } -#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ +#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp index dc8f8e3b6b..6c38461469 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp @@ -3,45 +3,87 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // - -// -// Symbol table for parsing. Most functionaliy and main ideas -// are documented in the header file. +// Symbol table for parsing. The design principles and most of the functionality are documented in +// the header file. // #if defined(_MSC_VER) -#pragma warning(disable: 4718) +#pragma warning(disable : 4718) #endif #include "compiler/translator/SymbolTable.h" + #include "compiler/translator/Cache.h" +#include "compiler/translator/IntermNode.h" #include #include -int TSymbolTable::uniqueIdCounter = 0; +namespace sh +{ + +namespace +{ + +static const char kFunctionMangledNameSeparator = '('; + +} // anonymous namespace + +TSymbol::TSymbol(TSymbolTable *symbolTable, const TString *n) + : uniqueId(symbolTable->nextUniqueId()), name(n), extension(TExtension::UNDEFINED) +{ +} // // Functions have buried pointers to delete. // TFunction::~TFunction() +{ + clearParameters(); +} + +void TFunction::clearParameters() { for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) delete (*i).type; + parameters.clear(); + mangledName = nullptr; +} + +void TFunction::swapParameters(const TFunction ¶metersSource) +{ + clearParameters(); + for (auto parameter : parametersSource.parameters) + { + addParameter(parameter); + } } const TString *TFunction::buildMangledName() const { - std::string newName = mangleName(getName()).c_str(); + std::string newName = getName().c_str(); + newName += kFunctionMangledNameSeparator; for (const auto &p : parameters) { - newName += p.type->getMangledName().c_str(); + newName += p.type->getMangledName(); } - return NewPoolTString(newName.c_str()); } +const TString &TFunction::GetMangledNameFromCall(const TString &functionName, + const TIntermSequence &arguments) +{ + std::string newName = functionName.c_str(); + newName += kFunctionMangledNameSeparator; + + for (TIntermNode *argument : arguments) + { + newName += argument->getAsTyped()->getType().getMangledName(); + } + return *NewPoolTString(newName.c_str()); +} + // // Symbol table levels are a map of pointers to symbols that have to be deleted. // @@ -53,8 +95,6 @@ TSymbolTableLevel::~TSymbolTableLevel() bool TSymbolTableLevel::insert(TSymbol *symbol) { - symbol->setUniqueId(TSymbolTable::nextUniqueId()); - // returning true means symbol was added to the table tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol)); @@ -63,8 +103,6 @@ bool TSymbolTableLevel::insert(TSymbol *symbol) bool TSymbolTableLevel::insertUnmangled(TFunction *function) { - function->setUniqueId(TSymbolTable::nextUniqueId()); - // returning true means symbol was added to the table tInsertResult result = level.insert(tLevelPair(function->getName(), function)); @@ -80,22 +118,27 @@ TSymbol *TSymbolTableLevel::find(const TString &name) const return (*it).second; } -TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, - bool *builtIn, bool *sameScope) const +TSymbol *TSymbolTable::find(const TString &name, + int shaderVersion, + bool *builtIn, + bool *sameScope) const { int level = currentLevel(); TSymbol *symbol; do { - if (level == ESSL3_BUILTINS && shaderVersion != 300) + if (level == GLSL_BUILTINS) + level--; + if (level == ESSL3_1_BUILTINS && shaderVersion != 310) + level--; + if (level == ESSL3_BUILTINS && shaderVersion < 300) level--; if (level == ESSL1_BUILTINS && shaderVersion != 100) level--; symbol = table[level]->find(name); - } - while (symbol == 0 && --level >= 0); + } while (symbol == 0 && --level >= 0); if (builtIn) *builtIn = (level <= LAST_BUILTIN_LEVEL); @@ -105,12 +148,28 @@ TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, return symbol; } -TSymbol *TSymbolTable::findBuiltIn( - const TString &name, int shaderVersion) const +TSymbol *TSymbolTable::findGlobal(const TString &name) const +{ + ASSERT(table.size() > GLOBAL_LEVEL); + return table[GLOBAL_LEVEL]->find(name); +} + +TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) const +{ + return findBuiltIn(name, shaderVersion, false); +} + +TSymbol *TSymbolTable::findBuiltIn(const TString &name, + int shaderVersion, + bool includeGLSLBuiltins) const { for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--) { - if (level == ESSL3_BUILTINS && shaderVersion != 300) + if (level == GLSL_BUILTINS && !includeGLSLBuiltins) + level--; + if (level == ESSL3_1_BUILTINS && shaderVersion != 310) + level--; + if (level == ESSL3_BUILTINS && shaderVersion < 300) level--; if (level == ESSL1_BUILTINS && shaderVersion != 100) level--; @@ -121,7 +180,7 @@ TSymbol *TSymbolTable::findBuiltIn( return symbol; } - return 0; + return nullptr; } TSymbolTable::~TSymbolTable() @@ -135,7 +194,8 @@ bool IsGenType(const TType *type) if (type) { TBasicType basicType = type->getBasicType(); - return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType || basicType == EbtGenBType; + return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType || + basicType == EbtGenBType; } return false; @@ -146,7 +206,8 @@ bool IsVecType(const TType *type) if (type) { TBasicType basicType = type->getBasicType(); - return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec || basicType == EbtBVec; + return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec || + basicType == EbtBVec; } return false; @@ -163,13 +224,19 @@ const TType *SpecificType(const TType *type, int size) ASSERT(!IsVecType(type)); - switch(type->getBasicType()) + switch (type->getBasicType()) { - 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; + case EbtGenType: + return TCache::getType(EbtFloat, type->getQualifier(), + static_cast(size)); + case EbtGenIType: + return TCache::getType(EbtInt, type->getQualifier(), static_cast(size)); + case EbtGenUType: + return TCache::getType(EbtUInt, type->getQualifier(), static_cast(size)); + case EbtGenBType: + return TCache::getType(EbtBool, type->getQualifier(), static_cast(size)); + default: + return type; } } @@ -184,65 +251,232 @@ const TType *VectorType(const TType *type, int size) ASSERT(!IsGenType(type)); - switch(type->getBasicType()) + switch (type->getBasicType()) + { + 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; + } +} + +TVariable *TSymbolTable::declareVariable(const TString *name, const TType &type) +{ + return insertVariable(currentLevel(), name, type); +} + +TVariable *TSymbolTable::declareStructType(TStructure *str) +{ + return insertStructType(currentLevel(), str); +} + +TInterfaceBlockName *TSymbolTable::declareInterfaceBlockName(const TString *name) +{ + TInterfaceBlockName *blockNameSymbol = new TInterfaceBlockName(this, name); + if (insert(currentLevel(), blockNameSymbol)) + { + return blockNameSymbol; + } + return nullptr; +} + +TInterfaceBlockName *TSymbolTable::insertInterfaceBlockNameExt(ESymbolLevel level, + TExtension ext, + const TString *name) +{ + TInterfaceBlockName *blockNameSymbol = new TInterfaceBlockName(this, name); + if (insert(level, ext, blockNameSymbol)) + { + return blockNameSymbol; + } + return nullptr; +} + +TVariable *TSymbolTable::insertVariable(ESymbolLevel level, const char *name, const TType &type) +{ + return insertVariable(level, NewPoolTString(name), type); +} + +TVariable *TSymbolTable::insertVariable(ESymbolLevel level, const TString *name, const TType &type) +{ + TVariable *var = new TVariable(this, name, type); + if (insert(level, var)) + { + // Do lazy initialization for struct types, so we allocate to the current scope. + if (var->getType().getBasicType() == EbtStruct) + { + var->getType().realize(); + } + return var; + } + return nullptr; +} + +TVariable *TSymbolTable::insertVariableExt(ESymbolLevel level, + TExtension ext, + const char *name, + const TType &type) +{ + TVariable *var = new TVariable(this, NewPoolTString(name), type); + if (insert(level, ext, var)) + { + if (var->getType().getBasicType() == EbtStruct) + { + var->getType().realize(); + } + return var; + } + return nullptr; +} + +TVariable *TSymbolTable::insertStructType(ESymbolLevel level, TStructure *str) +{ + TVariable *var = new TVariable(this, &str->name(), TType(str), true); + if (insert(level, var)) { - 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; + var->getType().realize(); + return var; } + return nullptr; } -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) +void TSymbolTable::insertBuiltIn(ESymbolLevel level, + TOperator op, + TExtension 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) { + insertUnmangledBuiltInName(name, level); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - 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); + 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) { + insertUnmangledBuiltInName(name, level); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - 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); + 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) { + insertUnmangledBuiltInName(name, level); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - 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); + 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) { + insertUnmangledBuiltInName(name, level); bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - 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); + 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)) + else if (ptype1->getBasicType() == EbtGSampler2DMS) { - ASSERT(!ptype4 && !ptype5); - insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1)); - insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2)); - insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3)); - insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4)); + insertUnmangledBuiltInName(name, level); + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name, + TCache::getType(EbtSampler2DMS), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name, + TCache::getType(EbtISampler2DMS), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name, + TCache::getType(EbtUSampler2DMS), ptype2, ptype3, ptype4, ptype5); + } + else if (IsGImage(ptype1->getBasicType())) + { + insertUnmangledBuiltInName(name, level); + + const TType *floatType = TCache::getType(EbtFloat, 4); + const TType *intType = TCache::getType(EbtInt, 4); + const TType *unsignedType = TCache::getType(EbtUInt, 4); + + const TType *floatImage = + TCache::getType(convertGImageToFloatImage(ptype1->getBasicType())); + const TType *intImage = TCache::getType(convertGImageToIntImage(ptype1->getBasicType())); + const TType *unsignedImage = + TCache::getType(convertGImageToUnsignedImage(ptype1->getBasicType())); + + // GLSL ES 3.10, Revision 4, 8.12 Image Functions + if (rvalue->getBasicType() == EbtGVec4) + { + // imageLoad + insertBuiltIn(level, floatType, name, floatImage, ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, intType, name, intImage, ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, unsignedType, name, unsignedImage, ptype2, ptype3, ptype4, ptype5); + } + else if (rvalue->getBasicType() == EbtVoid) + { + // imageStore + insertBuiltIn(level, rvalue, name, floatImage, ptype2, floatType, ptype4, ptype5); + insertBuiltIn(level, rvalue, name, intImage, ptype2, intType, ptype4, ptype5); + insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, unsignedType, ptype4, ptype5); + } + else + { + // imageSize + insertBuiltIn(level, rvalue, name, floatImage, ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, rvalue, name, intImage, ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, rvalue, name, unsignedImage, ptype2, ptype3, ptype4, ptype5); + } + } + else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3) || + IsGenType(ptype4)) + { + ASSERT(!ptype5); + insertUnmangledBuiltInName(name, level); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), + SpecificType(ptype2, 1), SpecificType(ptype3, 1), SpecificType(ptype4, 1)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), + SpecificType(ptype2, 2), SpecificType(ptype3, 2), SpecificType(ptype4, 2)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), + SpecificType(ptype2, 3), SpecificType(ptype3, 3), SpecificType(ptype4, 3)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), + SpecificType(ptype2, 4), SpecificType(ptype3, 4), SpecificType(ptype4, 4)); } else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3)) { ASSERT(!ptype4 && !ptype5); - insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2)); - insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3)); - insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4)); + insertUnmangledBuiltInName(name, level); + insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), + VectorType(ptype2, 2), VectorType(ptype3, 2)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), + VectorType(ptype2, 3), VectorType(ptype3, 3)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), + VectorType(ptype2, 4), VectorType(ptype3, 4)); } else { - TFunction *function = new TFunction(NewPoolTString(name), rvalue, op, ext); + TFunction *function = new TFunction(this, NewPoolTString(name), rvalue, op, ext); function->addParameter(TConstParameter(ptype1)); @@ -266,10 +500,61 @@ void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *e function->addParameter(TConstParameter(ptype5)); } + ASSERT(hasUnmangledBuiltInAtLevel(name, level)); insert(level, function); } } +void TSymbolTable::insertBuiltInOp(ESymbolLevel level, + TOperator op, + const TType *rvalue, + const TType *ptype1, + const TType *ptype2, + const TType *ptype3, + const TType *ptype4, + const TType *ptype5) +{ + const char *name = GetOperatorString(op); + ASSERT(strlen(name) > 0); + insertUnmangledBuiltInName(name, level); + insertBuiltIn(level, op, TExtension::UNDEFINED, rvalue, name, ptype1, ptype2, ptype3, ptype4, + ptype5); +} + +void TSymbolTable::insertBuiltInOp(ESymbolLevel level, + TOperator op, + TExtension ext, + const TType *rvalue, + const TType *ptype1, + const TType *ptype2, + const TType *ptype3, + const TType *ptype4, + const TType *ptype5) +{ + const char *name = GetOperatorString(op); + insertUnmangledBuiltInName(name, level); + insertBuiltIn(level, op, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); +} + +void TSymbolTable::insertBuiltInFunctionNoParameters(ESymbolLevel level, + TOperator op, + const TType *rvalue, + const char *name) +{ + insertUnmangledBuiltInName(name, level); + insert(level, new TFunction(this, NewPoolTString(name), rvalue, op)); +} + +void TSymbolTable::insertBuiltInFunctionNoParametersExt(ESymbolLevel level, + TExtension ext, + TOperator op, + const TType *rvalue, + const char *name) +{ + insertUnmangledBuiltInName(name, level); + insert(level, new TFunction(this, NewPoolTString(name), rvalue, op, ext)); +} + TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const { if (!SupportsPrecision(type)) @@ -279,7 +564,7 @@ TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const TBasicType baseType = (type == EbtUInt) ? EbtInt : type; int level = static_cast(precisionStack.size()) - 1; - assert(level >= 0); // Just to be safe. Should not happen. + assert(level >= 0); // Just to be safe. Should not happen. // If we dont find anything we return this. Some types don't have predefined default precision. TPrecision prec = EbpUndefined; while (level >= 0) @@ -294,3 +579,44 @@ TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const } return prec; } + +void TSymbolTable::insertUnmangledBuiltInName(const char *name, ESymbolLevel level) +{ + ASSERT(level >= 0 && level < static_cast(table.size())); + table[level]->insertUnmangledBuiltInName(std::string(name)); +} + +bool TSymbolTable::hasUnmangledBuiltInAtLevel(const char *name, ESymbolLevel level) +{ + ASSERT(level >= 0 && level < static_cast(table.size())); + return table[level]->hasUnmangledBuiltIn(std::string(name)); +} + +bool TSymbolTable::hasUnmangledBuiltInForShaderVersion(const char *name, int shaderVersion) +{ + ASSERT(static_cast(table.size()) > LAST_BUILTIN_LEVEL); + + for (int level = LAST_BUILTIN_LEVEL; level >= 0; --level) + { + if (level == ESSL3_1_BUILTINS && shaderVersion != 310) + { + --level; + } + if (level == ESSL3_BUILTINS && shaderVersion < 300) + { + --level; + } + if (level == ESSL1_BUILTINS && shaderVersion != 100) + { + --level; + } + + if (table[level]->hasUnmangledBuiltIn(name)) + { + return true; + } + } + return false; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h index 2706149e3c..5d792ec188 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h @@ -18,7 +18,7 @@ // so that symbol table lookups are never ambiguous. This allows // a simpler symbol table structure. // -// * Pushing and popping of scope, so symbol table will really be a stack +// * Pushing and popping of scope, so symbol table will really be a stack // of symbol tables. Searched from the top, with new inserts going into // the top. // @@ -30,111 +30,78 @@ // are tracked in the intermediate representation, not the symbol table. // +#include #include #include #include "common/angleutils.h" +#include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolUniqueId.h" + +namespace sh +{ // Symbol base class. (Can build functions or variables out of these...) class TSymbol : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); - TSymbol(const TString *n) - : uniqueId(0), - name(n) - { - } + TSymbol(TSymbolTable *symbolTable, const TString *n); + virtual ~TSymbol() { // don't delete name, it's from the pool } - const TString &getName() const - { - return *name; - } - virtual const TString &getMangledName() const - { - return getName(); - } - virtual bool isFunction() const - { - return false; - } - virtual bool isVariable() const - { - return false; - } - void setUniqueId(int id) - { - uniqueId = id; - } - int getUniqueId() const - { - return uniqueId; - } - void relateToExtension(const TString &ext) - { - extension = ext; - } - const TString &getExtension() const - { - return extension; - } + const TString &getName() const { return *name; } + virtual const TString &getMangledName() const { return getName(); } + virtual bool isFunction() const { return false; } + virtual bool isVariable() const { return false; } + const TSymbolUniqueId &getUniqueId() const { return uniqueId; } + void relateToExtension(TExtension ext) { extension = ext; } + TExtension getExtension() const { return extension; } private: - int uniqueId; // For real comparing during code generation + const TSymbolUniqueId uniqueId; const TString *name; - TString extension; + TExtension extension; }; -// Variable class, meaning a symbol that's not a function. -// -// There could be a separate class heirarchy for Constant variables; -// Only one of int, bool, or float, (or none) is correct for -// any particular use, but it's easy to do this way, and doesn't -// seem worth having separate classes, and "getConst" can't simply return -// different values for different types polymorphically, so this is -// just simple and pragmatic. +// Variable, meaning a symbol that's not a function. +// +// May store the value of a constant variable of any type (float, int, bool or struct). class TVariable : public TSymbol { public: - TVariable(const TString *name, const TType &t, bool uT = false) - : TSymbol(name), - type(t), - userType(uT), - unionArray(0) - { - } ~TVariable() override {} bool isVariable() const override { return true; } - TType &getType() - { - return type; - } - const TType &getType() const - { - return type; - } - bool isUserType() const - { - return userType; - } - void setQualifier(TQualifier qualifier) - { - type.setQualifier(qualifier); - } + TType &getType() { return type; } + const TType &getType() const { return type; } + bool isUserType() const { return userType; } + void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } const TConstantUnion *getConstPointer() const { return unionArray; } void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; } private: + friend class TSymbolTable; + + TVariable(TSymbolTable *symbolTable, + const TString *name, + const TType &t, + bool isUserTypeDefinition = false) + : TSymbol(symbolTable, name), type(t), userType(isUserTypeDefinition), unionArray(0) + { + } + TType type; + + // Set to true if this represents a struct type, as opposed to a variable. bool userType; + // we are assuming that Pool Allocator will free the memory // allocated to unionArray when this object is destroyed. const TConstantUnion *unionArray; @@ -143,34 +110,18 @@ class TVariable : public TSymbol // 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) - { - } + 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(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; + const TString *const name; + const TType *const type; }; // The function sub-class of symbols and the parser will need to @@ -183,25 +134,26 @@ struct TParameter TConstParameter turnToConst() { const TString *constName = name; - const TType *constType = type; - name = nullptr; - type = nullptr; + const TType *constType = type; + name = nullptr; + type = nullptr; return TConstParameter(constName, constType); } - TString *name; + const TString *name; TType *type; }; -// The function sub-class of a symbol. +// The function sub-class of a symbol. class TFunction : public TSymbol { public: - TFunction(const TString *name, + TFunction(TSymbolTable *symbolTable, + const TString *name, const TType *retType, - TOperator tOp = EOpNull, - const char *ext = "") - : TSymbol(name), + TOperator tOp = EOpNull, + TExtension ext = TExtension::UNDEFINED) + : TSymbol(symbolTable, name), returnType(retType), mangledName(nullptr), op(tOp), @@ -213,21 +165,14 @@ class TFunction : public TSymbol ~TFunction() override; bool isFunction() const override { return true; } - static TString mangleName(const TString &name) - { - return name + '('; - } - static TString unmangleName(const TString &mangledName) - { - return TString(mangledName.c_str(), mangledName.find_first_of('(')); - } - void addParameter(const TConstParameter &p) { parameters.push_back(p); mangledName = nullptr; } + void swapParameters(const TFunction ¶metersSource); + const TString &getMangledName() const override { if (mangledName == nullptr) @@ -236,31 +181,25 @@ class TFunction : public TSymbol } return *mangledName; } - const TType &getReturnType() const - { - return *returnType; - } - TOperator getBuiltInOp() const - { - return op; - } + static const TString &GetMangledNameFromCall(const TString &functionName, + const TIntermSequence &arguments); + + const TType &getReturnType() const { return *returnType; } + + TOperator getBuiltInOp() const { return op; } 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 TConstParameter &getParam(size_t i) const - { - return parameters[i]; - } + size_t getParamCount() const { return parameters.size(); } + const TConstParameter &getParam(size_t i) const { return parameters[i]; } private: + void clearParameters(); + const TString *buildMangledName() const; typedef TVector TParamList; @@ -276,12 +215,11 @@ class TFunction : public TSymbol class TInterfaceBlockName : public TSymbol { public: - TInterfaceBlockName(const TString *name) - : TSymbol(name) - { - } + virtual ~TInterfaceBlockName() {} - virtual ~TInterfaceBlockName() + private: + friend class TSymbolTable; + TInterfaceBlockName(TSymbolTable *symbolTable, const TString *name) : TSymbol(symbolTable, name) { } }; @@ -289,14 +227,12 @@ class TInterfaceBlockName : public TSymbol class TSymbolTableLevel { public: - typedef TMap tLevel; + typedef TUnorderedMap tLevel; typedef tLevel::const_iterator const_iterator; typedef const tLevel::value_type tLevelPair; typedef std::pair tInsertResult; - TSymbolTableLevel() - { - } + TSymbolTableLevel() : mGlobalInvariant(false) {} ~TSymbolTableLevel(); bool insert(TSymbol *symbol); @@ -306,25 +242,52 @@ class TSymbolTableLevel TSymbol *find(const TString &name) const; + void addInvariantVarying(const std::string &name) { mInvariantVaryings.insert(name); } + + bool isVaryingInvariant(const std::string &name) + { + return (mGlobalInvariant || mInvariantVaryings.count(name) > 0); + } + + void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; } + + void insertUnmangledBuiltInName(const std::string &name) + { + mUnmangledBuiltInNames.insert(name); + } + + bool hasUnmangledBuiltIn(const std::string &name) + { + return mUnmangledBuiltInNames.count(name) > 0; + } + protected: tLevel level; + std::set mInvariantVaryings; + bool mGlobalInvariant; + + private: + std::set mUnmangledBuiltInNames; }; // Define ESymbolLevel as int rather than an enum since level can go // above GLOBAL_LEVEL and cause atBuiltInLevel() to fail if the // compiler optimizes the >= of the last element to ==. typedef int ESymbolLevel; -const int COMMON_BUILTINS = 0; -const int ESSL1_BUILTINS = 1; -const int ESSL3_BUILTINS = 2; -const int LAST_BUILTIN_LEVEL = ESSL3_BUILTINS; -const int GLOBAL_LEVEL = 3; +const int COMMON_BUILTINS = 0; +const int ESSL1_BUILTINS = 1; +const int ESSL3_BUILTINS = 2; +const int ESSL3_1_BUILTINS = 3; +// GLSL_BUILTINS are desktop GLSL builtins that don't exist in ESSL but are used to implement +// features in ANGLE's GLSL backend. They're not visible to the parser. +const int GLSL_BUILTINS = 4; +const int LAST_BUILTIN_LEVEL = GLSL_BUILTINS; +const int GLOBAL_LEVEL = 5; class TSymbolTable : angle::NonCopyable { public: - TSymbolTable() - : mGlobalInvariant(false) + TSymbolTable() : mUniqueIdCounter(0), mEmptySymbolId(this) { // The symbol table cannot be used until push() is called, but // the lack of an initial call to push() can be used to detect @@ -336,18 +299,9 @@ class TSymbolTable : angle::NonCopyable // When the symbol table is initialized with the built-ins, there should // 'push' calls, so that built-ins are at level 0 and the shader // globals are at level 1. - bool isEmpty() const - { - return table.empty(); - } - bool atBuiltInLevel() const - { - return currentLevel() <= LAST_BUILTIN_LEVEL; - } - bool atGlobalLevel() const - { - return currentLevel() <= GLOBAL_LEVEL; - } + bool isEmpty() const { return table.empty(); } + bool atBuiltInLevel() const { return currentLevel() <= LAST_BUILTIN_LEVEL; } + bool atGlobalLevel() const { return currentLevel() == GLOBAL_LEVEL; } void push() { table.push_back(new TSymbolTableLevel); @@ -363,87 +317,159 @@ class TSymbolTable : angle::NonCopyable precisionStack.pop_back(); } - bool declare(TSymbol *symbol) - { - return insert(currentLevel(), symbol); - } - - bool insert(ESymbolLevel level, TSymbol *symbol) - { - return table[level]->insert(symbol); - } - - bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol) - { - symbol->relateToExtension(ext); - return table[level]->insert(symbol); - } - - bool insertConstInt(ESymbolLevel level, const char *name, int value) + // The declare* entry points are used when parsing and declare symbols at the current scope. + // They return the created symbol in case the declaration was successful, and nullptr if the + // declaration failed due to redefinition. + TVariable *declareVariable(const TString *name, const TType &type); + TVariable *declareStructType(TStructure *str); + TInterfaceBlockName *declareInterfaceBlockName(const TString *name); + + // The insert* entry points are used when initializing the symbol table with built-ins. + // They return the created symbol in case the declaration was successful, and nullptr if the + // declaration failed due to redefinition. + TVariable *insertVariable(ESymbolLevel level, const char *name, const TType &type); + TVariable *insertVariableExt(ESymbolLevel level, + TExtension ext, + const char *name, + const TType &type); + TVariable *insertStructType(ESymbolLevel level, TStructure *str); + TInterfaceBlockName *insertInterfaceBlockNameExt(ESymbolLevel level, + TExtension ext, + const TString *name); + + bool insertConstInt(ESymbolLevel level, const char *name, int value, TPrecision precision) { - TVariable *constant = new TVariable( - NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); + TVariable *constant = + new TVariable(this, NewPoolTString(name), TType(EbtInt, precision, EvqConst, 1)); TConstantUnion *unionArray = new TConstantUnion[1]; unionArray[0].setIConst(value); constant->shareConstPointer(unionArray); return insert(level, constant); } - bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value) + bool insertConstIntExt(ESymbolLevel level, + TExtension ext, + const char *name, + int value, + TPrecision precision) { TVariable *constant = - new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); + new TVariable(this, NewPoolTString(name), TType(EbtInt, precision, 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, 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) + bool insertConstIvec3(ESymbolLevel level, + const char *name, + const std::array &values, + TPrecision precision) { - insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); - } + TVariable *constantIvec3 = + new TVariable(this, NewPoolTString(name), TType(EbtInt, precision, EvqConst, 3)); - 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) - { + TConstantUnion *unionArray = new TConstantUnion[3]; + for (size_t index = 0u; index < 3u; ++index) + { + unionArray[index].setIConst(values[index]); + } + constantIvec3->shareConstPointer(unionArray); + + return insert(level, constantIvec3); + } + + void insertBuiltIn(ESymbolLevel level, + TOperator op, + TExtension 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, + 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) + { + insertUnmangledBuiltInName(name, level); + insertBuiltIn(level, EOpNull, TExtension::UNDEFINED, rvalue, name, ptype1, ptype2, ptype3, + ptype4, ptype5); + } + + void insertBuiltIn(ESymbolLevel level, + TExtension 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) + { + insertUnmangledBuiltInName(name, level); insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); } - 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); - } + void insertBuiltInOp(ESymbolLevel level, + TOperator op, + const TType *rvalue, + const TType *ptype1, + const TType *ptype2 = 0, + const TType *ptype3 = 0, + const TType *ptype4 = 0, + const TType *ptype5 = 0); + + void insertBuiltInOp(ESymbolLevel level, + TOperator op, + TExtension ext, + const TType *rvalue, + const TType *ptype1, + const TType *ptype2 = 0, + const TType *ptype3 = 0, + const TType *ptype4 = 0, + const TType *ptype5 = 0); + + void insertBuiltInFunctionNoParameters(ESymbolLevel level, + TOperator op, + const TType *rvalue, + const char *name); + + void insertBuiltInFunctionNoParametersExt(ESymbolLevel level, + TExtension ext, + TOperator op, + const TType *rvalue, + const char *name); + + TSymbol *find(const TString &name, + int shaderVersion, + bool *builtIn = nullptr, + bool *sameScope = nullptr) const; + + TSymbol *findGlobal(const TString &name) const; - TSymbol *find(const TString &name, int shaderVersion, - bool *builtIn = NULL, bool *sameScope = NULL) const; TSymbol *findBuiltIn(const TString &name, int shaderVersion) const; - + + TSymbol *findBuiltIn(const TString &name, int shaderVersion, bool includeGLSLBuiltins) const; + TSymbolTableLevel *getOuterLevel() { assert(currentLevel() >= 1); return table[currentLevel() - 1]; } - void dump(TInfoSink &infoSink) const; - - bool setDefaultPrecision(const TPublicType &type, TPrecision prec) + void setDefaultPrecision(TBasicType type, TPrecision prec) { - 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; // Uses map operator [], overwrites the current value - (*precisionStack[indexOfLastElement])[type.type] = prec; - return true; + (*precisionStack[indexOfLastElement])[type] = prec; } // Searches down the precisionStack for a precision qualifier @@ -454,7 +480,8 @@ class TSymbolTable : angle::NonCopyable // "invariant varying_name;". void addInvariantVarying(const std::string &originalName) { - mInvariantVaryings.insert(originalName); + ASSERT(atGlobalLevel()); + table[currentLevel()]->addInvariantVarying(originalName); } // If this returns false, the varying could still be invariant // if it is set as invariant during the varying variable @@ -462,32 +489,57 @@ class TSymbolTable : angle::NonCopyable // variable's type, not here. bool isVaryingInvariant(const std::string &originalName) const { - return (mGlobalInvariant || - mInvariantVaryings.count(originalName) > 0); + ASSERT(atGlobalLevel()); + return table[currentLevel()]->isVaryingInvariant(originalName); } - void setGlobalInvariant() { mGlobalInvariant = true; } - bool getGlobalInvariant() const { return mGlobalInvariant; } - - static int nextUniqueId() + void setGlobalInvariant(bool invariant) { - return ++uniqueIdCounter; + ASSERT(atGlobalLevel()); + table[currentLevel()]->setGlobalInvariant(invariant); } + const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); } + + // The empty symbol id is shared between all empty string ("") symbols. They are used in the + // AST for unused function parameters and struct type declarations that don't declare a + // variable, for example. + const TSymbolUniqueId &getEmptySymbolId() { return mEmptySymbolId; } + + // Checks whether there is a built-in accessible by a shader with the specified version. + bool hasUnmangledBuiltInForShaderVersion(const char *name, int shaderVersion); + private: - ESymbolLevel currentLevel() const + friend class TSymbolUniqueId; + int nextUniqueIdValue() { return ++mUniqueIdCounter; } + + ESymbolLevel currentLevel() const { return static_cast(table.size() - 1); } + + TVariable *insertVariable(ESymbolLevel level, const TString *name, const TType &type); + + bool insert(ESymbolLevel level, TSymbol *symbol) { return table[level]->insert(symbol); } + + bool insert(ESymbolLevel level, TExtension ext, TSymbol *symbol) { - return static_cast(table.size() - 1); + symbol->relateToExtension(ext); + return table[level]->insert(symbol); } + // Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00 and + // above. + void insertUnmangledBuiltInName(const char *name, ESymbolLevel level); + + bool hasUnmangledBuiltInAtLevel(const char *name, ESymbolLevel level); + std::vector table; typedef TMap PrecisionStackLevel; - std::vector< PrecisionStackLevel *> precisionStack; + std::vector precisionStack; - std::set mInvariantVaryings; - bool mGlobalInvariant; + int mUniqueIdCounter; - static int uniqueIdCounter; + const TSymbolUniqueId mEmptySymbolId; }; -#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.cpp new file mode 100644 index 0000000000..2a68ae3e70 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.cpp @@ -0,0 +1,28 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SymbolUniqueId.cpp: Encapsulates a unique id for a symbol. + +#include "compiler/translator/SymbolUniqueId.h" + +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +TSymbolUniqueId::TSymbolUniqueId(TSymbolTable *symbolTable) : mId(symbolTable->nextUniqueIdValue()) +{ +} + +TSymbolUniqueId::TSymbolUniqueId(const TSymbol &symbol) : mId(symbol.getUniqueId().get()) +{ +} + +int TSymbolUniqueId::get() const +{ + return mId; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.h b/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.h new file mode 100644 index 0000000000..4bd5604246 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SymbolUniqueId.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SymbolUniqueId.h: Encapsulates a unique id for a symbol. + +#ifndef COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ +#define COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ + +#include "compiler/translator/Common.h" + +namespace sh +{ + +class TSymbolTable; +class TSymbol; + +class TSymbolUniqueId +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + explicit TSymbolUniqueId(TSymbolTable *symbolTable); + explicit TSymbolUniqueId(const TSymbol &symbol); + TSymbolUniqueId(const TSymbolUniqueId &) = default; + TSymbolUniqueId &operator=(const TSymbolUniqueId &) = default; + + int get() const; + + private: + int mId; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.cpp new file mode 100644 index 0000000000..d2b65a6c56 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.cpp @@ -0,0 +1,1322 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL +// output. Some of the implementations are straightforward and just call the HLSL equivalent of the +// ESSL texture function, others do more work to emulate ESSL texture sampling or size query +// behavior. +// + +#include "compiler/translator/TextureFunctionHLSL.h" + +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +namespace +{ + +void OutputIntTexCoordWrap(TInfoSinkBase &out, + const char *wrapMode, + const char *size, + const TString &texCoord, + const TString &texCoordOffset, + const char *texCoordOutName) +{ + // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim + // but rather use equivalent formulas that map better to HLSL. + out << "int " << texCoordOutName << ";\n"; + out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset + << ") / " << size << ";\n"; + + // CLAMP_TO_EDGE + out << "if (" << wrapMode << " == 1)\n"; + out << "{\n"; + out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName + << "Offset)), 0, int(" << size << ") - 1);\n"; + out << "}\n"; + + // MIRRORED_REPEAT + out << "else if (" << wrapMode << " == 3)\n"; + out << "{\n"; + out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName + << "Offset) * 0.5) * 2.0 - 1.0);\n"; + out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n"; + out << "}\n"; + + // REPEAT + out << "else\n"; + out << "{\n"; + out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName + << "Offset)));\n"; + out << "}\n"; +} + +void OutputIntTexCoordWraps(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + TString *texCoordX, + TString *texCoordY, + TString *texCoordZ) +{ + // Convert from normalized floating-point to integer + out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix"); + } + else + { + OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix"); + } + *texCoordX = "tix"; + out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy"); + } + else + { + OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy"); + } + *texCoordY = "tiy"; + + if (IsSamplerArray(textureFunction.sampler)) + { + *texCoordZ = "int(max(0, min(layers - 1, floor(0.5 + t.z))))"; + } + else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler)) + { + out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz"); + } + else + { + OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz"); + } + *texCoordZ = "tiz"; + } +} + +void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const TString &textureReference, + const TString &samplerReference) +{ + out << textureReference; + if (IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + out << ".Load("; + return; + } + + if (IsShadowSampler(textureFunction.sampler)) + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + case TextureFunctionHLSL::TextureFunction::BIAS: + case TextureFunctionHLSL::TextureFunction::LOD: + out << ".SampleCmp("; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + case TextureFunctionHLSL::TextureFunction::GRAD: + out << ".SampleCmpLevelZero("; + break; + default: + UNREACHABLE(); + } + } + else + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << ".Sample("; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << ".SampleBias("; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << ".SampleLevel("; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + out << ".SampleGrad("; + break; + default: + UNREACHABLE(); + } + } + out << samplerReference << ", "; +} + +const char *GetSamplerCoordinateTypeString( + const TextureFunctionHLSL::TextureFunction &textureFunction, + int hlslCoords) +{ + if (IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + switch (hlslCoords) + { + case 2: + if (textureFunction.sampler == EbtSampler2DMS || + textureFunction.sampler == EbtISampler2DMS || + textureFunction.sampler == EbtUSampler2DMS) + return "int2"; + else + return "int3"; + case 3: + return "int4"; + default: + UNREACHABLE(); + } + } + else + { + switch (hlslCoords) + { + case 2: + return "float2"; + case 3: + return "float3"; + case 4: + return "float4"; + default: + UNREACHABLE(); + } + } + return ""; +} + +int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction, + ShShaderOutput outputType) +{ + if (outputType == SH_HLSL_3_0_OUTPUT) + { + int hlslCoords = 2; + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + case EbtSampler2DMS: + hlslCoords = 2; + break; + case EbtSamplerCube: + hlslCoords = 3; + break; + default: + UNREACHABLE(); + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + case TextureFunctionHLSL::TextureFunction::GRAD: + return hlslCoords; + case TextureFunctionHLSL::TextureFunction::BIAS: + case TextureFunctionHLSL::TextureFunction::LOD: + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + return 4; + default: + UNREACHABLE(); + } + } + else + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + return 2; + case EbtSampler2DMS: + return 2; + case EbtSampler3D: + return 3; + case EbtSamplerCube: + return 3; + case EbtSampler2DArray: + return 3; + case EbtSamplerExternalOES: + return 2; + case EbtISampler2D: + return 2; + case EbtISampler2DMS: + return 2; + case EbtISampler3D: + return 3; + case EbtISamplerCube: + return 3; + case EbtISampler2DArray: + return 3; + case EbtUSampler2D: + return 2; + case EbtUSampler2DMS: + 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; +} + +void OutputTextureFunctionArgumentList(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType) +{ + if (outputType == SH_HLSL_3_0_OUTPUT) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + out << "sampler2D s"; + break; + case EbtSamplerCube: + out << "samplerCUBE s"; + break; + default: + UNREACHABLE(); + } + } + else + { + if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << TextureString(textureFunction.sampler) << " x, " + << SamplerString(textureFunction.sampler) << " s"; + } + else + { + ASSERT(outputType == SH_HLSL_4_1_OUTPUT); + // A bug in the D3D compiler causes some nested sampling operations to fail. + // See http://anglebug.com/1923 + // TODO(jmadill): Reinstate the const keyword when possible. + out << /*"const"*/ "uint samplerIndex"; + } + } + + if (textureFunction.method == + TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates + { + switch (textureFunction.coords) + { + case 2: + out << ", int2 t"; + break; + case 3: + out << ", int3 t"; + break; + default: + UNREACHABLE(); + } + } + else // Floating-point coordinates (except textureSize) + { + switch (textureFunction.coords) + { + case 0: + break; // textureSize(gSampler2DMS sampler) + case 1: + out << ", int lod"; + break; // textureSize() + case 2: + out << ", float2 t"; + break; + case 3: + out << ", float3 t"; + break; + case 4: + out << ", float4 t"; + break; + default: + UNREACHABLE(); + } + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSamplerExternalOES: + out << ", float2 ddx, float2 ddy"; + break; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + out << ", float3 ddx, float3 ddy"; + break; + default: + UNREACHABLE(); + } + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + break; // Comes after the offset parameter + case TextureFunctionHLSL::TextureFunction::LOD: + out << ", float lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + break; // Comes after the offset parameter + case TextureFunctionHLSL::TextureFunction::SIZE: + break; + case TextureFunctionHLSL::TextureFunction::FETCH: + if (textureFunction.sampler == EbtSampler2DMS || + textureFunction.sampler == EbtISampler2DMS || + textureFunction.sampler == EbtUSampler2DMS) + out << ", int index"; + else + out << ", int mip"; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + break; + default: + UNREACHABLE(); + } + + if (textureFunction.offset) + { + switch (textureFunction.sampler) + { + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + out << ", int3 offset"; + break; + case EbtSampler2D: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + case EbtSamplerExternalOES: + out << ", int2 offset"; + break; + default: + UNREACHABLE(); + } + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS || + textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << ", float bias"; + } +} + +void GetTextureReference(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + TString *textureReference, + TString *samplerReference) +{ + if (outputType == 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]"; + } + } + else + { + *textureReference = "x"; + *samplerReference = "s"; + } +} + +void OutputTextureSizeFunctionBody(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const TString &textureReference, + bool getDimensionsIgnoresBaseLevel) +{ + if (IsSampler2DMS(textureFunction.sampler)) + { + out << " uint width; uint height; uint samples;\n" + << " " << textureReference << ".GetDimensions(width, height, samples);\n"; + } + else + { + if (getDimensionsIgnoresBaseLevel) + { + out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n"; + } + else + { + out << " int baseLevel = 0;\n"; + } + + if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) || + (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler))) + { + // "depth" stores either the number of layers in an array texture or 3D depth + out << " uint width; uint height; uint depth; uint numberOfLevels;\n" + << " " << textureReference + << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; + + if (!IsSamplerArray(textureFunction.sampler)) + { + out << " depth = max(depth >> lod, 1);\n"; + } + } + else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler)) + { + out << " uint width; uint height; uint numberOfLevels;\n" + << " " << textureReference + << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; + } + else + UNREACHABLE(); + } + + if (strcmp(textureFunction.getReturnType(), "int3") == 0) + { + out << " return int3(width, height, depth);\n"; + } + else + { + out << " return int2(width, height);\n"; + } +} + +void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction, + TString *texCoordX, + TString *texCoordY, + TString *texCoordZ) +{ + if (textureFunction.proj) + { + TString proj(""); + switch (textureFunction.coords) + { + case 3: + proj = " / t.z"; + break; + case 4: + proj = " / t.w"; + break; + default: + UNREACHABLE(); + } + *texCoordX = "(" + *texCoordX + proj + ")"; + *texCoordY = "(" + *texCoordY + proj + ")"; + *texCoordZ = "(" + *texCoordZ + proj + ")"; + } +} + +void OutputIntegerTextureSampleFunctionComputations( + TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + const TString &textureReference, + TString *texCoordX, + TString *texCoordY, + TString *texCoordZ) +{ + if (!IsIntegerSampler(textureFunction.sampler)) + { + return; + } + if (IsSamplerCube(textureFunction.sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + + out << " uint mip = 0;\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"; + out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n"; + out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || " + "(zMajor && t.z < 0.0f);\n"; + + // FACE_POSITIVE_X = 000b + // FACE_NEGATIVE_X = 001b + // FACE_POSITIVE_Y = 010b + // FACE_NEGATIVE_Y = 011b + // FACE_POSITIVE_Z = 100b + // FACE_NEGATIVE_Z = 101b + out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n"; + + out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n"; + out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n"; + out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n"; + + out << " t.x = (u * 0.5f / m) + 0.5f;\n"; + out << " t.y = (v * 0.5f / m) + 0.5f;\n"; + + // Mip level computation. + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD || + textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + if (textureFunction.method == TextureFunctionHLSL::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"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial + // derivatives of P are assumed to be in the coordinate system used before + // texture coordinates are projected onto the appropriate cube face." + // ddx[0] and ddy[0] are the derivatives of t.x passed into the function + // ddx[1] and ddy[1] are the derivatives of t.y passed into the function + // ddx[2] and ddy[2] are the derivatives of t.z passed into the function + // Determine the derivatives of u, v and m + out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] " + ": ddx[0]);\n" + " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] " + ": ddy[0]);\n" + " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n" + " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n" + " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n" + " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n"; + // Now determine the derivatives of the face coordinates, using the + // derivatives calculated above. + // d / dx (u(x) * 0.5 / m(x) + 0.5) + // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2 + out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n" + " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n" + " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n" + " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n" + " float2 sizeVec = float2(width, height);\n" + " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n" + " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n"; + // Optimization: instead of: log2(max(length(faceddx), length(faceddy))) + // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2 + out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n" + " float lengthfaceddy2 = dot(faceddy, faceddy);\n" + " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n"; + } + out << " mip = uint(min(max(round(lod), 0), levels - 1));\n" + << " " << textureReference + << ".GetDimensions(mip, width, height, layers, levels);\n"; + } + + // Convert from normalized floating-point to integer + *texCoordX = "int(floor(width * frac(" + *texCoordX + ")))"; + *texCoordY = "int(floor(height * frac(" + *texCoordY + ")))"; + *texCoordZ = "face"; + } + else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH) + { + if (IsSampler2D(textureFunction.sampler)) + { + if (IsSamplerArray(textureFunction.sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + + out << " " << textureReference + << ".GetDimensions(0, width, height, layers, levels);\n"; + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + 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"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float2 sizeVec = float2(width, height);\n" + " float2 sizeDdx = ddx * sizeVec;\n" + " float2 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), " + "dot(sizeDdy, sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(mip, width, height, layers, levels);\n"; + } + else + { + out << " float width; float height; float levels;\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + out << " " << textureReference + << ".GetDimensions(0, width, height, levels);\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + 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"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float2 sizeVec = float2(width, height);\n" + " float2 sizeDdx = ddx * sizeVec;\n" + " float2 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), " + "dot(sizeDdy, sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(mip, width, height, levels);\n"; + } + } + else if (IsSampler3D(textureFunction.sampler)) + { + out << " float width; float height; float depth; float levels;\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + out << " " << textureReference + << ".GetDimensions(0, width, height, depth, levels);\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + 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"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float3 sizeVec = float3(width, height, depth);\n" + " float3 sizeDdx = ddx * sizeVec;\n" + " float3 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, " + "sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(mip, width, height, depth, levels);\n"; + } + else + UNREACHABLE(); + + OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ); + } +} + +void OutputTextureSampleFunctionReturnStatement( + TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + const TString &textureReference, + const TString &samplerReference, + const TString &texCoordX, + const TString &texCoordY, + const TString &texCoordZ) +{ + out << " return "; + + // HLSL intrinsic + if (outputType == SH_HLSL_3_0_OUTPUT) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + out << "tex2D"; + break; + case EbtSamplerCube: + out << "texCUBE"; + break; + default: + UNREACHABLE(); + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << "(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << "bias(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + out << "grad(" << samplerReference << ", "; + break; + default: + UNREACHABLE(); + } + } + else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference); + } + else + UNREACHABLE(); + + const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType); + + out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", " + << texCoordY; + + if (outputType == SH_HLSL_3_0_OUTPUT) + { + if (hlslCoords >= 3) + { + if (textureFunction.coords < 3) + { + out << ", 0"; + } + else + { + out << ", " << texCoordZ; + } + } + + if (hlslCoords == 4) + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::BIAS: + out << ", bias"; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << ", lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << ", 0"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << ", bias"; + break; + default: + UNREACHABLE(); + } + } + + out << ")"; + } + else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + if (hlslCoords >= 3) + { + ASSERT(!IsIntegerSampler(textureFunction.sampler) || + !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face"); + out << ", " << texCoordZ; + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction.sampler)) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction.sampler)) + { + // Compare value + if (textureFunction.proj) + { + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as + // Dref + out << "), " << texCoordZ; + } + else + { + switch (textureFunction.coords) + { + case 3: + out << "), t.z"; + break; + case 4: + out << "), t.w"; + break; + default: + UNREACHABLE(); + } + } + } + else + { + out << "), ddx, ddy"; + } + } + else if (IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + if (textureFunction.sampler == EbtSampler2DMS || + textureFunction.sampler == EbtISampler2DMS || + textureFunction.sampler == EbtUSampler2DMS) + out << "), index"; + else + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction.sampler)) + { + // Compare value + if (textureFunction.proj) + { + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), " << texCoordZ; + } + else + { + switch (textureFunction.coords) + { + case 3: + out << "), t.z"; + break; + case 4: + out << "), t.w"; + break; + default: + UNREACHABLE(); + } + } + } + else + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << ")"; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << "), bias"; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << "), lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << "), 0"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << "), bias"; + break; + default: + UNREACHABLE(); + } + } + + if (textureFunction.offset && + (!IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)) + { + out << ", offset"; + } + } + else + UNREACHABLE(); + + out << ");\n"; // Close the sample function call and return statement +} + +} // Anonymous namespace + +TString TextureFunctionHLSL::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) + { + name += "Proj"; + } + + if (offset) + { + name += "Offset"; + } + + switch (method) + { + case IMPLICIT: + break; + case BIAS: + break; // Extra parameter makes the signature unique + case LOD: + name += "Lod"; + break; + case LOD0: + name += "Lod0"; + break; + case LOD0BIAS: + name += "Lod0"; + break; // Extra parameter makes the signature unique + case SIZE: + name += "Size"; + break; + case FETCH: + name += "Fetch"; + break; + case GRAD: + name += "Grad"; + break; + default: + UNREACHABLE(); + } + + return name; +} + +const char *TextureFunctionHLSL::TextureFunction::getReturnType() const +{ + if (method == TextureFunction::SIZE) + { + switch (sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DShadow: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + case EbtSamplerExternalOES: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return "int2"; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DArrayShadow: + return "int3"; + default: + UNREACHABLE(); + } + } + else // Sampling function + { + switch (sampler) + { + case EbtSampler2D: + case EbtSampler2DMS: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSampler2DArray: + case EbtSamplerExternalOES: + return "float4"; + case EbtISampler2D: + case EbtISampler2DMS: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + return "int4"; + case EbtUSampler2D: + case EbtUSampler2DMS: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + return "uint4"; + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return "float"; + default: + UNREACHABLE(); + } + } + return ""; +} + +bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const +{ + return std::tie(sampler, coords, proj, offset, method) < + std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method); +} + +TString TextureFunctionHLSL::useTextureFunction(const TString &name, + TBasicType samplerType, + int coords, + size_t argumentCount, + bool lod0, + sh::GLenum shaderType) +{ + TextureFunction textureFunction; + textureFunction.sampler = samplerType; + textureFunction.coords = coords; + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = false; + textureFunction.offset = false; + + if (name == "texture2D" || name == "textureCube" || name == "texture") + { + textureFunction.method = TextureFunction::IMPLICIT; + } + else if (name == "texture2DProj" || name == "textureProj") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = true; + } + else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" || + name == "texture2DLodEXT" || name == "textureCubeLodEXT") + { + textureFunction.method = TextureFunction::LOD; + } + else if (name == "texture2DProjLod" || name == "textureProjLod" || + name == "texture2DProjLodEXT") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + } + else if (name == "textureSize") + { + textureFunction.method = TextureFunction::SIZE; + } + else if (name == "textureOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + } + else if (name == "textureProjOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + textureFunction.proj = true; + } + else if (name == "textureLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.offset = true; + } + else if (name == "textureProjLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else if (name == "texelFetch") + { + textureFunction.method = TextureFunction::FETCH; + } + else if (name == "texelFetchOffset") + { + textureFunction.method = TextureFunction::FETCH; + textureFunction.offset = true; + } + else if (name == "textureGrad" || name == "texture2DGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + } + else if (name == "textureGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.offset = true; + } + else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || + name == "textureCubeGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + } + else if (name == "textureProjGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else + UNREACHABLE(); + + if (textureFunction.method == + TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument + { + size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments + + if (textureFunction.offset) + { + mandatoryArgumentCount++; + } + + bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional + + if (lod0 || shaderType == GL_VERTEX_SHADER) + { + if (bias) + { + textureFunction.method = TextureFunction::LOD0BIAS; + } + else + { + textureFunction.method = TextureFunction::LOD0; + } + } + else if (bias) + { + textureFunction.method = TextureFunction::BIAS; + } + } + + mUsesTexture.insert(textureFunction); + return textureFunction.name(); +} + +void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel) +{ + for (const TextureFunction &textureFunction : mUsesTexture) + { + // Function header + out << textureFunction.getReturnType() << " " << textureFunction.name() << "("; + + OutputTextureFunctionArgumentList(out, textureFunction, outputType); + + 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 references to the texture and sampler + // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture* + // tests. + TString textureReference; + TString samplerReference; + GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference); + + if (textureFunction.method == TextureFunction::SIZE) + { + OutputTextureSizeFunctionBody(out, textureFunction, textureReference, + getDimensionsIgnoresBaseLevel); + } + else + { + TString texCoordX("t.x"); + TString texCoordY("t.y"); + TString texCoordZ("t.z"); + ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ); + OutputIntegerTextureSampleFunctionComputations(out, textureFunction, outputType, + textureReference, &texCoordX, &texCoordY, + &texCoordZ); + OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType, + textureReference, samplerReference, + texCoordX, texCoordY, texCoordZ); + } + + out << "}\n" + "\n"; + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.h b/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.h new file mode 100644 index 0000000000..68bf8c0898 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/TextureFunctionHLSL.h @@ -0,0 +1,76 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL +// output. Some of the implementations are straightforward and just call the HLSL equivalent of the +// ESSL texture function, others do more work to emulate ESSL texture sampling or size query +// behavior. +// + +#ifndef COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ + +#include + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" +#include "GLSLANG/ShaderLang.h" + +namespace sh +{ + +class TextureFunctionHLSL final : angle::NonCopyable +{ + public: + struct TextureFunction + { + // See ESSL 3.00.6 section 8.8 for reference about what the different methods below do. + enum Method + { + IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) + BIAS, + LOD, + LOD0, + LOD0BIAS, + SIZE, // textureSize() + FETCH, + GRAD + }; + + TString name() const; + + bool operator<(const TextureFunction &rhs) const; + + const char *getReturnType() const; + + TBasicType sampler; + int coords; + bool proj; + bool offset; + Method method; + }; + + // Returns the name of the texture function implementation to call. + // The name that's passed in is the name of the GLSL texture function that it should implement. + TString useTextureFunction(const TString &name, + TBasicType samplerType, + int coords, + size_t argumentCount, + bool lod0, + sh::GLenum shaderType); + + void textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel); + + private: + typedef std::set TextureFunctionSet; + TextureFunctionSet mUsesTexture; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp index 76d006fd11..23c967f944 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp @@ -12,21 +12,28 @@ #include "compiler/translator/OutputESSL.h" #include "angle_gl.h" +namespace sh +{ + TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) : TCompiler(type, spec, SH_ESSL_OUTPUT) { } -void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) { - if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION) { - InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu); } } -void TranslatorESSL::translate(TIntermNode *root, int) { - TInfoSinkBase& sink = getInfoSink().obj; +void TranslatorESSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics * /*perfDiagnostics*/) +{ + TInfoSinkBase &sink = getInfoSink().obj; int shaderVer = getShaderVersion(); if (shaderVer > 100) @@ -34,69 +41,144 @@ void TranslatorESSL::translate(TIntermNode *root, int) { sink << "#version " << shaderVer << " es\n"; } - writePragma(); - // Write built-in extension behaviors. - writeExtensionBehavior(); + writeExtensionBehavior(compileOptions); - bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { - EmulatePrecision emulatePrecision(getSymbolTable(), shaderVer); + EmulatePrecision emulatePrecision(&getSymbolTable(), shaderVer); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); - emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT); + emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT); } - RecordConstantPrecision(root, getTemporaryIndex()); + RecordConstantPrecision(root, &getSymbolTable()); // Write emulated built-in functions if needed. - if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + if (!getBuiltInFunctionEmulator().isOutputEmpty()) { sink << "// BEGIN: Generated code for built-in function emulation\n\n"; if (getShaderType() == GL_FRAGMENT_SHADER) { sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" - << "#define webgl_emu_precision highp\n" + << "#define emu_precision highp\n" << "#else\n" - << "#define webgl_emu_precision mediump\n" + << "#define emu_precision mediump\n" << "#endif\n\n"; } else { - sink << "#define webgl_emu_precision highp\n"; + sink << "#define emu_precision highp\n"; } - getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + getBuiltInFunctionEmulator().outputEmulatedFunctions(sink); sink << "// END: Generated code for built-in function emulation\n\n"; } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) + { + const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); + sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] + << ", local_size_z=" << localSize[2] << ") in;\n"; + } + + if (getShaderType() == GL_GEOMETRY_SHADER_OES) + { + WriteGeometryShaderLayoutQualifiers( + sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(), + getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices()); + } + // Write translated shader. TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), - getSymbolTable(), shaderVer, precisionEmulation); + &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation, + compileOptions); + + if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM) + { + TName uniformName(TString("ViewID_OVR")); + uniformName.setInternal(true); + sink << "highp uniform int " << outputESSL.hashName(uniformName) << ";\n"; + } + root->traverse(&outputESSL); } -void TranslatorESSL::writeExtensionBehavior() { - TInfoSinkBase& sink = getInfoSink().obj; - const TExtensionBehavior& extBehavior = getExtensionBehavior(); - for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); - iter != extBehavior.end(); ++iter) { - if (iter->second != EBhUndefined) { - if (getResources().NV_shader_framebuffer_fetch && iter->first == "GL_EXT_shader_framebuffer_fetch") { +bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Not necessary when translating to ESSL. + return false; +} + +void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions) +{ + TInfoSinkBase &sink = getInfoSink().obj; + const TExtensionBehavior &extBehavior = getExtensionBehavior(); + const bool isMultiviewExtEmulated = + (compileOptions & + (SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM | SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW | + SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER)) != 0u; + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end(); + ++iter) + { + if (iter->second != EBhUndefined) + { + const bool isMultiview = (iter->first == TExtension::OVR_multiview); + if (getResources().NV_shader_framebuffer_fetch && + iter->first == TExtension::EXT_shader_framebuffer_fetch) + { sink << "#extension GL_NV_shader_framebuffer_fetch : " - << getBehaviorString(iter->second) << "\n"; - } else if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { - sink << "#extension GL_NV_draw_buffers : " - << getBehaviorString(iter->second) << "\n"; - } else { - sink << "#extension " << iter->first << " : " - << getBehaviorString(iter->second) << "\n"; + << GetBehaviorString(iter->second) << "\n"; + } + else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers) + { + sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second) + << "\n"; + } + else if (isMultiview && isMultiviewExtEmulated) + { + if (getShaderType() == GL_VERTEX_SHADER && + (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u) + { + // Emit the NV_viewport_array2 extension in a vertex shader if the + // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the + // OVR_multiview(2) extension is requested. + sink << "#extension GL_NV_viewport_array2 : require\n"; + } + } + else if (iter->first == TExtension::OES_geometry_shader) + { + sink << "#ifdef GL_OES_geometry_shader\n" + << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second) + << "\n" + << "#elif defined GL_EXT_geometry_shader\n" + << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second) + << "\n"; + if (iter->second == EBhRequire) + { + sink << "#else\n" + << "#error \"No geometry shader extensions available.\" // Only generate " + "this if the extension is \"required\"\n"; + } + sink << "#endif\n"; + } + else + { + sink << "#extension " << GetExtensionNameString(iter->first) << " : " + << GetBehaviorString(iter->second) << "\n"; } } } } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h index 2cc61074d4..24dc738513 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h @@ -9,18 +9,27 @@ #include "compiler/translator/Compiler.h" +namespace sh +{ + class TranslatorESSL : public TCompiler { public: TranslatorESSL(sh::GLenum type, ShShaderSpec spec); protected: - void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) override; - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; private: - void writeExtensionBehavior(); + void writeExtensionBehavior(ShCompileOptions compileOptions); }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp index 05e9eb310b..a14e69e5d5 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -11,53 +11,116 @@ #include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/ExtensionGLSL.h" #include "compiler/translator/OutputGLSL.h" +#include "compiler/translator/RewriteTexelFetchOffset.h" +#include "compiler/translator/RewriteUnaryMinusOperatorFloat.h" #include "compiler/translator/VersionGLSL.h" -TranslatorGLSL::TranslatorGLSL(sh::GLenum type, - ShShaderSpec spec, - ShShaderOutput output) - : TCompiler(type, spec, output) { +namespace sh +{ + +TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) + : TCompiler(type, spec, output) +{ } -void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) { - if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION) + { + InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + } + + if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) { - InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion()); + } + + if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION) + { + InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu); } int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType()); InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion); } -void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) +void TranslatorGLSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics * /*perfDiagnostics*/) { - TInfoSinkBase& sink = getInfoSink().obj; + TInfoSinkBase &sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); - writePragma(); - // Write extension behaviour as needed - writeExtensionBehavior(root); + writeExtensionBehavior(root, compileOptions); + + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + + // If flattening the global invariant pragma, write invariant declarations for built-in + // variables. It should be harmless to do this twice in the case that the shader also explicitly + // did this. However, it's important to emit invariant qualifiers only for those built-in + // variables that are actually used, to avoid affecting the behavior of the shader. + if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 && + getPragma().stdgl.invariantAll && + !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions)) + { + ASSERT(wereVariablesCollected()); + + switch (getShaderType()) + { + case GL_VERTEX_SHADER: + sink << "invariant gl_Position;\n"; - bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment + // shaders if it's statically referenced. + conditionallyOutputInvariantDeclaration("gl_PointSize"); + break; + case GL_FRAGMENT_SHADER: + // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment + // shaders, so we can use simple logic to determine whether to declare these + // variables invariant. + conditionallyOutputInvariantDeclaration("gl_FragCoord"); + conditionallyOutputInvariantDeclaration("gl_PointCoord"); + break; + default: + // Currently not reached, but leave this in for future expansion. + ASSERT(false); + break; + } + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + + if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0) + { + sh::RewriteUnaryMinusOperatorFloat(root); + } + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { - EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); + EmulatePrecision emulatePrecision(&getSymbolTable(), getShaderVersion()); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); - emulatePrecision.writeEmulationHelpers(sink, getOutputType()); + emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType()); } // Write emulated built-in functions if needed. - if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + if (!getBuiltInFunctionEmulator().isOutputEmpty()) { sink << "// BEGIN: Generated code for built-in function emulation\n\n"; - sink << "#define webgl_emu_precision\n\n"; - getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + sink << "#define emu_precision\n\n"; + getBuiltInFunctionEmulator().outputEmulatedFunctions(sink); sink << "// END: Generated code for built-in function emulation\n\n"; } @@ -69,7 +132,7 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) if (getShaderType() == GL_FRAGMENT_SHADER) { const bool mayHaveESSL1SecondaryOutputs = - IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") && + IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) && getShaderVersion() == 100; const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); @@ -132,17 +195,48 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) } } + if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) + { + const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); + sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] + << ", local_size_z=" << localSize[2] << ") in;\n"; + } + + if (getShaderType() == GL_GEOMETRY_SHADER_OES) + { + WriteGeometryShaderLayoutQualifiers( + sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(), + getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices()); + } + // Write translated shader. - TOutputGLSL outputGLSL(sink, - getArrayIndexClampingStrategy(), - getHashFunction(), - getNameMap(), - getSymbolTable(), - getShaderVersion(), - getOutputType()); + TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), + &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), + compileOptions); + + if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM) + { + TName uniformName(TString("ViewID_OVR")); + uniformName.setInternal(true); + sink << "uniform int " << outputGLSL.hashName(uniformName) << ";\n"; + } + root->traverse(&outputGLSL); } +bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't + // translate to that version, return true for the next higher version. + return IsGLSL130OrNewer(getOutputType()); +} + +bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions) +{ + return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) || + TCompiler::shouldCollectVariables(compileOptions); +} + void TranslatorGLSL::writeVersion(TIntermNode *root) { TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType()); @@ -152,15 +246,15 @@ void TranslatorGLSL::writeVersion(TIntermNode *root) // If there is no version directive in the shader, 110 is implied. if (version > 110) { - TInfoSinkBase& sink = getInfoSink().obj; + TInfoSinkBase &sink = getInfoSink().obj; sink << "#version " << version << "\n"; } } -void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) +void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions) { - TInfoSinkBase& sink = getInfoSink().obj; - const TExtensionBehavior& extBehavior = getExtensionBehavior(); + TInfoSinkBase &sink = getInfoSink().obj; + const TExtensionBehavior &extBehavior = getExtensionBehavior(); for (const auto &iter : extBehavior) { if (iter.second == EBhUndefined) @@ -168,21 +262,58 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) 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") + if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT) + { + // For GLSL output, we don't need to emit most extensions explicitly, + // but some we need to translate in GL compatibility profile. + if (iter.first == TExtension::EXT_shader_texture_lod) + { + sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second) + << "\n"; + } + + if (iter.first == TExtension::EXT_draw_buffers) + { + sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second) + << "\n"; + } + + if (iter.first == TExtension::OES_geometry_shader) + { + sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second) + << "\n"; + } + } + + const bool isMultiview = (iter.first == TExtension::OVR_multiview); + if (isMultiview && getShaderType() == GL_VERTEX_SHADER && + (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u) { - sink << "#extension GL_ARB_shader_texture_lod : " << getBehaviorString(iter.second) - << "\n"; + // Emit the NV_viewport_array2 extension in a vertex shader if the + // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview(2) + // extension is requested. + sink << "#extension GL_NV_viewport_array2 : require\n"; } } // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330 - if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT) + if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT && + getShaderType() != GL_COMPUTE_SHADER) { sink << "#extension GL_ARB_explicit_attrib_location : require\n"; } + // Need to enable gpu_shader5 to have index constant sampler array indexing + if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT && + getShaderVersion() == 100) + { + // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently + // support index constant sampler array indexing, but don't have the extension or + // on drivers that don't have the extension at all as it would break WebGL 1 for + // some users. + sink << "#extension GL_ARB_gpu_shader5 : enable\n"; + } + TExtensionGLSL extensionGLSL(getOutputType()); root->traverse(&extensionGLSL); @@ -195,3 +326,14 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) sink << "#extension " << ext << " : require\n"; } } + +void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName) +{ + if (isVaryingDefined(builtinVaryingName)) + { + TInfoSinkBase &sink = getInfoSink().obj; + sink << "invariant " << builtinVaryingName << ";\n"; + } +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h index 4f07b21980..982d0e5ddc 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h @@ -9,19 +9,30 @@ #include "compiler/translator/Compiler.h" +namespace sh +{ + class TranslatorGLSL : public TCompiler { public: TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); protected: - void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) override; - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; + bool shouldCollectVariables(ShCompileOptions compileOptions) override; private: void writeVersion(TIntermNode *root); - void writeExtensionBehavior(TIntermNode *root); + void writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions); + void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName); }; +} // namespace sh + #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 c5d18d21bf..091a649cfc 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -6,79 +6,156 @@ #include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/AddDefaultReturnStatements.h" #include "compiler/translator/ArrayReturnValueToOutParameter.h" +#include "compiler/translator/BreakVariableAliasingInInnerLoops.h" +#include "compiler/translator/EmulatePrecision.h" +#include "compiler/translator/ExpandIntegerPowExpressions.h" +#include "compiler/translator/IntermNodePatternMatcher.h" #include "compiler/translator/OutputHLSL.h" #include "compiler/translator/RemoveDynamicIndexing.h" +#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h" #include "compiler/translator/RewriteElseBlocks.h" +#include "compiler/translator/RewriteTexelFetchOffset.h" +#include "compiler/translator/RewriteUnaryMinusOperatorInt.h" #include "compiler/translator/SeparateArrayInitialization.h" #include "compiler/translator/SeparateDeclarations.h" #include "compiler/translator/SeparateExpressionsReturningArrays.h" +#include "compiler/translator/SimplifyLoopConditions.h" +#include "compiler/translator/SplitSequenceOperator.h" #include "compiler/translator/UnfoldShortCircuitToIf.h" +#include "compiler/translator/WrapSwitchStatementsInBlocks.h" + +namespace sh +{ TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) : TCompiler(type, spec, output) { } -void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) +void TranslatorHLSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) { const ShBuiltInResources &resources = getResources(); - int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + + sh::AddDefaultReturnStatements(root); - SeparateDeclarations(root); + // Note that SimplifyLoopConditions needs to be run before any other AST transformations that + // may need to generate new statements from loop conditions or loop expressions. + // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl(). + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + &getSymbolTable(), getShaderVersion()); + + SplitSequenceOperator(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + &getSymbolTable(), getShaderVersion()); // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf. - UnfoldShortCircuitToIf(root, getTemporaryIndex()); + UnfoldShortCircuitToIf(root, &getSymbolTable()); - SeparateExpressionsReturningArrays(root, getTemporaryIndex()); + SeparateExpressionsReturningArrays(root, &getSymbolTable()); // 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()); + ArrayReturnValueToOutParameter(root, &getSymbolTable()); if (!shouldRunLoopAndIndexingValidation(compileOptions)) { // HLSL doesn't support dynamic indexing of vectors and matrices. - RemoveDynamicIndexing(root, getTemporaryIndex(), getSymbolTable(), getShaderVersion()); + RemoveDynamicIndexing(root, &getSymbolTable(), getShaderVersion(), perfDiagnostics); } // 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::RewriteElseBlocks(root, &getSymbolTable()); + } + + // Work around an HLSL compiler frontend aliasing optimization bug. + // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed + // in the next release of d3dcompiler.dll, it would be nice to detect the DLL + // version and only apply the workaround if it is too old. + sh::BreakVariableAliasingInInnerLoops(root); + + // WrapSwitchStatementsInBlocks should be called after any AST transformations that might + // introduce variable declarations inside the main scope of any switch statement. + if (WrapSwitchStatementsInBlocks(root)) + { + // The WrapSwitchStatementsInBlocks step might introduce new no-op cases to the end of + // switch statements, so make sure to clean up the AST. + RemoveNoOpCasesFromEndOfSwitchStatements(root, &getSymbolTable()); + } + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision(&getSymbolTable(), getShaderVersion()); + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(), + getOutputType()); + } + + if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0) + { + sh::ExpandIntegerPowExpressions(root, &getSymbolTable()); + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + + if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) && + getShaderType() == GL_VERTEX_SHADER) + { + sh::RewriteUnaryMinusOperatorInt(root); } sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), - getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions); + getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), + compileOptions, &getSymbolTable(), perfDiagnostics); outputHLSL.output(root, getInfoSink().obj); - mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap(); - mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); + mUniformBlockRegisterMap = outputHLSL.getUniformBlockRegisterMap(); + mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); } -bool TranslatorHLSL::hasInterfaceBlock(const std::string &interfaceBlockName) const +bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll() { - return (mInterfaceBlockRegisterMap.count(interfaceBlockName) > 0); + // Not necessary when translating to HLSL. + return false; } -unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interfaceBlockName) const +bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const { - ASSERT(hasInterfaceBlock(interfaceBlockName)); - return mInterfaceBlockRegisterMap.find(interfaceBlockName)->second; + return (mUniformBlockRegisterMap.count(uniformBlockName) > 0); } -bool TranslatorHLSL::hasUniform(const std::string &uniformName) const +unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const { - return (mUniformRegisterMap.count(uniformName) > 0); + ASSERT(hasUniformBlock(uniformBlockName)); + return mUniformBlockRegisterMap.find(uniformBlockName)->second; } -unsigned int TranslatorHLSL::getUniformRegister(const std::string &uniformName) const +const std::map *TranslatorHLSL::getUniformRegisterMap() const { - ASSERT(hasUniform(uniformName)); - return mUniformRegisterMap.find(uniformName)->second; + return &mUniformRegisterMap; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h index 907d816744..d7005a603c 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h @@ -9,26 +9,33 @@ #include "compiler/translator/Compiler.h" +namespace sh +{ + class TranslatorHLSL : public TCompiler { public: TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); TranslatorHLSL *getAsTranslatorHLSL() override { return this; } - bool hasInterfaceBlock(const std::string &interfaceBlockName) const; - unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const; + bool hasUniformBlock(const std::string &interfaceBlockName) const; + unsigned int getUniformBlockRegister(const std::string &interfaceBlockName) const; - bool hasUniform(const std::string &uniformName) const; - unsigned int getUniformRegister(const std::string &uniformName) const; + const std::map *getUniformRegisterMap() const; protected: - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; // collectVariables needs to be run always so registers can be assigned. - bool shouldCollectVariables(int compileOptions) override { return true; } + bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; } - std::map mInterfaceBlockRegisterMap; + std::map mUniformBlockRegisterMap; std::map mUniformRegisterMap; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.cpp new file mode 100644 index 0000000000..0fe2a21f90 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.cpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// TranslatorVulkan: +// A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl. +// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side). +// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt +// + +#include "compiler/translator/TranslatorVulkan.h" + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/OutputVulkanGLSL.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +class DeclareDefaultUniformsTraverser : public TIntermTraverser +{ + public: + DeclareDefaultUniformsTraverser(TInfoSinkBase *sink, + ShHashFunction64 hashFunction, + NameMap *nameMap) + : TIntermTraverser(true, true, true), + mSink(sink), + mHashFunction(hashFunction), + mNameMap(nameMap), + mInDefaultUniform(false) + { + } + + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + const TIntermSequence &sequence = *(node->getSequence()); + + // TODO(jmadill): Compound declarations. + ASSERT(sequence.size() == 1); + + TIntermTyped *variable = sequence.front()->getAsTyped(); + const TType &type = variable->getType(); + bool isUniform = (type.getQualifier() == EvqUniform) && !IsOpaqueType(type.getBasicType()); + + if (visit == PreVisit) + { + if (isUniform) + { + (*mSink) << " " << GetTypeName(type, mHashFunction, mNameMap) << " "; + mInDefaultUniform = true; + } + } + else if (visit == InVisit) + { + mInDefaultUniform = isUniform; + } + else if (visit == PostVisit) + { + if (isUniform) + { + (*mSink) << ";\n"; + + // Remove the uniform declaration from the tree so it isn't parsed again. + TIntermSequence emptyReplacement; + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry( + getParentNode()->getAsBlock(), node, emptyReplacement)); + } + + mInDefaultUniform = false; + } + return true; + } + + void visitSymbol(TIntermSymbol *symbol) override + { + if (mInDefaultUniform) + { + const TName &name = symbol->getName(); + ASSERT(name.getString().substr(0, 3) != "gl_"); + (*mSink) << HashName(name, mHashFunction, mNameMap); + } + } + + private: + TInfoSinkBase *mSink; + ShHashFunction64 mHashFunction; + NameMap *mNameMap; + bool mInDefaultUniform; +}; + +TranslatorVulkan::TranslatorVulkan(sh::GLenum type, ShShaderSpec spec) + : TCompiler(type, spec, SH_GLSL_450_CORE_OUTPUT) +{ +} + +void TranslatorVulkan::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics * /*perfDiagnostics*/) +{ + TInfoSinkBase &sink = getInfoSink().obj; + + sink << "#version 450 core\n"; + + // Write out default uniforms into a uniform block assigned to a specific set/binding. + int defaultUniformCount = 0; + for (const auto &uniform : getUniforms()) + { + if (!uniform.isBuiltIn() && uniform.staticUse && !gl::IsOpaqueType(uniform.type)) + { + ++defaultUniformCount; + } + } + + if (defaultUniformCount > 0) + { + sink << "\nlayout(@@ DEFAULT-UNIFORMS-SET-BINDING @@) uniform defaultUniforms\n{\n"; + + DeclareDefaultUniformsTraverser defaultTraverser(&sink, getHashFunction(), &getNameMap()); + root->traverse(&defaultTraverser); + defaultTraverser.updateTree(); + + sink << "};\n"; + } + + // 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) + { + bool hasGLFragColor = false; + bool hasGLFragData = false; + + for (const auto &outputVar : outputVariables) + { + if (outputVar.name == "gl_FragColor") + { + ASSERT(!hasGLFragColor); + hasGLFragColor = true; + continue; + } + else if (outputVar.name == "gl_FragData") + { + ASSERT(!hasGLFragData); + hasGLFragData = true; + continue; + } + } + ASSERT(!(hasGLFragColor && hasGLFragData)); + if (hasGLFragColor) + { + sink << "layout(location = 0) out vec4 webgl_FragColor;\n"; + } + if (hasGLFragData) + { + sink << "layout(location = 0) out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; + } + } + + // Write translated shader. + TOutputVulkanGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), + getNameMap(), &getSymbolTable(), getShaderType(), + getShaderVersion(), getOutputType(), compileOptions); + root->traverse(&outputGLSL); +} + +bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll() +{ + // Not necessary. + return false; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.h b/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.h new file mode 100644 index 0000000000..ef67b15ae1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorVulkan.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// TranslatorVulkan: +// A GLSL-based translator that outputs shaders that fit GL_KHR_vulkan_glsl. +// The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side). +// See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt +// + +#ifndef COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_ +#define COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_ + +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +class TranslatorVulkan : public TCompiler +{ + public: + TranslatorVulkan(sh::GLenum type, ShShaderSpec spec); + + protected: + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TRANSLATORVULKAN_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Types.cpp b/src/3rdparty/angle/src/compiler/translator/Types.cpp index 87fdfe0d54..530ffe3aeb 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Types.cpp @@ -5,58 +5,394 @@ // #if defined(_MSC_VER) -#pragma warning(disable: 4718) +#pragma warning(disable : 4718) #endif #include "compiler/translator/Types.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" #include #include -const char* getBasicString(TBasicType t) +namespace sh +{ + +const char *getBasicString(TBasicType t) { switch (t) { - case EbtVoid: return "void"; break; - case EbtFloat: return "float"; break; - case EbtInt: return "int"; break; - case EbtUInt: return "uint"; break; - case EbtBool: return "bool"; break; - case EbtSampler2D: return "sampler2D"; break; - case EbtSampler3D: return "sampler3D"; break; - case EbtSamplerCube: return "samplerCube"; break; - case EbtSamplerExternalOES: return "samplerExternalOES"; break; - case EbtSampler2DRect: return "sampler2DRect"; break; - case EbtSampler2DArray: return "sampler2DArray"; break; - case EbtISampler2D: return "isampler2D"; break; - case EbtISampler3D: return "isampler3D"; break; - case EbtISamplerCube: return "isamplerCube"; break; - case EbtISampler2DArray: return "isampler2DArray"; break; - case EbtUSampler2D: return "usampler2D"; break; - case EbtUSampler3D: return "usampler3D"; break; - case EbtUSamplerCube: return "usamplerCube"; break; - case EbtUSampler2DArray: return "usampler2DArray"; break; - case EbtSampler2DShadow: return "sampler2DShadow"; break; - case EbtSamplerCubeShadow: return "samplerCubeShadow"; break; - case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; break; - case EbtStruct: return "structure"; break; - case EbtInterfaceBlock: return "interface block"; break; - default: UNREACHABLE(); return "unknown type"; + case EbtVoid: + return "void"; + case EbtFloat: + return "float"; + case EbtInt: + return "int"; + case EbtUInt: + return "uint"; + case EbtBool: + return "bool"; + case EbtYuvCscStandardEXT: + return "yuvCscStandardEXT"; + case EbtSampler2D: + return "sampler2D"; + case EbtSampler3D: + return "sampler3D"; + case EbtSamplerCube: + return "samplerCube"; + case EbtSamplerExternalOES: + return "samplerExternalOES"; + case EbtSamplerExternal2DY2YEXT: + return "__samplerExternal2DY2YEXT"; + case EbtSampler2DRect: + return "sampler2DRect"; + case EbtSampler2DArray: + return "sampler2DArray"; + case EbtSampler2DMS: + return "sampler2DMS"; + case EbtISampler2D: + return "isampler2D"; + case EbtISampler3D: + return "isampler3D"; + case EbtISamplerCube: + return "isamplerCube"; + case EbtISampler2DArray: + return "isampler2DArray"; + case EbtISampler2DMS: + return "isampler2DMS"; + case EbtUSampler2D: + return "usampler2D"; + case EbtUSampler3D: + return "usampler3D"; + case EbtUSamplerCube: + return "usamplerCube"; + case EbtUSampler2DArray: + return "usampler2DArray"; + case EbtUSampler2DMS: + return "usampler2DMS"; + case EbtSampler2DShadow: + return "sampler2DShadow"; + case EbtSamplerCubeShadow: + return "samplerCubeShadow"; + case EbtSampler2DArrayShadow: + return "sampler2DArrayShadow"; + case EbtStruct: + return "structure"; + case EbtInterfaceBlock: + return "interface block"; + case EbtImage2D: + return "image2D"; + case EbtIImage2D: + return "iimage2D"; + case EbtUImage2D: + return "uimage2D"; + case EbtImage3D: + return "image3D"; + case EbtIImage3D: + return "iimage3D"; + case EbtUImage3D: + return "uimage3D"; + case EbtImage2DArray: + return "image2DArray"; + case EbtIImage2DArray: + return "iimage2DArray"; + case EbtUImage2DArray: + return "uimage2DArray"; + case EbtImageCube: + return "imageCube"; + case EbtIImageCube: + return "iimageCube"; + case EbtUImageCube: + return "uimageCube"; + case EbtAtomicCounter: + return "atomic_uint"; + default: + UNREACHABLE(); + return "unknown type"; } } +// TType implementation. +TType::TType() + : type(EbtVoid), + precision(EbpUndefined), + qualifier(EvqGlobal), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(0), + secondarySize(0), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{ +} + +TType::TType(TBasicType t, unsigned char ps, unsigned char ss) + : type(t), + precision(EbpUndefined), + qualifier(EvqGlobal), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(ps), + secondarySize(ss), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{ +} + +TType::TType(TBasicType t, TPrecision p, TQualifier q, unsigned char ps, unsigned char ss) + : type(t), + precision(p), + qualifier(q), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(ps), + secondarySize(ss), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{ +} + TType::TType(const TPublicType &p) - : 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) + : type(p.getBasicType()), + precision(p.precision), + qualifier(p.qualifier), + invariant(p.invariant), + memoryQualifier(p.memoryQualifier), + layoutQualifier(p.layoutQualifier), + primarySize(p.getPrimarySize()), + secondarySize(p.getSecondarySize()), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) { - if (p.userDef) - structure = p.userDef->getStruct(); + ASSERT(primarySize <= 4); + ASSERT(secondarySize <= 4); + if (p.isArray()) + { + mArraySizes = new TVector(*p.arraySizes); + } + if (p.getUserDef()) + { + mStructure = p.getUserDef(); + mIsStructSpecifier = p.isStructSpecifier(); + } } -bool TStructure::equals(const TStructure &other) const +TType::TType(TStructure *userDef) + : type(EbtStruct), + precision(EbpUndefined), + qualifier(EvqTemporary), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(1), + secondarySize(1), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(userDef), + mIsStructSpecifier(false), + mMangledName(nullptr) { - return (uniqueId() == other.uniqueId()); +} + +TType::TType(TInterfaceBlock *interfaceBlockIn, + TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn) + : type(EbtInterfaceBlock), + precision(EbpUndefined), + qualifier(qualifierIn), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(layoutQualifierIn), + primarySize(1), + secondarySize(1), + mArraySizes(nullptr), + mInterfaceBlock(interfaceBlockIn), + mStructure(0), + mIsStructSpecifier(false), + mMangledName(nullptr) +{ +} + +TType::TType(const TType &t) + : type(t.type), + precision(t.precision), + qualifier(t.qualifier), + invariant(t.invariant), + memoryQualifier(t.memoryQualifier), + layoutQualifier(t.layoutQualifier), + primarySize(t.primarySize), + secondarySize(t.secondarySize), + mArraySizes(t.mArraySizes ? new TVector(*t.mArraySizes) : nullptr), + mInterfaceBlock(t.mInterfaceBlock), + mStructure(t.mStructure), + mIsStructSpecifier(t.mIsStructSpecifier), + mMangledName(t.mMangledName) +{ +} + +TType &TType::operator=(const TType &t) +{ + type = t.type; + precision = t.precision; + qualifier = t.qualifier; + invariant = t.invariant; + memoryQualifier = t.memoryQualifier; + layoutQualifier = t.layoutQualifier; + primarySize = t.primarySize; + secondarySize = t.secondarySize; + mArraySizes = t.mArraySizes ? new TVector(*t.mArraySizes) : nullptr; + mInterfaceBlock = t.mInterfaceBlock; + mStructure = t.mStructure; + mIsStructSpecifier = t.mIsStructSpecifier; + mMangledName = t.mMangledName; + return *this; +} + +bool TType::canBeConstructed() const +{ + switch (type) + { + case EbtFloat: + case EbtInt: + case EbtUInt: + case EbtBool: + case EbtStruct: + return true; + default: + return false; + } +} + +const char *TType::getBuiltInTypeNameString() const +{ + if (isMatrix()) + { + switch (getCols()) + { + case 2: + switch (getRows()) + { + case 2: + return "mat2"; + case 3: + return "mat2x3"; + case 4: + return "mat2x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 3: + switch (getRows()) + { + case 2: + return "mat3x2"; + case 3: + return "mat3"; + case 4: + return "mat3x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 4: + switch (getRows()) + { + case 2: + return "mat4x2"; + case 3: + return "mat4x3"; + case 4: + return "mat4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + if (isVector()) + { + switch (getBasicType()) + { + case EbtFloat: + switch (getNominalSize()) + { + case 2: + return "vec2"; + case 3: + return "vec3"; + case 4: + return "vec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtInt: + switch (getNominalSize()) + { + case 2: + return "ivec2"; + case 3: + return "ivec3"; + case 4: + return "ivec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtBool: + switch (getNominalSize()) + { + case 2: + return "bvec2"; + case 3: + return "bvec3"; + case 4: + return "bvec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtUInt: + switch (getNominalSize()) + { + case 2: + return "uvec2"; + case 3: + return "uvec3"; + case 4: + return "uvec4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + ASSERT(getBasicType() != EbtStruct); + ASSERT(getBasicType() != EbtInterfaceBlock); + return getBasicString(); } TString TType::getCompleteString() const @@ -69,8 +405,14 @@ TString TType::getCompleteString() const stream << getQualifierString() << " "; if (precision != EbpUndefined) stream << getPrecisionString() << " "; - if (array) - stream << "array[" << getArraySize() << "] of "; + if (mArraySizes) + { + for (auto arraySizeIter = mArraySizes->rbegin(); arraySizeIter != mArraySizes->rend(); + ++arraySizeIter) + { + stream << "array[" << (*arraySizeIter) << "] of "; + } + } if (isMatrix()) stream << getCols() << "X" << getRows() << " matrix of "; else if (isVector()) @@ -83,7 +425,7 @@ TString TType::getCompleteString() const // // Recursively generate mangled names. // -TString TType::buildMangledName() const +const char *TType::buildMangledName() const { TString mangledName; if (isMatrix()) @@ -93,78 +435,132 @@ TString TType::buildMangledName() const switch (type) { - case EbtFloat: - mangledName += 'f'; - break; - case EbtInt: - mangledName += 'i'; - break; - case EbtUInt: - mangledName += 'u'; - break; - case EbtBool: - mangledName += 'b'; - break; - case EbtSampler2D: - mangledName += "s2"; - break; - case EbtSampler3D: - mangledName += "s3"; - break; - case EbtSamplerCube: - mangledName += "sC"; - break; - case EbtSampler2DArray: - mangledName += "s2a"; - break; - case EbtSamplerExternalOES: - mangledName += "sext"; - break; - case EbtSampler2DRect: - mangledName += "s2r"; - break; - case EbtISampler2D: - mangledName += "is2"; - break; - case EbtISampler3D: - mangledName += "is3"; - break; - case EbtISamplerCube: - mangledName += "isC"; - break; - case EbtISampler2DArray: - mangledName += "is2a"; - break; - case EbtUSampler2D: - mangledName += "us2"; - break; - case EbtUSampler3D: - mangledName += "us3"; - break; - case EbtUSamplerCube: - mangledName += "usC"; - break; - case EbtUSampler2DArray: - mangledName += "us2a"; - break; - case EbtSampler2DShadow: - mangledName += "s2s"; - break; - case EbtSamplerCubeShadow: - mangledName += "sCs"; - break; - case EbtSampler2DArrayShadow: - mangledName += "s2as"; - break; - case EbtStruct: - mangledName += structure->mangledName(); - break; - case EbtInterfaceBlock: - mangledName += interfaceBlock->mangledName(); - break; - default: - // EbtVoid, EbtAddress and non types - break; + case EbtFloat: + mangledName += 'f'; + break; + case EbtInt: + mangledName += 'i'; + break; + case EbtUInt: + mangledName += 'u'; + break; + case EbtBool: + mangledName += 'b'; + break; + case EbtYuvCscStandardEXT: + mangledName += "ycs"; + break; + case EbtSampler2D: + mangledName += "s2"; + break; + case EbtSampler3D: + mangledName += "s3"; + break; + case EbtSamplerCube: + mangledName += "sC"; + break; + case EbtSampler2DArray: + mangledName += "s2a"; + break; + case EbtSamplerExternalOES: + mangledName += "sext"; + break; + case EbtSamplerExternal2DY2YEXT: + mangledName += "sext2y2y"; + break; + case EbtSampler2DRect: + mangledName += "s2r"; + break; + case EbtSampler2DMS: + mangledName += "s2ms"; + break; + case EbtISampler2D: + mangledName += "is2"; + break; + case EbtISampler3D: + mangledName += "is3"; + break; + case EbtISamplerCube: + mangledName += "isC"; + break; + case EbtISampler2DArray: + mangledName += "is2a"; + break; + case EbtISampler2DMS: + mangledName += "is2ms"; + break; + case EbtUSampler2D: + mangledName += "us2"; + break; + case EbtUSampler3D: + mangledName += "us3"; + break; + case EbtUSamplerCube: + mangledName += "usC"; + break; + case EbtUSampler2DArray: + mangledName += "us2a"; + break; + case EbtUSampler2DMS: + mangledName += "us2ms"; + break; + case EbtSampler2DShadow: + mangledName += "s2s"; + break; + case EbtSamplerCubeShadow: + mangledName += "sCs"; + break; + case EbtSampler2DArrayShadow: + mangledName += "s2as"; + break; + case EbtImage2D: + mangledName += "im2"; + break; + case EbtIImage2D: + mangledName += "iim2"; + break; + case EbtUImage2D: + mangledName += "uim2"; + break; + case EbtImage3D: + mangledName += "im3"; + break; + case EbtIImage3D: + mangledName += "iim3"; + break; + case EbtUImage3D: + mangledName += "uim3"; + break; + case EbtImage2DArray: + mangledName += "im2a"; + break; + case EbtIImage2DArray: + mangledName += "iim2a"; + break; + case EbtUImage2DArray: + mangledName += "uim2a"; + break; + case EbtImageCube: + mangledName += "imc"; + break; + case EbtIImageCube: + mangledName += "iimc"; + break; + case EbtUImageCube: + mangledName += "uimc"; + break; + case EbtAtomicCounter: + mangledName += "ac"; + break; + case EbtStruct: + mangledName += mStructure->mangledName(); + break; + case EbtInterfaceBlock: + mangledName += mInterfaceBlock->mangledName(); + break; + default: + // EbtVoid, EbtAddress and non types + break; } if (isMatrix()) @@ -178,15 +574,25 @@ TString TType::buildMangledName() const mangledName += static_cast('0' + getNominalSize()); } - if (isArray()) + if (mArraySizes) { - char buf[20]; - snprintf(buf, sizeof(buf), "%d", arraySize); - mangledName += '['; - mangledName += buf; - mangledName += ']'; + for (unsigned int arraySize : *mArraySizes) + { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } } - return mangledName; + + mangledName += ';'; + + // Copy string contents into a pool-allocated buffer, so we never need to call delete. + size_t requiredSize = mangledName.size() + 1; + char *buffer = reinterpret_cast(GetGlobalPoolAllocator()->allocate(requiredSize)); + memcpy(buffer, mangledName.c_str(), requiredSize); + return buffer; } size_t TType::getObjectSize() const @@ -194,23 +600,265 @@ size_t TType::getObjectSize() const size_t totalSize; if (getBasicType() == EbtStruct) - totalSize = structure->objectSize(); + totalSize = mStructure->objectSize(); else totalSize = primarySize * secondarySize; - if (isArray()) + if (totalSize == 0) + return 0; + + if (mArraySizes) { - // TODO: getArraySize() returns an int, not a size_t - size_t currentArraySize = getArraySize(); - if (currentArraySize > INT_MAX / totalSize) - totalSize = INT_MAX; - else - totalSize *= currentArraySize; + for (size_t arraySize : *mArraySizes) + { + if (arraySize > INT_MAX / totalSize) + totalSize = INT_MAX; + else + totalSize *= arraySize; + } } return totalSize; } +int TType::getLocationCount() const +{ + int count = 1; + + if (getBasicType() == EbtStruct) + { + count = mStructure->getLocationCount(); + } + + if (count == 0) + { + return 0; + } + + if (mArraySizes) + { + for (unsigned int arraySize : *mArraySizes) + { + if (arraySize > static_cast(std::numeric_limits::max() / count)) + { + count = std::numeric_limits::max(); + } + else + { + count *= static_cast(arraySize); + } + } + } + + return count; +} + +unsigned int TType::getArraySizeProduct() const +{ + if (!mArraySizes) + return 1u; + + unsigned int product = 1u; + + for (unsigned int arraySize : *mArraySizes) + { + product *= arraySize; + } + return product; +} + +bool TType::isUnsizedArray() const +{ + if (!mArraySizes) + return false; + + for (unsigned int arraySize : *mArraySizes) + { + if (arraySize == 0u) + { + return true; + } + } + return false; +} + +bool TType::sameNonArrayType(const TType &right) const +{ + return (type == right.type && primarySize == right.primarySize && + secondarySize == right.secondarySize && mStructure == right.mStructure); +} + +bool TType::isElementTypeOf(const TType &arrayType) const +{ + if (!sameNonArrayType(arrayType)) + { + return false; + } + if (arrayType.getNumArraySizes() != getNumArraySizes() + 1u) + { + return false; + } + if (isArray()) + { + for (size_t i = 0; i < mArraySizes->size(); ++i) + { + if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i]) + { + return false; + } + } + } + return true; +} + +void TType::sizeUnsizedArrays(const TVector *newArraySizes) +{ + size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0; + for (size_t i = 0u; i < getNumArraySizes(); ++i) + { + if ((*mArraySizes)[i] == 0) + { + if (i < newArraySizesSize) + { + ASSERT(newArraySizes != nullptr); + (*mArraySizes)[i] = (*newArraySizes)[i]; + } + else + { + (*mArraySizes)[i] = 1u; + } + } + } + invalidateMangledName(); +} + +void TType::sizeOutermostUnsizedArray(unsigned int arraySize) +{ + ASSERT(isArray()); + ASSERT(mArraySizes->back() == 0u); + mArraySizes->back() = arraySize; +} + +void TType::setBasicType(TBasicType t) +{ + if (type != t) + { + type = t; + invalidateMangledName(); + } +} + +void TType::setPrimarySize(unsigned char ps) +{ + if (primarySize != ps) + { + ASSERT(ps <= 4); + primarySize = ps; + invalidateMangledName(); + } +} + +void TType::setSecondarySize(unsigned char ss) +{ + if (secondarySize != ss) + { + ASSERT(ss <= 4); + secondarySize = ss; + invalidateMangledName(); + } +} + +void TType::makeArray(unsigned int s) +{ + if (!mArraySizes) + mArraySizes = new TVector(); + + mArraySizes->push_back(s); + invalidateMangledName(); +} + +void TType::makeArrays(const TVector &sizes) +{ + if (!mArraySizes) + mArraySizes = new TVector(); + + mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end()); + invalidateMangledName(); +} + +void TType::setArraySize(size_t arrayDimension, unsigned int s) +{ + ASSERT(mArraySizes != nullptr); + ASSERT(arrayDimension < mArraySizes->size()); + if (mArraySizes->at(arrayDimension) != s) + { + (*mArraySizes)[arrayDimension] = s; + invalidateMangledName(); + } +} + +void TType::toArrayElementType() +{ + ASSERT(mArraySizes != nullptr); + if (mArraySizes->size() > 0) + { + mArraySizes->pop_back(); + invalidateMangledName(); + } +} + +void TType::setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) +{ + if (mInterfaceBlock != interfaceBlockIn) + { + mInterfaceBlock = interfaceBlockIn; + invalidateMangledName(); + } +} + +void TType::setStruct(TStructure *s) +{ + if (mStructure != s) + { + mStructure = s; + invalidateMangledName(); + } +} + +const char *TType::getMangledName() const +{ + if (mMangledName == nullptr) + { + mMangledName = buildMangledName(); + } + + return mMangledName; +} + +void TType::realize() +{ + getMangledName(); +} + +void TType::invalidateMangledName() +{ + mMangledName = nullptr; +} + +// TStructure implementation. +TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields) + : TFieldListCollection(name, fields), + mDeepestNesting(0), + mUniqueId(symbolTable->nextUniqueId()), + mAtGlobalScope(false) +{ +} + +bool TStructure::equals(const TStructure &other) const +{ + return (uniqueId() == other.uniqueId()); +} + bool TStructure::containsArrays() const { for (size_t i = 0; i < mFields->size(); ++i) @@ -244,6 +892,66 @@ bool TStructure::containsSamplers() const return false; } +void TType::createSamplerSymbols(const TString &namePrefix, + const TString &apiNamePrefix, + TVector *outputSymbols, + TMap *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const +{ + if (isStructureContainingSamplers()) + { + if (isArray()) + { + TType elementType(*this); + elementType.toArrayElementType(); + for (unsigned int arrayIndex = 0u; arrayIndex < getOutermostArraySize(); ++arrayIndex) + { + TStringStream elementName; + elementName << namePrefix << "_" << arrayIndex; + TStringStream elementApiName; + elementApiName << apiNamePrefix << "[" << arrayIndex << "]"; + elementType.createSamplerSymbols(elementName.str(), elementApiName.str(), + outputSymbols, outputSymbolsToAPINames, + symbolTable); + } + } + else + { + mStructure->createSamplerSymbols(namePrefix, apiNamePrefix, outputSymbols, + outputSymbolsToAPINames, symbolTable); + } + return; + } + + ASSERT(IsSampler(type)); + TIntermSymbol *symbol = new TIntermSymbol(symbolTable->nextUniqueId(), namePrefix, *this); + outputSymbols->push_back(symbol); + if (outputSymbolsToAPINames) + { + (*outputSymbolsToAPINames)[symbol] = apiNamePrefix; + } +} + +void TStructure::createSamplerSymbols(const TString &namePrefix, + const TString &apiNamePrefix, + TVector *outputSymbols, + TMap *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const +{ + ASSERT(containsSamplers()); + for (auto &field : *mFields) + { + const TType *fieldType = field->type(); + if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) + { + TString fieldName = namePrefix + "_" + field->name(); + TString fieldApiName = apiNamePrefix + "." + field->name(); + fieldType->createSamplerSymbols(fieldName, fieldApiName, outputSymbols, + outputSymbolsToAPINames, symbolTable); + } + } +} + TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const { TString mangledName(mangledNamePrefix); @@ -259,9 +967,9 @@ TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) size_t TFieldListCollection::calculateObjectSize() const { size_t size = 0; - for (size_t i = 0; i < mFields->size(); ++i) + for (const TField *field : *mFields) { - size_t fieldSize = (*mFields)[i]->type()->getObjectSize(); + size_t fieldSize = field->type()->getObjectSize(); if (fieldSize > INT_MAX - size) size = INT_MAX; else @@ -270,6 +978,24 @@ size_t TFieldListCollection::calculateObjectSize() const return size; } +int TFieldListCollection::getLocationCount() const +{ + int count = 0; + for (const TField *field : *mFields) + { + int fieldCount = field->type()->getLocationCount(); + if (fieldCount > std::numeric_limits::max() - count) + { + count = std::numeric_limits::max(); + } + else + { + count += fieldCount; + } + } + return count; +} + int TStructure::calculateDeepestNesting() const { int maxNesting = 0; @@ -277,3 +1003,70 @@ int TStructure::calculateDeepestNesting() const maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting()); return 1 + maxNesting; } + +// TPublicType implementation. +void TPublicType::initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q) +{ + typeSpecifierNonArray = typeSpecifier; + layoutQualifier = TLayoutQualifier::Create(); + memoryQualifier = TMemoryQualifier::Create(); + qualifier = q; + invariant = false; + precision = EbpUndefined; + arraySizes = nullptr; +} + +void TPublicType::initializeBasicType(TBasicType basicType) +{ + typeSpecifierNonArray.type = basicType; + typeSpecifierNonArray.primarySize = 1; + typeSpecifierNonArray.secondarySize = 1; + layoutQualifier = TLayoutQualifier::Create(); + memoryQualifier = TMemoryQualifier::Create(); + qualifier = EvqTemporary; + invariant = false; + precision = EbpUndefined; + arraySizes = nullptr; +} + +bool TPublicType::isStructureContainingArrays() const +{ + if (!typeSpecifierNonArray.userDef) + { + return false; + } + + return typeSpecifierNonArray.userDef->containsArrays(); +} + +bool TPublicType::isStructureContainingType(TBasicType t) const +{ + if (!typeSpecifierNonArray.userDef) + { + return false; + } + + return typeSpecifierNonArray.userDef->containsType(t); +} + +void TPublicType::setArraySizes(TVector *sizes) +{ + arraySizes = sizes; +} + +bool TPublicType::isArray() const +{ + return arraySizes && !arraySizes->empty(); +} + +void TPublicType::clearArrayness() +{ + arraySizes = nullptr; +} + +bool TPublicType::isAggregate() const +{ + return isArray() || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/Types.h b/src/3rdparty/angle/src/compiler/translator/Types.h index c2968dceba..7dc84c5b1c 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.h +++ b/src/3rdparty/angle/src/compiler/translator/Types.h @@ -12,41 +12,33 @@ #include "compiler/translator/BaseTypes.h" #include "compiler/translator/Common.h" +#include "compiler/translator/SymbolUniqueId.h" + +namespace sh +{ struct TPublicType; class TType; class TSymbol; +class TIntermSymbol; +class TSymbolTable; class TField : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); TField(TType *type, TString *name, const TSourceLoc &line) - : mType(type), - mName(name), - mLine(line) + : mType(type), mName(name), mLine(line) { } // TODO(alokp): We should only return const type. // Fix it by tweaking grammar. - TType *type() - { - return mType; - } - const TType *type() const - { - return mType; - } + TType *type() { return mType; } + const TType *type() const { return mType; } - const TString &name() const - { - return *mName; - } - const TSourceLoc &line() const - { - return mLine; - } + const TString &name() const { return *mName; } + const TSourceLoc &line() const { return mLine; } private: TType *mType; @@ -58,33 +50,28 @@ typedef TVector TFieldList; inline TFieldList *NewPoolTFieldList() { void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList)); - return new(memory) TFieldList; + return new (memory) TFieldList; } class TFieldListCollection : angle::NonCopyable { public: - const TString &name() const - { - return *mName; - } - const TFieldList &fields() const - { - return *mFields; - } + const TString &name() const { return *mName; } + const TFieldList &fields() const { return *mFields; } size_t objectSize() const { if (mObjectSize == 0) mObjectSize = calculateObjectSize(); return mObjectSize; - }; + } + + // How many locations the field list consumes as a uniform. + int getLocationCount() const; protected: TFieldListCollection(const TString *name, TFieldList *fields) - : mName(name), - mFields(fields), - mObjectSize(0) + : mName(name), mFields(fields), mObjectSize(0) { } TString buildMangledName(const TString &mangledNamePrefix) const; @@ -102,13 +89,7 @@ class TStructure : public TFieldListCollection { public: POOL_ALLOCATOR_NEW_DELETE(); - TStructure(const TString *name, TFieldList *fields) - : TFieldListCollection(name, fields), - mDeepestNesting(0), - mUniqueId(0), - mAtGlobalScope(false) - { - } + TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields); int deepestNesting() const { @@ -120,28 +101,19 @@ class TStructure : public TFieldListCollection bool containsType(TBasicType t) const; bool containsSamplers() const; - bool equals(const TStructure &other) const; + void createSamplerSymbols(const TString &namePrefix, + const TString &apiNamePrefix, + TVector *outputSymbols, + TMap *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const; - void setUniqueId(int uniqueId) - { - mUniqueId = uniqueId; - } + bool equals(const TStructure &other) const; - int uniqueId() const - { - ASSERT(mUniqueId != 0); - return mUniqueId; - } + int uniqueId() const { return mUniqueId.get(); } - void setAtGlobalScope(bool atGlobalScope) - { - mAtGlobalScope = atGlobalScope; - } + void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; } - bool atGlobalScope() const - { - return mAtGlobalScope; - } + bool atGlobalScope() const { return mAtGlobalScope; } const TString &mangledName() const { @@ -158,13 +130,13 @@ class TStructure : public TFieldListCollection void setName(const TString &name) { TString *mutableName = const_cast(mName); - *mutableName = name; + *mutableName = name; } int calculateDeepestNesting() const; mutable int mDeepestNesting; - int mUniqueId; + const TSymbolUniqueId mUniqueId; bool mAtGlobalScope; }; @@ -172,40 +144,23 @@ class TInterfaceBlock : public TFieldListCollection { public: POOL_ALLOCATOR_NEW_DELETE(); - TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName, - int arraySize, const TLayoutQualifier &layoutQualifier) + TInterfaceBlock(const TString *name, + TFieldList *fields, + const TString *instanceName, + const TLayoutQualifier &layoutQualifier) : TFieldListCollection(name, fields), mInstanceName(instanceName), - mArraySize(arraySize), mBlockStorage(layoutQualifier.blockStorage), - mMatrixPacking(layoutQualifier.matrixPacking) + mMatrixPacking(layoutQualifier.matrixPacking), + mBinding(layoutQualifier.binding) { } - const TString &instanceName() const - { - return *mInstanceName; - } - bool hasInstanceName() const - { - return mInstanceName != NULL; - } - bool isArray() const - { - return mArraySize > 0; - } - int arraySize() const - { - return mArraySize; - } - TLayoutBlockStorage blockStorage() const - { - return mBlockStorage; - } - TLayoutMatrixPacking matrixPacking() const - { - return mMatrixPacking; - } + const TString &instanceName() const { return *mInstanceName; } + bool hasInstanceName() const { return mInstanceName != nullptr; } + TLayoutBlockStorage blockStorage() const { return mBlockStorage; } + TLayoutMatrixPacking matrixPacking() const { return mMatrixPacking; } + int blockBinding() const { return mBinding; } const TString &mangledName() const { if (mMangledName.empty()) @@ -214,10 +169,10 @@ class TInterfaceBlock : public TFieldListCollection } private: - const TString *mInstanceName; // for interface block instance names - int mArraySize; // 0 if not an array + const TString *mInstanceName; // for interface block instance names TLayoutBlockStorage mBlockStorage; TLayoutMatrixPacking mMatrixPacking; + int mBinding; }; // @@ -227,101 +182,42 @@ 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), invariant(false), - layoutQualifier(TLayoutQualifier::create()), - primarySize(ps), secondarySize(ss), array(false), arraySize(0), - interfaceBlock(0), structure(0) - { - } - TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, - unsigned char ps = 1, unsigned char ss = 1, bool a = false) - : type(t), precision(p), qualifier(q), invariant(false), - layoutQualifier(TLayoutQualifier::create()), - primarySize(ps), secondarySize(ss), array(a), arraySize(0), - interfaceBlock(0), structure(0) - { - } + TType(); + explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1); + TType(TBasicType t, + TPrecision p, + TQualifier q = EvqTemporary, + unsigned char ps = 1, + unsigned char ss = 1); explicit TType(const TPublicType &p); - TType(TStructure *userDef, TPrecision p = EbpUndefined) - : type(EbtStruct), precision(p), qualifier(EvqTemporary), invariant(false), - layoutQualifier(TLayoutQualifier::create()), - primarySize(1), secondarySize(1), array(false), arraySize(0), - interfaceBlock(0), structure(userDef) - { - } - TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn, - TLayoutQualifier layoutQualifierIn, int arraySizeIn) - : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn), - invariant(false), layoutQualifier(layoutQualifierIn), - primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), - interfaceBlock(interfaceBlockIn), structure(0) - { - } + explicit TType(TStructure *userDef); + TType(TInterfaceBlock *interfaceBlockIn, + TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn); + TType(const TType &t); + TType &operator=(const TType &t); - TType(const TType &) = default; - TType &operator=(const TType &) = default; + TBasicType getBasicType() const { return type; } + void setBasicType(TBasicType t); - TBasicType getBasicType() const - { - return type; - } - void setBasicType(TBasicType t) - { - if (type != t) - { - type = t; - invalidateMangledName(); - } - } + TPrecision getPrecision() const { return precision; } + void setPrecision(TPrecision p) { precision = p; } - TPrecision getPrecision() const - { - return precision; - } - void setPrecision(TPrecision p) - { - precision = p; - } + TQualifier getQualifier() const { return qualifier; } + void setQualifier(TQualifier q) { qualifier = q; } - TQualifier getQualifier() const - { - return qualifier; - } - void setQualifier(TQualifier q) - { - qualifier = q; - } + bool isInvariant() const { return invariant; } - bool isInvariant() const - { - return invariant; - } + void setInvariant(bool i) { invariant = i; } - TLayoutQualifier getLayoutQualifier() const - { - return layoutQualifier; - } - void setLayoutQualifier(TLayoutQualifier lq) - { - layoutQualifier = lq; - } + TMemoryQualifier getMemoryQualifier() const { return memoryQualifier; } + void setMemoryQualifier(const TMemoryQualifier &mq) { memoryQualifier = mq; } - int getNominalSize() const - { - return primarySize; - } - int getSecondarySize() const - { - return secondarySize; - } + TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; } + void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; } + + int getNominalSize() const { return primarySize; } + int getSecondarySize() const { return secondarySize; } int getCols() const { ASSERT(isMatrix()); @@ -332,139 +228,82 @@ class TType ASSERT(isMatrix()); return secondarySize; } - void setPrimarySize(unsigned char ps) - { - if (primarySize != ps) - { - primarySize = ps; - invalidateMangledName(); - } - } - void setSecondarySize(unsigned char ss) - { - if (secondarySize != ss) - { - secondarySize = ss; - invalidateMangledName(); - } - } + void setPrimarySize(unsigned char ps); + void setSecondarySize(unsigned char ss); // Full size of single instance of type size_t getObjectSize() const; - bool isMatrix() const - { - return primarySize > 1 && secondarySize > 1; - } - bool isNonSquareMatrix() const - { - return isMatrix() && primarySize != secondarySize; - } - bool isArray() const - { - return array; - } - bool isUnsizedArray() const - { - return array && arraySize == 0; - } - int getArraySize() const - { - return arraySize; - } - void setArraySize(int s) - { - if (!array || arraySize != s) - { - array = true; - arraySize = s; - invalidateMangledName(); - } - } - void clearArrayness() - { - if (array) - { - array = false; - arraySize = 0; - invalidateMangledName(); - } - } + // Get how many locations this type consumes as a uniform. + int getLocationCount() const; - TInterfaceBlock *getInterfaceBlock() const - { - return interfaceBlock; - } - void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) - { - if (interfaceBlock != interfaceBlockIn) - { - interfaceBlock = interfaceBlockIn; - invalidateMangledName(); - } - } - bool isInterfaceBlock() const - { - return type == EbtInterfaceBlock; + bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } + bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; } + bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); } + bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; } + size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; } + const TVector *getArraySizes() const { return mArraySizes; } + unsigned int getArraySizeProduct() const; + bool isUnsizedArray() const; + unsigned int getOutermostArraySize() const { + ASSERT(isArray()); + return mArraySizes->back(); } + void makeArray(unsigned int s); - bool isVector() const - { - return primarySize > 1 && secondarySize == 1; - } + // sizes contain new outermost array sizes. + void makeArrays(const TVector &sizes); + // Here, the array dimension value 0 corresponds to the innermost array. + void setArraySize(size_t arrayDimension, unsigned int s); + + // Will set unsized array sizes according to newArraySizes. In case there are more + // unsized arrays than there are sizes in newArraySizes, defaults to setting any + // remaining array sizes to 1. + void sizeUnsizedArrays(const TVector *newArraySizes); + + // Will size the outermost array according to arraySize. + void sizeOutermostUnsizedArray(unsigned int arraySize); + + // Note that the array element type might still be an array type in GLSL ES version >= 3.10. + void toArrayElementType(); + + TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; } + void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn); + bool isInterfaceBlock() const { return type == EbtInterfaceBlock; } + + bool isVector() const { return primarySize > 1 && secondarySize == 1; } bool isScalar() const { - return primarySize == 1 && secondarySize == 1 && !structure; - } - bool isScalarInt() const - { - return isScalar() && (type == EbtInt || type == EbtUInt); + return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray(); } + bool isScalarFloat() const { return isScalar() && type == EbtFloat; } + bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } - TStructure *getStruct() const - { - return structure; - } - void setStruct(TStructure *s) - { - if (structure != s) - { - structure = s; - invalidateMangledName(); - } - } + bool canBeConstructed() const; - const TString &getMangledName() const - { - if (mangled.empty()) - { - mangled = buildMangledName(); - mangled += ';'; - } + TStructure *getStruct() { return mStructure; } + const TStructure *getStruct() const { return mStructure; } + void setStruct(TStructure *s); - return mangled; - } + const char *getMangledName() const; + + bool sameNonArrayType(const TType &right) const; + + // Returns true if arrayType is an array made of this type. + bool isElementTypeOf(const TType &arrayType) const; - bool sameElementType(const TType &right) const - { - return type == right.type && - primarySize == right.primarySize && - secondarySize == right.secondarySize && - structure == right.structure; - } bool operator==(const TType &right) const { - return type == right.type && - primarySize == right.primarySize && - secondarySize == right.secondarySize && - array == right.array && (!array || arraySize == right.arraySize) && - structure == right.structure; + size_t numArraySizesL = getNumArraySizes(); + size_t numArraySizesR = right.getNumArraySizes(); + bool arraySizesEqual = numArraySizesL == numArraySizesR && + (numArraySizesL == 0 || *mArraySizes == *right.mArraySizes); + return type == right.type && primarySize == right.primarySize && + secondarySize == right.secondarySize && arraySizesEqual && + mStructure == right.mStructure; // don't check the qualifier, it's not ever what's being sought after } - bool operator!=(const TType &right) const - { - return !operator==(right); - } + bool operator!=(const TType &right) const { return !operator==(right); } bool operator<(const TType &right) const { if (type != right.type) @@ -473,28 +312,28 @@ class TType return primarySize < right.primarySize; if (secondarySize != right.secondarySize) return secondarySize < right.secondarySize; - if (array != right.array) - return array < right.array; - if (arraySize != right.arraySize) - return arraySize < right.arraySize; - if (structure != right.structure) - return structure < right.structure; + size_t numArraySizesL = getNumArraySizes(); + size_t numArraySizesR = right.getNumArraySizes(); + if (numArraySizesL != numArraySizesR) + return numArraySizesL < numArraySizesR; + for (size_t i = 0; i < numArraySizesL; ++i) + { + if ((*mArraySizes)[i] != (*right.mArraySizes)[i]) + return (*mArraySizes)[i] < (*right.mArraySizes)[i]; + } + if (mStructure != right.mStructure) + return mStructure < right.mStructure; return false; } - const char *getBasicString() const - { - return ::getBasicString(type); - } - const char *getPrecisionString() const - { - return ::getPrecisionString(precision); - } - const char *getQualifierString() const - { - return ::getQualifierString(qualifier); - } + const char *getBasicString() const { return sh::getBasicString(type); } + + const char *getPrecisionString() const { return sh::getPrecisionString(precision); } + const char *getQualifierString() const { return sh::getQualifierString(qualifier); } + + const char *getBuiltInTypeNameString() const; + TString getCompleteString() const; // If this type is a struct, returns the deepest struct nesting of @@ -509,176 +348,162 @@ class TType // For type "nesting2", this method would return 2 -- the number // of structures through which indirection must occur to reach the // deepest field (nesting2.field1.position). - int getDeepestStructNesting() const - { - return structure ? structure->deepestNesting() : 0; - } + int getDeepestStructNesting() const { return mStructure ? mStructure->deepestNesting() : 0; } + + bool isNamelessStruct() const { return mStructure && mStructure->name() == ""; } bool isStructureContainingArrays() const { - return structure ? structure->containsArrays() : false; + return mStructure ? mStructure->containsArrays() : false; } bool isStructureContainingType(TBasicType t) const { - return structure ? structure->containsType(t) : false; + return mStructure ? mStructure->containsType(t) : false; } bool isStructureContainingSamplers() const { - return structure ? structure->containsSamplers() : false; + return mStructure ? mStructure->containsSamplers() : false; } + bool isStructSpecifier() const { return mIsStructSpecifier; } + + void createSamplerSymbols(const TString &namePrefix, + const TString &apiNamePrefix, + TVector *outputSymbols, + TMap *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const; + // Initializes all lazily-initialized members. - void realize() - { - getMangledName(); - } + void realize(); private: - void invalidateMangledName() { mangled = ""; } - TString buildMangledName() const; - size_t getStructSize() const; + void invalidateMangledName(); + const char *buildMangledName() const; TBasicType type; TPrecision precision; TQualifier qualifier; bool invariant; + TMemoryQualifier memoryQualifier; TLayoutQualifier layoutQualifier; - unsigned char primarySize; // size of vector or cols matrix - unsigned char secondarySize; // rows of a matrix - bool array; - int arraySize; + unsigned char primarySize; // size of vector or cols matrix + unsigned char secondarySize; // rows of a matrix + + // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0 + // in this vector means an unsized array. + TVector *mArraySizes; - // 0 unless this is an interface block, or interface block member variable - TInterfaceBlock *interfaceBlock; + // This is set only in the following two cases: + // 1) Represents an interface block. + // 2) Represents the member variable of an unnamed interface block. + // It's nullptr also for members of named interface blocks. + TInterfaceBlock *mInterfaceBlock; // 0 unless this is a struct - TStructure *structure; + TStructure *mStructure; + bool mIsStructSpecifier; - mutable TString mangled; + mutable const char *mMangledName; }; -// -// This is a workaround for a problem with the yacc stack, It can't have -// types that it thinks have non-trivial constructors. It should -// just be used while recognizing the grammar, not anything else. Pointers -// could be used, but also trying to avoid lots of memory management overhead. -// -// Not as bad as it looks, there is no actual assumption that the fields -// match up or are name the same or anything like that. -// -struct TPublicType +// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the +// grammar +struct TTypeSpecifierNonArray { 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 - bool array; - int arraySize; - TType *userDef; + unsigned char primarySize; // size of vector or cols of matrix + unsigned char secondarySize; // rows of matrix + TStructure *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) + void initialize(TBasicType aType, const TSourceLoc &aLine) { - type = bt; - layoutQualifier = TLayoutQualifier::create(); - qualifier = q; - invariant = false; - precision = EbpUndefined; - primarySize = 1; - secondarySize = 1; - array = false; - arraySize = 0; - userDef = 0; - line = ln; + ASSERT(aType != EbtStruct); + type = aType; + primarySize = 1; + secondarySize = 1; + userDef = nullptr; + line = aLine; isStructSpecifier = false; } - void setAggregate(unsigned char size) + void initializeStruct(TStructure *aUserDef, bool aIsStructSpecifier, const TSourceLoc &aLine) { - primarySize = size; + type = EbtStruct; + primarySize = 1; + secondarySize = 1; + userDef = aUserDef; + line = aLine; + isStructSpecifier = aIsStructSpecifier; } - void setMatrix(unsigned char c, unsigned char r) - { - ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4); - primarySize = c; - secondarySize = r; - } + void setAggregate(unsigned char size) { primarySize = size; } - bool isUnsizedArray() const - { - return array && arraySize == 0; - } - void setArraySize(int s) - { - array = true; - arraySize = s; - } - void clearArrayness() + void setMatrix(unsigned char columns, unsigned char rows) { - array = false; - arraySize = 0; + ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4); + primarySize = columns; + secondarySize = rows; } - bool isStructureContainingArrays() const - { - if (!userDef) - { - return false; - } + bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } - return userDef->isStructureContainingArrays(); - } + bool isVector() const { return primarySize > 1 && secondarySize == 1; } +}; - bool isStructureContainingType(TBasicType t) const - { - if (!userDef) - { - return false; - } +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + TPublicType() = default; - return userDef->isStructureContainingType(t); - } + void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q); + void initializeBasicType(TBasicType basicType); - bool isMatrix() const - { - return primarySize > 1 && secondarySize > 1; - } + TBasicType getBasicType() const { return typeSpecifierNonArray.type; } + void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; } - bool isVector() const - { - return primarySize > 1 && secondarySize == 1; - } + unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; } + unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; } - int getCols() const - { - ASSERT(isMatrix()); - return primarySize; - } + TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; } + const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; } - int getRows() const - { - ASSERT(isMatrix()); - return secondarySize; - } + bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; } - int getNominalSize() const - { - return primarySize; - } + bool isStructureContainingArrays() const; + bool isStructureContainingType(TBasicType t) const; + void setArraySizes(TVector *sizes); + bool isArray() const; + void clearArrayness(); + bool isAggregate() const; - bool isAggregate() const - { - return array || isMatrix() || isVector(); - } + TTypeSpecifierNonArray typeSpecifierNonArray; + TLayoutQualifier layoutQualifier; + TMemoryQualifier memoryQualifier; + TQualifier qualifier; + bool invariant; + TPrecision precision; + + // Either nullptr or empty in case the type is not an array. The last element is the outermost + // array size. Note that due to bison restrictions, copies of the public type created by the + // copy constructor share the same arraySizes pointer. + const TVector *arraySizes; }; -#endif // COMPILER_TRANSLATOR_TYPES_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp deleted file mode 100644 index f79f9dd7fb..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// 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. -// -// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as 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/UnfoldShortCircuit.h" - -#include "compiler/translator/InfoSink.h" -#include "compiler/translator/OutputHLSL.h" -#include "compiler/translator/UtilsHLSL.h" - -namespace sh -{ -UnfoldShortCircuit::UnfoldShortCircuit(OutputHLSL *outputHLSL) : mOutputHLSL(outputHLSL) -{ - mTemporaryIndex = 0; -} - -void UnfoldShortCircuit::traverse(TIntermNode *node) -{ - int rewindIndex = mTemporaryIndex; - node->traverse(this); - mTemporaryIndex = rewindIndex; -} - -bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) -{ - TInfoSinkBase &out = mOutputHLSL->getInfoSink(); - - // If our right node doesn't have side effects, we know we don't need to unfold this - // expression: there will be no short-circuiting side effects to avoid - // (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: - // "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;". - { - int i = mTemporaryIndex; - - out << "bool s" << i << ";\n"; - - out << "{\n"; - - mTemporaryIndex = i + 1; - node->getLeft()->traverse(this); - out << "s" << i << " = "; - mTemporaryIndex = i + 1; - node->getLeft()->traverse(mOutputHLSL); - out << ";\n"; - out << "if (!s" << i << ")\n" - "{\n"; - mTemporaryIndex = i + 1; - node->getRight()->traverse(this); - out << " s" << i << " = "; - mTemporaryIndex = i + 1; - node->getRight()->traverse(mOutputHLSL); - out << ";\n" - "}\n"; - - out << "}\n"; - - mTemporaryIndex = i + 1; - } - return false; - case EOpLogicalAnd: - // "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;". - { - int i = mTemporaryIndex; - - out << "bool s" << i << ";\n"; - - out << "{\n"; - - mTemporaryIndex = i + 1; - node->getLeft()->traverse(this); - out << "s" << i << " = "; - mTemporaryIndex = i + 1; - node->getLeft()->traverse(mOutputHLSL); - out << ";\n"; - out << "if (s" << i << ")\n" - "{\n"; - mTemporaryIndex = i + 1; - node->getRight()->traverse(this); - out << " s" << i << " = "; - mTemporaryIndex = i + 1; - node->getRight()->traverse(mOutputHLSL); - out << ";\n" - "}\n"; - - out << "}\n"; - - mTemporaryIndex = i + 1; - } - return false; - default: - return true; - } -} - -bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) -{ - TInfoSinkBase &out = mOutputHLSL->getInfoSink(); - - // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" - if (node->usesTernaryOperator()) - { - int i = mTemporaryIndex; - - out << TypeString(node->getType()) << " s" << i << ";\n"; - - out << "{\n"; - - mTemporaryIndex = i + 1; - node->getCondition()->traverse(this); - out << "if ("; - mTemporaryIndex = i + 1; - node->getCondition()->traverse(mOutputHLSL); - out << ")\n" - "{\n"; - mTemporaryIndex = i + 1; - node->getTrueBlock()->traverse(this); - out << " s" << i << " = "; - mTemporaryIndex = i + 1; - node->getTrueBlock()->traverse(mOutputHLSL); - out << ";\n" - "}\n" - "else\n" - "{\n"; - mTemporaryIndex = i + 1; - node->getFalseBlock()->traverse(this); - out << " s" << i << " = "; - mTemporaryIndex = i + 1; - node->getFalseBlock()->traverse(mOutputHLSL); - out << ";\n" - "}\n"; - - out << "}\n"; - - mTemporaryIndex = i + 1; - } - - return false; -} - -bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node) -{ - int rewindIndex = mTemporaryIndex; - - if (node->getInit()) - { - node->getInit()->traverse(this); - } - - if (node->getCondition()) - { - node->getCondition()->traverse(this); - } - - if (node->getExpression()) - { - node->getExpression()->traverse(this); - } - - mTemporaryIndex = rewindIndex; - - return false; -} - -int UnfoldShortCircuit::getNextTemporaryIndex() -{ - return mTemporaryIndex++; -} -} diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h deleted file mode 100644 index eaceb0a0b3..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements -// - -#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ -#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ - -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/ParseContext.h" - -namespace sh -{ -class OutputHLSL; - -class UnfoldShortCircuit : public TIntermTraverser -{ - public: - UnfoldShortCircuit(OutputHLSL *outputHLSL); - - void traverse(TIntermNode *node); - bool visitBinary(Visit visit, TIntermBinary*); - bool visitSelection(Visit visit, TIntermSelection *node); - bool visitLoop(Visit visit, TIntermLoop *node); - - int getNextTemporaryIndex(); - - protected: - OutputHLSL *const mOutputHLSL; - - int mTemporaryIndex; -}; -} - -#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp index e50bf202ef..4e4653bbe5 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp @@ -6,52 +6,54 @@ #include "compiler/translator/UnfoldShortCircuitAST.h" +namespace sh +{ + namespace { // "x || y" is equivalent to "x ? true : y". -TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y) +TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y) { - const TType boolType(EbtBool, EbpUndefined); TConstantUnion *u = new TConstantUnion; u->setBConst(true); - TIntermConstantUnion *trueNode = new TIntermConstantUnion( - u, TType(EbtBool, EbpUndefined, EvqConst, 1)); - return new TIntermSelection(x, trueNode, y, boolType); + TIntermConstantUnion *trueNode = + new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1)); + return new TIntermTernary(x, trueNode, y); } // "x && y" is equivalent to "x ? y : false". -TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y) +TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y) { - const TType boolType(EbtBool, EbpUndefined); TConstantUnion *u = new TConstantUnion; u->setBConst(false); - TIntermConstantUnion *falseNode = new TIntermConstantUnion( - u, TType(EbtBool, EbpUndefined, EvqConst, 1)); - return new TIntermSelection(x, y, falseNode, boolType); + TIntermConstantUnion *falseNode = + new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1)); + return new TIntermTernary(x, y, falseNode); } } // namespace anonymous bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) { - TIntermSelection *replacement = NULL; + TIntermTernary *replacement = nullptr; switch (node->getOp()) { - case EOpLogicalOr: - replacement = UnfoldOR(node->getLeft(), node->getRight()); - break; - case EOpLogicalAnd: - replacement = UnfoldAND(node->getLeft(), node->getRight()); - break; - default: - break; + case EOpLogicalOr: + replacement = UnfoldOR(node->getLeft(), node->getRight()); + break; + case EOpLogicalAnd: + replacement = UnfoldAND(node->getLeft(), node->getRight()); + break; + default: + break; } if (replacement) { - mReplacements.push_back( - NodeUpdateEntry(getParentNode(), node, replacement, false)); + queueReplacement(replacement, OriginalNode::IS_DROPPED); } return true; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h index b92a4e9152..7f377e6f15 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h @@ -11,7 +11,10 @@ #define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ #include "common/angleutils.h" -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ // This traverser identifies all the short circuit binary nodes that need to // be replaced, and creates the corresponding replacement nodes. However, @@ -20,12 +23,11 @@ class UnfoldShortCircuitAST : public TIntermTraverser { public: - UnfoldShortCircuitAST() - : TIntermTraverser(true, false, false) - { - } + UnfoldShortCircuitAST() : TIntermTraverser(true, false, false) {} bool visitBinary(Visit visit, TIntermBinary *) override; }; +} // namespace sh + #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 index be23b524d7..774f1fc704 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp @@ -3,14 +3,19 @@ // 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. +// 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" +#include "compiler/translator/IntermNodePatternMatcher.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ namespace { @@ -19,44 +24,26 @@ namespace class UnfoldShortCircuitTraverser : public TIntermTraverser { public: - UnfoldShortCircuitTraverser(); + UnfoldShortCircuitTraverser(TSymbolTable *symbolTable); 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; + bool visitTernary(Visit visit, TIntermTernary *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; + IntermNodePatternMatcher mPatternToUnfoldMatcher; }; -UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser() - : TIntermTraverser(true, false, true), +UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFoundShortCircuit(false), - mParentLoop(nullptr), - mLoopParent(nullptr), - mInLoopCondition(false), - mInLoopExpression(false) + mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression) { } @@ -64,19 +51,23 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) { if (mFoundShortCircuit) return false; + + if (visit != PreVisit) + return true; + + if (!mPatternToUnfoldMatcher.match(node, getParentNode())) + return true; + // 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; - } + ASSERT(node->getRight()->hasSideEffects()); + + mFoundShortCircuit = true; switch (node->getOp()) { - case EOpLogicalOr: - mFoundShortCircuit = true; - if (!copyLoopConditionOrExpression(getParentNode(), node)) + case EOpLogicalOr: { // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; // else s = y;", @@ -88,24 +79,21 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) ASSERT(node->getLeft()->getType() == boolType); insertions.push_back(createTempInitDeclaration(node->getLeft())); - TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); + TIntermBlock *assignRightBlock = new TIntermBlock(); 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); + TIntermUnary *notTempSymbol = + new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType)); + TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr); insertions.push_back(ifNode); insertStatementsInParentBlock(insertions); - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false); - mReplacements.push_back(replaceVariable); + queueReplacement(createTempSymbol(boolType), OriginalNode::IS_DROPPED); + return false; } - return false; - case EOpLogicalAnd: - mFoundShortCircuit = true; - if (!copyLoopConditionOrExpression(getParentNode(), node)) + case EOpLogicalAnd: { // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; // else s = false;", @@ -116,246 +104,75 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) ASSERT(node->getLeft()->getType() == boolType); insertions.push_back(createTempInitDeclaration(node->getLeft())); - TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); + TIntermBlock *assignRightBlock = new TIntermBlock(); ASSERT(node->getRight()->getType() == boolType); assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); - TIntermSelection *ifNode = new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr); + TIntermIfElse *ifNode = + new TIntermIfElse(createTempSymbol(boolType), assignRightBlock, nullptr); insertions.push_back(ifNode); insertStatementsInParentBlock(insertions); - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false); - mReplacements.push_back(replaceVariable); + queueReplacement(createTempSymbol(boolType), OriginalNode::IS_DROPPED); + return false; } - return false; - default: - return true; + default: + UNREACHABLE(); + return true; } } -bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *node) +bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *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 (visit != PreVisit) + return true; - if (node->getOp() == EOpComma) - { - ASSERT(visit != PreVisit || !mFoundShortCircuit); + if (!mPatternToUnfoldMatcher.match(node)) + return true; - 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; -} + mFoundShortCircuit = 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); + // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" + TIntermSequence insertions; - if (node->getInit()) - { - node->getInit()->traverse(this); - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } + TIntermDeclaration *tempDeclaration = createTempDeclaration(node->getType()); + insertions.push_back(tempDeclaration); - if (node->getCondition()) - { - mInLoopCondition = true; - node->getCondition()->traverse(this); - mInLoopCondition = false; - - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } + TIntermBlock *trueBlock = new TIntermBlock(); + TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression()); + trueBlock->getSequence()->push_back(trueAssignment); - if (node->getExpression()) - { - mInLoopExpression = true; - node->getExpression()->traverse(this); - mInLoopExpression = false; - - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } + TIntermBlock *falseBlock = new TIntermBlock(); + TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression()); + falseBlock->getSequence()->push_back(falseAssignment); - if (node->getBody()) - node->getBody()->traverse(this); + TIntermIfElse *ifNode = + new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock); + insertions.push_back(ifNode); - decrementDepth(); - } - return false; -} + insertStatementsInParentBlock(insertions); -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; - } + TIntermSymbol *ternaryResult = createTempSymbol(node->getType()); + queueReplacement(ternaryResult, OriginalNode::IS_DROPPED); - 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(); + nextTemporaryId(); } -} // namespace +} // namespace -void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex) +void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable) { - UnfoldShortCircuitTraverser traverser; - ASSERT(temporaryIndex != nullptr); - traverser.useTemporaryIndex(temporaryIndex); + UnfoldShortCircuitTraverser traverser(symbolTable); // Unfold one operator at a time, and reset the traverser between iterations. do { @@ -363,6 +180,7 @@ void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex) root->traverse(&traverser); if (traverser.foundShortCircuit()) traverser.updateTree(); - } - while (traverser.foundShortCircuit()); + } while (traverser.foundShortCircuit()); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h index 0fe37b7140..37dd83a8cf 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitToIf.h @@ -3,7 +3,8 @@ // 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. +// 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. // @@ -11,8 +12,14 @@ #ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ #define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ +namespace sh +{ + class TIntermNode; +class TSymbolTable; + +void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable); -void UnfoldShortCircuitToIf(TIntermNode *root, unsigned int *temporaryIndex); +} // namespace sh -#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ +#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 20961c44c1..9f18509438 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // // UniformHLSL.cpp: -// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// Methods for GLSL to HLSL translation for uniforms and uniform blocks. // #include "compiler/translator/UniformHLSL.h" @@ -18,6 +18,9 @@ namespace sh { +namespace +{ + static const char *UniformRegisterPrefix(const TType &type) { if (IsSampler(type.getBasicType())) @@ -32,22 +35,23 @@ static const char *UniformRegisterPrefix(const TType &type) static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) { - const TType &fieldType = *field.type(); + const TType &fieldType = *field.type(); const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; ASSERT(matrixPacking != EmpUnspecified); - TStructure *structure = fieldType.getStruct(); + const TStructure *structure = fieldType.getStruct(); if (fieldType.isMatrix()) { // Use HLSL row-major packing for GLSL column-major matrices - const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); + const TString &matrixPackString = + (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); return matrixPackString + " " + TypeString(fieldType); } else if (structure) { // Use HLSL row-major packing for GLSL column-major matrices return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, - blockStorage == EbsStd140); + blockStorage == EbsStd140); } else { @@ -60,23 +64,58 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) return DecoratePrivate(interfaceBlock.name()) + "_type"; } -UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms) +void OutputSamplerIndexArrayInitializer(TInfoSinkBase &out, + const TType &type, + unsigned int startIndex) +{ + out << "{"; + TType elementType(type); + elementType.toArrayElementType(); + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) + { + if (i > 0u) + { + out << ", "; + } + if (elementType.isArray()) + { + OutputSamplerIndexArrayInitializer(out, elementType, + startIndex + i * elementType.getArraySizeProduct()); + } + else + { + out << (startIndex + i); + } + } + out << "}"; +} + +} // anonymous namespace + +UniformHLSL::UniformHLSL(sh::GLenum shaderType, + StructureHLSL *structureHLSL, + ShShaderOutput outputType, + const std::vector &uniforms) : mUniformRegister(0), - mInterfaceBlockRegister(0), - mSamplerRegister(0), + mUniformBlockRegister(0), + mTextureRegister(0), + mRWTextureRegister(0), + mSamplerCount(0), + mShaderType(shaderType), mStructureHLSL(structureHLSL), mOutputType(outputType), mUniforms(uniforms) -{} +{ +} void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) { mUniformRegister = registerCount; } -void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount) +void UniformHLSL::reserveUniformBlockRegisters(unsigned int registerCount) { - mInterfaceBlockRegister = registerCount; + mUniformBlockRegister = registerCount; } const Uniform *UniformHLSL::findUniformByName(const TString &name) const @@ -89,46 +128,78 @@ const Uniform *UniformHLSL::findUniformByName(const TString &name) const } } - UNREACHABLE(); - return NULL; + return nullptr; } -unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, - const TString &name, - unsigned int *registerCount) +unsigned int UniformHLSL::assignUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount) { - unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); - + unsigned int registerIndex; const Uniform *uniform = findUniformByName(name); ASSERT(uniform); + if (IsSampler(type.getBasicType()) || + (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) + { + registerIndex = mTextureRegister; + } + else if (IsImage(type.getBasicType())) + { + registerIndex = mRWTextureRegister; + } + else + { + registerIndex = mUniformRegister; + } + mUniformRegisterMap[uniform->name] = registerIndex; - ASSERT(registerCount); - *registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); + unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); - if (gl::IsSamplerType(uniform->type)) + if (IsSampler(type.getBasicType()) || + (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) { - mSamplerRegister += *registerCount; + mTextureRegister += registerCount; + } + else if (IsImage(type.getBasicType())) + { + mRWTextureRegister += registerCount; } else { - mUniformRegister += *registerCount; + mUniformRegister += registerCount; + } + if (outRegisterCount) + { + *outRegisterCount = registerCount; } - return registerIndex; } -unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) +unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount) { - unsigned int registerCount; - return declareUniformAndAssignRegister(type, name, ®isterCount); + // Sampler that is a field of a uniform structure. + ASSERT(IsSampler(type.getBasicType())); + unsigned int registerIndex = mTextureRegister; + mUniformRegisterMap[std::string(name.c_str())] = registerIndex; + unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u; + mTextureRegister += registerCount; + if (outRegisterCount) + { + *outRegisterCount = registerCount; + } + return registerIndex; } -void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, - const HLSLTextureSamplerGroup textureGroup, - const TVector &group, - unsigned int *groupTextureRegisterIndex) +void UniformHLSL::outputHLSLSamplerUniformGroup( + TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector &group, + const TMap &samplerInStructSymbolsToAPINames, + unsigned int *groupTextureRegisterIndex) { if (group.empty()) { @@ -140,24 +211,33 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, const TType &type = uniform->getType(); const TString &name = uniform->getSymbol(); unsigned int registerCount; - unsigned int samplerArrayIndex = - declareUniformAndAssignRegister(type, name, ®isterCount); + + // The uniform might be just a regular sampler or one extracted from a struct. + unsigned int samplerArrayIndex = 0u; + const Uniform *uniformByName = findUniformByName(name); + if (uniformByName) + { + samplerArrayIndex = assignUniformRegister(type, name, ®isterCount); + } + else + { + ASSERT(samplerInStructSymbolsToAPINames.find(uniform) != + samplerInStructSymbolsToAPINames.end()); + samplerArrayIndex = assignSamplerInStructUniformRegister( + type, samplerInStructSymbolsToAPINames.at(uniform), ®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"; + out << "static const uint " << DecorateVariableIfNeeded(uniform->getName()) + << ArrayString(type) << " = "; + OutputSamplerIndexArrayInitializer(out, type, samplerArrayIndex); + out << ";\n"; } else { - out << "static const uint " << DecorateIfNeeded(uniform->getName()) << " = " + out << "static const uint " << DecorateVariableIfNeeded(uniform->getName()) << " = " << samplerArrayIndex << ";\n"; } } @@ -179,9 +259,88 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, *groupTextureRegisterIndex += groupRegisterCount; } +void UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex) +{ + out << "uniform " << SamplerString(type.getBasicType()) << " sampler_" + << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(s" + << str(registerIndex) << ");\n"; + out << "uniform " << TextureString(type.getBasicType()) << " texture_" + << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(t" + << str(registerIndex) << ");\n"; +} + +void UniformHLSL::outputHLSL4_1_FL11Texture(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex) +{ + // TODO(xinghua.cao@intel.com): if image2D variable is bound on one layer of Texture3D or + // Texture2DArray. Translate this variable to HLSL Texture3D object or HLSL Texture2DArray + // object, or create a temporary Texture2D to save content of the layer and bind the + // temporary Texture2D to image2D variable. + out << "uniform " + << TextureString(type.getBasicType(), type.getLayoutQualifier().imageInternalFormat) << " " + << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(t" + << str(registerIndex) << ");\n"; + return; +} + +void UniformHLSL::outputHLSL4_1_FL11RWTexture(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex) +{ + // TODO(xinghua.cao@intel.com): if image2D variable is bound on one layer of Texture3D or + // Texture2DArray. Translate this variable to HLSL RWTexture3D object or HLSL RWTexture2DArray + // object, or create a temporary Texture2D to save content of the layer and bind the + // temporary Texture2D to image2D variable. + if (mShaderType == GL_COMPUTE_SHADER) + { + out << "uniform " + << RWTextureString(type.getBasicType(), type.getLayoutQualifier().imageInternalFormat) + << " " << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(u" + << str(registerIndex) << ");\n"; + } + else + { + // TODO(xinghua.cao@intel.com): Support images in vertex shader and fragment shader, + // which are needed to sync binding value when linking program. + } + return; +} + +void UniformHLSL::outputUniform(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex) +{ + 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 + // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers + // are permitted. + const TString &typeName = ((structure && !structure->name().empty()) + ? QualifiedStructNameString(*structure, false, false) + : TypeString(type)); + + const TString ®isterString = + TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; + + out << "uniform " << typeName << " "; + + out << DecorateVariableIfNeeded(name); + + out << ArrayString(type) << " : " << registerString << ";\n"; +} + void UniformHLSL::uniformsHeader(TInfoSinkBase &out, ShShaderOutput outputType, - const ReferencedSymbols &referencedUniforms) + const ReferencedSymbols &referencedUniforms, + TSymbolTable *symbolTable) { if (!referencedUniforms.empty()) { @@ -190,45 +349,69 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, // 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); + TVector> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1); + TMap samplerInStructSymbolsToAPINames; + TVector imageUniformsHLSL41Output; for (auto &uniformIt : referencedUniforms) { // Output regular uniforms. Group sampler uniforms by type. const TIntermSymbol &uniform = *uniformIt.second; - const TType &type = uniform.getType(); - const TString &name = uniform.getSymbol(); + const TType &type = uniform.getType(); + const TName &name = uniform.getName(); if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType())) { - HLSLTextureSamplerGroup group = TextureGroup(type.getBasicType()); + HLSLTextureGroup 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"; + unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr); + outputHLSL4_0_FL9_3Sampler(out, type, name, registerIndex); + } + else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType())) + { + imageUniformsHLSL41Output.push_back(&uniform); } 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 - // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers are - // permitted. - const TString &typeName = ((structure && !structure->name().empty()) ? - QualifiedStructNameString(*structure, false, false) : TypeString(type)); - - const TString ®isterString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; - - out << "uniform " << typeName << " " << DecorateUniform(name, type) << ArrayString(type) - << " : " << registerString << ";\n"; + if (type.isStructureContainingSamplers()) + { + TVector samplerSymbols; + TMap symbolsToAPINames; + type.createSamplerSymbols("angle_" + name.getString(), name.getString(), + &samplerSymbols, &symbolsToAPINames, symbolTable); + for (TIntermSymbol *sampler : samplerSymbols) + { + const TType &samplerType = sampler->getType(); + + // Will use angle_ prefix instead of regular prefix. + sampler->setInternal(true); + const TName &samplerName = sampler->getName(); + + if (outputType == SH_HLSL_4_1_OUTPUT) + { + HLSLTextureGroup group = TextureGroup(samplerType.getBasicType()); + groupedSamplerUniforms[group].push_back(sampler); + samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler]; + } + else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + unsigned int registerIndex = assignSamplerInStructUniformRegister( + samplerType, symbolsToAPINames[sampler], nullptr); + outputHLSL4_0_FL9_3Sampler(out, samplerType, samplerName, registerIndex); + } + else + { + ASSERT(outputType == SH_HLSL_3_0_OUTPUT); + unsigned int registerIndex = assignSamplerInStructUniformRegister( + samplerType, symbolsToAPINames[sampler], nullptr); + outputUniform(out, samplerType, samplerName, registerIndex); + } + } + } + unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr); + outputUniform(out, type, name, registerIndex); } } @@ -239,70 +422,114 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, 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); + outputHLSLSamplerUniformGroup( + out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId], + samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex); + } + mSamplerCount = groupTextureRegisterIndex; + + for (const TIntermSymbol *image : imageUniformsHLSL41Output) + { + const TType &type = image->getType(); + const TName &name = image->getName(); + unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr); + if (type.getMemoryQualifier().readonly) + { + outputHLSL4_1_FL11Texture(out, type, name, registerIndex); + } + else + { + outputHLSL4_1_FL11RWTexture(out, type, name, registerIndex); + } } } } -TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks) +void UniformHLSL::samplerMetadataUniforms(TInfoSinkBase &out, const char *reg) +{ + // If mSamplerCount is 0 the shader doesn't use any textures for samplers. + if (mSamplerCount > 0) + { + out << " struct SamplerMetadata\n" + " {\n" + " int baseLevel;\n" + " int internalFormatBits;\n" + " int wrapModes;\n" + " int padding;\n" + " };\n" + " SamplerMetadata samplerMetadata[" + << mSamplerCount << "] : packoffset(" << reg << ");\n"; + } +} + +TString UniformHLSL::uniformBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks) { TString interfaceBlocks; for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin(); interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++) { - const TType &nodeType = interfaceBlockIt->second->getType(); + const TType &nodeType = interfaceBlockIt->second->getType(); const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock(); - unsigned int arraySize = static_cast(interfaceBlock.arraySize()); - unsigned int activeRegister = mInterfaceBlockRegister; + // nodeType.isInterfaceBlock() == false means the node is a field of a uniform block which + // doesn't have instance name, so this block cannot be an array. + unsigned int interfaceBlockArraySize = 0u; + if (nodeType.isInterfaceBlock() && nodeType.isArray()) + { + interfaceBlockArraySize = nodeType.getOutermostArraySize(); + } + unsigned int activeRegister = mUniformBlockRegister; - mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister; - mInterfaceBlockRegister += std::max(1u, arraySize); + mUniformBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister; + mUniformBlockRegister += std::max(1u, interfaceBlockArraySize); // FIXME: interface block field names if (interfaceBlock.hasInstanceName()) { - interfaceBlocks += interfaceBlockStructString(interfaceBlock); + interfaceBlocks += uniformBlockStructString(interfaceBlock); } - if (arraySize > 0) + if (interfaceBlockArraySize > 0) { - for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + for (unsigned int arrayIndex = 0; arrayIndex < interfaceBlockArraySize; arrayIndex++) { - interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex); + interfaceBlocks += + uniformBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex); } } else { - interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX); + interfaceBlocks += uniformBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX); } } - return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks)); + return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks)); } -TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex) +TString UniformHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, + unsigned int registerIndex, + unsigned int arrayIndex) { - const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : ""); + const TString &arrayIndexString = + (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : ""); const TString &blockName = interfaceBlock.name() + arrayIndexString; TString hlsl; - hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n" + hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + + ")\n" "{\n"; if (interfaceBlock.hasInstanceName()) { hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + - interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; + uniformBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; } else { const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); - hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage); + hlsl += uniformBlockMembersString(interfaceBlock, blockStorage); } hlsl += "};\n\n"; @@ -310,13 +537,14 @@ TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, return hlsl; } -TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex) +TString UniformHLSL::uniformBlockInstanceString(const TInterfaceBlock &interfaceBlock, + unsigned int arrayIndex) { if (!interfaceBlock.hasInstanceName()) { return ""; } - else if (interfaceBlock.isArray()) + else if (arrayIndex != GL_INVALID_INDEX) { return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex); } @@ -326,7 +554,8 @@ TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfa } } -TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage) +TString UniformHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, + TLayoutBlockStorage blockStorage) { TString hlsl; @@ -334,7 +563,7 @@ TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfac for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++) { - const TField &field = *interfaceBlock.fields()[typeIndex]; + const TField &field = *interfaceBlock.fields()[typeIndex]; const TType &fieldType = *field.type(); if (blockStorage == EbsStd140) @@ -343,13 +572,15 @@ TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfac hlsl += padHelper.prePaddingString(fieldType); } - hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + - " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n"; + hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + " " + + Decorate(field.name()) + ArrayString(fieldType) + ";\n"; - // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff + // must pad out after matrices and arrays, where HLSL usually allows itself room to pack + // stuff if (blockStorage == EbsStd140) { - const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); + const bool useHLSLRowMajorPacking = + (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking); } } @@ -357,14 +588,13 @@ TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfac return hlsl; } -TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock) +TString UniformHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock) { const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); - return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n" + return "struct " + InterfaceBlockStructName(interfaceBlock) + + "\n" "{\n" + - interfaceBlockMembersString(interfaceBlock, blockStorage) + - "};\n\n"; + uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n"; } - } diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h index 0f51f349bb..8784e50533 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // // UniformHLSL.h: -// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// Methods for GLSL to HLSL translation for uniforms and uniform blocks. // #ifndef COMPILER_TRANSLATOR_UNIFORMHLSL_H_ @@ -16,29 +16,35 @@ namespace sh { class StructureHLSL; +class TSymbolTable; class UniformHLSL : angle::NonCopyable { public: - UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms); + UniformHLSL(sh::GLenum shaderType, + StructureHLSL *structureHLSL, + ShShaderOutput outputType, + const std::vector &uniforms); void reserveUniformRegisters(unsigned int registerCount); - void reserveInterfaceBlockRegisters(unsigned int registerCount); - void outputHLSLSamplerUniformGroup(TInfoSinkBase &out, - const HLSLTextureSamplerGroup textureGroup, - const TVector &group, - unsigned int *groupTextureRegisterIndex); + void reserveUniformBlockRegisters(unsigned int registerCount); void uniformsHeader(TInfoSinkBase &out, ShShaderOutput outputType, - const ReferencedSymbols &referencedUniforms); - TString interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks); + const ReferencedSymbols &referencedUniforms, + TSymbolTable *symbolTable); + + // Must be called after uniformsHeader + void samplerMetadataUniforms(TInfoSinkBase &out, const char *reg); + + TString uniformBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks); // Used for direct index references - static TString interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex); + static TString uniformBlockInstanceString(const TInterfaceBlock &interfaceBlock, + unsigned int arrayIndex); - const std::map &getInterfaceBlockRegisterMap() const + const std::map &getUniformBlockRegisterMap() const { - return mInterfaceBlockRegisterMap; + return mUniformBlockRegisterMap; } const std::map &getUniformRegisterMap() const { @@ -46,28 +52,59 @@ class UniformHLSL : angle::NonCopyable } private: - TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex); - TString interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage); - TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock); + TString uniformBlockString(const TInterfaceBlock &interfaceBlock, + unsigned int registerIndex, + unsigned int arrayIndex); + TString uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, + TLayoutBlockStorage blockStorage); + TString uniformBlockStructString(const TInterfaceBlock &interfaceBlock); const Uniform *findUniformByName(const TString &name) const; + void outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex); + void outputHLSL4_1_FL11Texture(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex); + void outputHLSL4_1_FL11RWTexture(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex); + void outputUniform(TInfoSinkBase &out, + const TType &type, + const TName &name, + const unsigned int registerIndex); + // 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 assignUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount); + unsigned int assignSamplerInStructUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount); + + void outputHLSLSamplerUniformGroup( + TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector &group, + const TMap &samplerInStructSymbolsToAPINames, + unsigned int *groupTextureRegisterIndex); unsigned int mUniformRegister; - unsigned int mInterfaceBlockRegister; - unsigned int mSamplerRegister; + unsigned int mUniformBlockRegister; + unsigned int mTextureRegister; + unsigned int mRWTextureRegister; + unsigned int mSamplerCount; + sh::GLenum mShaderType; StructureHLSL *mStructureHLSL; ShShaderOutput mOutputType; const std::vector &mUniforms; - std::map mInterfaceBlockRegisterMap; + std::map mUniformBlockRegisterMap; std::map mUniformRegisterMap; }; - } -#endif // COMPILER_TRANSLATOR_UNIFORMHLSL_H_ +#endif // COMPILER_TRANSLATOR_UNIFORMHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.cpp b/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.cpp new file mode 100644 index 0000000000..40bd42afad --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.cpp @@ -0,0 +1,105 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// UseInterfaceBlockFields.cpp: insert statements to reference all members in InterfaceBlock list at +// the beginning of main. This is to work around a Mac driver that treats unused standard/shared +// uniform blocks as inactive. + +#include "compiler/translator/UseInterfaceBlockFields.h" + +#include "compiler/translator/FindMain.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNode_util.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void AddNodeUseStatements(TIntermTyped *node, TIntermSequence *sequence) +{ + if (node->isArray()) + { + for (unsigned int i = 0u; i < node->getOutermostArraySize(); ++i) + { + TIntermBinary *element = + new TIntermBinary(EOpIndexDirect, node->deepCopy(), CreateIndexNode(i)); + AddNodeUseStatements(element, sequence); + } + } + else + { + sequence->insert(sequence->begin(), node); + } +} + +void AddFieldUseStatements(const ShaderVariable &var, + TIntermSequence *sequence, + const TSymbolTable &symbolTable) +{ + TString name = TString(var.name.c_str()); + ASSERT(name.find_last_of('[') == TString::npos); + TIntermSymbol *symbol = ReferenceGlobalVariable(name, symbolTable); + AddNodeUseStatements(symbol, sequence); +} + +void InsertUseCode(const InterfaceBlock &block, TIntermTyped *blockNode, TIntermSequence *sequence) +{ + for (unsigned int i = 0; i < block.fields.size(); ++i) + { + TIntermBinary *element = new TIntermBinary(EOpIndexDirectInterfaceBlock, + blockNode->deepCopy(), CreateIndexNode(i)); + sequence->insert(sequence->begin(), element); + } +} + +void InsertUseCode(TIntermSequence *sequence, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + for (const auto &block : blocks) + { + if (block.instanceName.empty()) + { + for (const auto &var : block.fields) + { + AddFieldUseStatements(var, sequence, symbolTable); + } + } + else if (block.arraySize > 0u) + { + TString name(block.instanceName.c_str()); + TIntermSymbol *arraySymbol = ReferenceGlobalVariable(name, symbolTable); + for (unsigned int i = 0u; i < block.arraySize; ++i) + { + TIntermBinary *elementSymbol = + new TIntermBinary(EOpIndexDirect, arraySymbol->deepCopy(), CreateIndexNode(i)); + InsertUseCode(block, elementSymbol, sequence); + } + } + else + { + TString name(block.instanceName.c_str()); + TIntermSymbol *blockSymbol = ReferenceGlobalVariable(name, symbolTable); + InsertUseCode(block, blockSymbol, sequence); + } + } +} + +} // namespace anonymous + +void UseInterfaceBlockFields(TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + TIntermBlock *mainBody = FindMainBody(root); + InsertUseCode(mainBody->getSequence(), blocks, symbolTable); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.h b/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.h new file mode 100644 index 0000000000..3e2a4815d4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/UseInterfaceBlockFields.h @@ -0,0 +1,30 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// UseInterfaceBlockFields.h: insert statements to reference all members in InterfaceBlock list at +// the beginning of main. This is to work around a Mac driver that treats unused standard/shared +// uniform blocks as inactive. + +#ifndef COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_ +#define COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_ + +#include + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +using InterfaceBlockList = std::vector; + +void UseInterfaceBlockFields(TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_USEINTERFACEBLOCKFIELDS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp index 404ccee75d..8a77f0049a 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp @@ -27,7 +27,7 @@ TString SamplerString(const TBasicType type) } } -TString SamplerString(HLSLTextureSamplerGroup type) +TString SamplerString(HLSLTextureGroup type) { if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END) { @@ -39,7 +39,8 @@ TString SamplerString(HLSLTextureSamplerGroup type) } } -HLSLTextureSamplerGroup TextureGroup(const TBasicType type) +HLSLTextureGroup TextureGroup(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) + { switch (type) { @@ -53,6 +54,8 @@ HLSLTextureSamplerGroup TextureGroup(const TBasicType type) return HLSL_TEXTURE_2D_ARRAY; case EbtSampler3D: return HLSL_TEXTURE_3D; + case EbtSampler2DMS: + return HLSL_TEXTURE_2D_MS; case EbtISampler2D: return HLSL_TEXTURE_2D_INT4; case EbtISampler3D: @@ -61,6 +64,8 @@ HLSLTextureSamplerGroup TextureGroup(const TBasicType type) return HLSL_TEXTURE_2D_ARRAY_INT4; case EbtISampler2DArray: return HLSL_TEXTURE_2D_ARRAY_INT4; + case EbtISampler2DMS: + return HLSL_TEXTURE_2D_MS_INT4; case EbtUSampler2D: return HLSL_TEXTURE_2D_UINT4; case EbtUSampler3D: @@ -69,42 +74,196 @@ HLSLTextureSamplerGroup TextureGroup(const TBasicType type) return HLSL_TEXTURE_2D_ARRAY_UINT4; case EbtUSampler2DArray: return HLSL_TEXTURE_2D_ARRAY_UINT4; + case EbtUSampler2DMS: + return HLSL_TEXTURE_2D_MS_UINT4; case EbtSampler2DShadow: return HLSL_TEXTURE_2D_COMPARISON; case EbtSamplerCubeShadow: return HLSL_TEXTURE_CUBE_COMPARISON; case EbtSampler2DArrayShadow: return HLSL_TEXTURE_2D_ARRAY_COMPARISON; + case EbtImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_2D; + case EiifRGBA8: + return HLSL_TEXTURE_2D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_2D_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_2D_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage2D: + { + switch (imageInternalFormat) + { + + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_2D_UINT4; + default: + UNREACHABLE(); + } + } + case EbtImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_3D; + case EiifRGBA8: + return HLSL_TEXTURE_3D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_3D_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_3D_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_3D_UINT4; + default: + UNREACHABLE(); + } + } + case EbtImage2DArray: + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_2D_ARRAY; + case EiifRGBA8: + return HLSL_TEXTURE_2D_ARRAY_UNORN; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_2D_ARRAY_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage2DArray: + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_2D_ARRAY_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage2DArray: + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_2D_ARRAY_UINT4; + default: + UNREACHABLE(); + } + } default: UNREACHABLE(); } return HLSL_TEXTURE_UNKNOWN; } -TString TextureString(const HLSLTextureSamplerGroup type) +TString TextureString(const HLSLTextureGroup textureGroup) { - switch (type) + switch (textureGroup) { case HLSL_TEXTURE_2D: - return "Texture2D"; + return "Texture2D"; case HLSL_TEXTURE_CUBE: - return "TextureCube"; + return "TextureCube"; case HLSL_TEXTURE_2D_ARRAY: - return "Texture2DArray"; + return "Texture2DArray"; case HLSL_TEXTURE_3D: - return "Texture3D"; + return "Texture3D"; + case HLSL_TEXTURE_2D_UNORM: + return "Texture2D"; + case HLSL_TEXTURE_CUBE_UNORM: + return "TextureCube"; + case HLSL_TEXTURE_2D_ARRAY_UNORN: + return "Texture2DArray"; + case HLSL_TEXTURE_3D_UNORM: + return "Texture3D"; + case HLSL_TEXTURE_2D_SNORM: + return "Texture2D"; + case HLSL_TEXTURE_CUBE_SNORM: + return "TextureCube"; + case HLSL_TEXTURE_2D_ARRAY_SNORM: + return "Texture2DArray"; + case HLSL_TEXTURE_3D_SNORM: + return "Texture3D"; + case HLSL_TEXTURE_2D_MS: + return "Texture2DMS"; 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_MS_INT4: + return "Texture2DMS"; 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_MS_UINT4: + return "Texture2DMS"; case HLSL_TEXTURE_2D_COMPARISON: return "Texture2D"; case HLSL_TEXTURE_CUBE_COMPARISON: @@ -115,15 +274,15 @@ TString TextureString(const HLSLTextureSamplerGroup type) UNREACHABLE(); } - return ""; + return ""; } -TString TextureString(const TBasicType type) +TString TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) { - return TextureString(TextureGroup(type)); + return TextureString(TextureGroup(type, imageInternalFormat)); } -TString TextureGroupSuffix(const HLSLTextureSamplerGroup type) +TString TextureGroupSuffix(const HLSLTextureGroup type) { switch (type) { @@ -135,18 +294,40 @@ TString TextureGroupSuffix(const HLSLTextureSamplerGroup type) return "2DArray"; case HLSL_TEXTURE_3D: return "3D"; + case HLSL_TEXTURE_2D_UNORM: + return "2D_unorm_float4_"; + case HLSL_TEXTURE_CUBE_UNORM: + return "Cube_unorm_float4_"; + case HLSL_TEXTURE_2D_ARRAY_UNORN: + return "2DArray_unorm_float4_"; + case HLSL_TEXTURE_3D_UNORM: + return "3D_unorm_float4_"; + case HLSL_TEXTURE_2D_SNORM: + return "2D_snorm_float4_"; + case HLSL_TEXTURE_CUBE_SNORM: + return "Cube_snorm_float4_"; + case HLSL_TEXTURE_2D_ARRAY_SNORM: + return "2DArray_snorm_float4_"; + case HLSL_TEXTURE_3D_SNORM: + return "3D_snorm_float4_"; + case HLSL_TEXTURE_2D_MS: + return "2DMS"; 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_MS_INT4: + return "2DMS_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_MS_UINT4: + return "2DMS_uint4_"; case HLSL_TEXTURE_2D_COMPARISON: return "2D_comparison"; case HLSL_TEXTURE_CUBE_COMPARISON: @@ -160,12 +341,12 @@ TString TextureGroupSuffix(const HLSLTextureSamplerGroup type) return ""; } -TString TextureGroupSuffix(const TBasicType type) +TString TextureGroupSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) { - return TextureGroupSuffix(TextureGroup(type)); + return TextureGroupSuffix(TextureGroup(type, imageInternalFormat)); } -TString TextureTypeSuffix(const TBasicType type) +TString TextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) { switch (type) { @@ -173,20 +354,340 @@ TString TextureTypeSuffix(const TBasicType type) return "Cube_int4_"; case EbtUSamplerCube: return "Cube_uint4_"; + case EbtSamplerExternalOES: + return "_External"; + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return "Cube_float4_"; + case EiifRGBA8: + return "Cube_unorm_float4_"; + case EiifRGBA8_SNORM: + return "Cube_snorm_float4_"; + default: + UNREACHABLE(); + } + } + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return "Cube_int4_"; + default: + UNREACHABLE(); + } + } + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return "Cube_uint4_"; + default: + UNREACHABLE(); + } + } default: // All other types are identified by their group suffix - return TextureGroupSuffix(type); + return TextureGroupSuffix(type, imageInternalFormat); + } +} + +HLSLRWTextureGroup RWTextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat) + +{ + switch (type) + { + case EbtImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_2D_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_2D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_2D_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_2D_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage2D: + { + switch (imageInternalFormat) + { + + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_2D_UINT4; + default: + UNREACHABLE(); + } + } + case EbtImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_3D_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_3D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_3D_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_3D_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_3D_UINT4; + default: + UNREACHABLE(); + } + } + case EbtImage2DArray: + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_2D_ARRAY_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_2D_ARRAY_UNORN; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_2D_ARRAY_SNORM; + default: + UNREACHABLE(); + } + } + case EbtIImage2DArray: + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_2D_ARRAY_INT4; + default: + UNREACHABLE(); + } + } + case EbtUImage2DArray: + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_2D_ARRAY_UINT4; + default: + UNREACHABLE(); + } + } + default: + UNREACHABLE(); } + return HLSL_RWTEXTURE_UNKNOWN; } -TString DecorateUniform(const TString &string, const TType &type) +TString RWTextureString(const HLSLRWTextureGroup RWTextureGroup) { - if (type.getBasicType() == EbtSamplerExternalOES) + switch (RWTextureGroup) { - return "ex_" + string; + case HLSL_RWTEXTURE_2D_FLOAT4: + return "RWTexture2D"; + case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4: + return "RWTexture2DArray"; + case HLSL_RWTEXTURE_3D_FLOAT4: + return "RWTexture3D"; + case HLSL_RWTEXTURE_2D_UNORM: + return "RWTexture2D"; + case HLSL_RWTEXTURE_2D_ARRAY_UNORN: + return "RWTexture2DArray"; + case HLSL_RWTEXTURE_3D_UNORM: + return "RWTexture3D"; + case HLSL_RWTEXTURE_2D_SNORM: + return "RWTexture2D"; + case HLSL_RWTEXTURE_2D_ARRAY_SNORM: + return "RWTexture2DArray"; + case HLSL_RWTEXTURE_3D_SNORM: + return "RWTexture3D"; + case HLSL_RWTEXTURE_2D_UINT4: + return "RWTexture2D"; + case HLSL_RWTEXTURE_2D_ARRAY_UINT4: + return "RWTexture2DArray"; + case HLSL_RWTEXTURE_3D_UINT4: + return "RWTexture3D"; + case HLSL_RWTEXTURE_2D_INT4: + return "RWTexture2D"; + case HLSL_RWTEXTURE_2D_ARRAY_INT4: + return "RWTexture2DArray"; + case HLSL_RWTEXTURE_3D_INT4: + return "RWTexture3D"; + default: + UNREACHABLE(); } - return Decorate(string); + return ""; +} + +TString RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + return RWTextureString(RWTextureGroup(type, imageInternalFormat)); +} + +TString RWTextureGroupSuffix(const HLSLRWTextureGroup type) +{ + switch (type) + { + case HLSL_RWTEXTURE_2D_FLOAT4: + return "RW2D_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4: + return "RW2DArray_float4_"; + case HLSL_RWTEXTURE_3D_FLOAT4: + return "RW3D_float4_"; + case HLSL_RWTEXTURE_2D_UNORM: + return "RW2D_unorm_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_UNORN: + return "RW2DArray_unorm_float4_"; + case HLSL_RWTEXTURE_3D_UNORM: + return "RW3D_unorm_float4_"; + case HLSL_RWTEXTURE_2D_SNORM: + return "RW2D_snorm_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_SNORM: + return "RW2DArray_snorm_float4_"; + case HLSL_RWTEXTURE_3D_SNORM: + return "RW3D_snorm_float4_"; + case HLSL_RWTEXTURE_2D_UINT4: + return "RW2D_uint4_"; + case HLSL_RWTEXTURE_2D_ARRAY_UINT4: + return "RW2DArray_uint4_"; + case HLSL_RWTEXTURE_3D_UINT4: + return "RW3D_uint4_"; + case HLSL_RWTEXTURE_2D_INT4: + return "RW2D_int4_"; + case HLSL_RWTEXTURE_2D_ARRAY_INT4: + return "RW2DArray_int4_"; + case HLSL_RWTEXTURE_3D_INT4: + return "RW3D_int4_"; + default: + UNREACHABLE(); + } + + return ""; +} + +TString RWTextureGroupSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + return RWTextureGroupSuffix(RWTextureGroup(type, imageInternalFormat)); +} + +TString RWTextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + switch (type) + { + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return "RWCube_float4_"; + case EiifRGBA8: + return "RWCube_unorm_float4_"; + case EiifRGBA8_SNORM: + return "RWCube_unorm_float4_"; + default: + UNREACHABLE(); + } + } + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return "RWCube_int4_"; + default: + UNREACHABLE(); + } + } + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return "RWCube_uint4_"; + default: + UNREACHABLE(); + } + } + default: + // All other types are identified by their group suffix + return TextureGroupSuffix(type, imageInternalFormat); + } } TString DecorateField(const TString &string, const TStructure &structure) @@ -214,10 +715,13 @@ TString Decorate(const TString &string) return string; } -TString DecorateIfNeeded(const TName &name) +TString DecorateVariableIfNeeded(const TName &name) { if (name.isInternal()) { + // The name should not have a prefix reserved for user-defined variables or functions. + ASSERT(name.getString().compare(0, 2, "f_") != 0); + ASSERT(name.getString().compare(0, 1, "_") != 0); return name.getString(); } else @@ -230,25 +734,29 @@ TString DecorateFunctionIfNeeded(const TName &name) { if (name.isInternal()) { - return TFunction::unmangleName(name.getString()); - } - else - { - return Decorate(TFunction::unmangleName(name.getString())); + // The name should not have a prefix reserved for user-defined variables or functions. + ASSERT(name.getString().compare(0, 2, "f_") != 0); + ASSERT(name.getString().compare(0, 1, "_") != 0); + return name.getString(); } + ASSERT(name.getString().compare(0, 3, "gl_") != 0); + // Add an additional f prefix to functions so that they're always disambiguated from variables. + // This is necessary in the corner case where a variable declaration hides a function that it + // uses in its initializer. + return "f_" + name.getString(); } TString TypeString(const TType &type) { - const TStructure* structure = type.getStruct(); + const TStructure *structure = type.getStruct(); if (structure) { - const TString& typeName = structure->name(); + const TString &typeName = structure->name(); if (typeName != "") { return StructNameString(*structure); } - else // Nameless structure, define in place + else // Nameless structure, define in place { return StructureHLSL::defineNameless(*structure); } @@ -263,55 +771,73 @@ TString TypeString(const TType &type) { switch (type.getBasicType()) { - case EbtFloat: - switch (type.getNominalSize()) - { - case 1: return "float"; - case 2: return "float2"; - case 3: return "float3"; - case 4: return "float4"; - } - case EbtInt: - switch (type.getNominalSize()) - { - case 1: return "int"; - case 2: return "int2"; - case 3: return "int3"; - case 4: return "int4"; - } - case EbtUInt: - switch (type.getNominalSize()) - { - case 1: return "uint"; - case 2: return "uint2"; - case 3: return "uint3"; - case 4: return "uint4"; - } - case EbtBool: - switch (type.getNominalSize()) - { - case 1: return "bool"; - case 2: return "bool2"; - case 3: return "bool3"; - case 4: return "bool4"; - } - case EbtVoid: - return "void"; - case EbtSampler2D: - case EbtISampler2D: - case EbtUSampler2D: - case EbtSampler2DArray: - case EbtISampler2DArray: - case EbtUSampler2DArray: - return "sampler2D"; - case EbtSamplerCube: - case EbtISamplerCube: - case EbtUSamplerCube: - return "samplerCUBE"; - case EbtSamplerExternalOES: - return "sampler2D"; - default: - break; + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: + return "float"; + case 2: + return "float2"; + case 3: + return "float3"; + case 4: + return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: + return "int"; + case 2: + return "int2"; + case 3: + return "int3"; + case 4: + return "int4"; + } + case EbtUInt: + switch (type.getNominalSize()) + { + case 1: + return "uint"; + case 2: + return "uint2"; + case 3: + return "uint3"; + case 4: + return "uint4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: + return "bool"; + case 2: + return "bool2"; + case 3: + return "bool3"; + case 4: + return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + return "sampler2D"; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + return "samplerCUBE"; + case EbtSamplerExternalOES: + return "sampler2D"; + case EbtAtomicCounter: + return "atomic_uint"; + default: + break; } } @@ -336,7 +862,8 @@ TString StructNameString(const TStructure &structure) return "ss" + str(structure.uniqueId()) + "_" + structure.name(); } -TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking, +TString QualifiedStructNameString(const TStructure &structure, + bool useHLSLRowMajorPacking, bool useStd140Packing) { if (structure.name() == "") @@ -366,17 +893,28 @@ TString InterpolationString(TQualifier qualifier) { switch (qualifier) { - case EvqVaryingIn: return ""; - case EvqFragmentIn: return ""; - case EvqSmoothIn: return "linear"; - case EvqFlatIn: return "nointerpolation"; - case EvqCentroidIn: return "centroid"; - case EvqVaryingOut: return ""; - case EvqVertexOut: return ""; - case EvqSmoothOut: return "linear"; - case EvqFlatOut: return "nointerpolation"; - case EvqCentroidOut: return "centroid"; - default: UNREACHABLE(); + case EvqVaryingIn: + return ""; + case EvqFragmentIn: + return ""; + case EvqSmoothIn: + return "linear"; + case EvqFlatIn: + return "nointerpolation"; + case EvqCentroidIn: + return "centroid"; + case EvqVaryingOut: + return ""; + case EvqVertexOut: + return ""; + case EvqSmoothOut: + return "linear"; + case EvqFlatOut: + return "nointerpolation"; + case EvqCentroidOut: + return "centroid"; + default: + UNREACHABLE(); } return ""; @@ -386,53 +924,47 @@ TString QualifierString(TQualifier qualifier) { switch (qualifier) { - case EvqIn: return "in"; - case EvqOut: return "inout"; // 'out' results in an HLSL error if not all fields are written, for GLSL it's undefined - case EvqInOut: return "inout"; - case EvqConstReadOnly: return "const"; - default: UNREACHABLE(); + case EvqIn: + return "in"; + case EvqOut: + return "inout"; // 'out' results in an HLSL error if not all fields are written, for + // GLSL it's undefined + case EvqInOut: + return "inout"; + case EvqConstReadOnly: + return "const"; + default: + UNREACHABLE(); } return ""; } -int HLSLTextureCoordsCount(const TBasicType samplerType) +TString DisambiguateFunctionName(const TIntermSequence *parameters) { - switch (samplerType) + TString disambiguatingString; + for (auto parameter : *parameters) { - 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(); + const TType ¶mType = parameter->getAsTyped()->getType(); + // Parameter types are only added to function names if they are ambiguous according to the + // native HLSL compiler. Other parameter types are not added to function names to avoid + // making function names longer. + if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat) + { + // Disambiguation is needed for float2x2 and float4 parameters. These are the only + // built-in types that HLSL thinks are identical. float2x3 and float3x2 are different + // types, for example. + disambiguatingString += "_" + TypeString(paramType); + } + else if (paramType.getBasicType() == EbtStruct) + { + // Disambiguation is needed for struct parameters, since HLSL thinks that structs with + // the same fields but a different name are identical. + ASSERT(paramType.getStruct()->name() != ""); + disambiguatingString += "_" + TypeString(paramType); + } } - return 0; -} + return disambiguatingString; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h index 42444e3a56..daeec8de41 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h @@ -11,6 +11,7 @@ #define COMPILER_TRANSLATOR_UTILSHLSL_H_ #include +#include "compiler/translator/IntermNode.h" #include "compiler/translator/Types.h" #include "angle_gl.h" @@ -20,22 +21,33 @@ class TName; namespace sh { -// Unique combinations of HLSL Texture type and HLSL Sampler type. -enum HLSLTextureSamplerGroup +// HLSL Texture type for GLSL sampler type and readonly image type. +enum HLSLTextureGroup { - // Regular samplers + // read resources HLSL_TEXTURE_2D, HLSL_TEXTURE_MIN = HLSL_TEXTURE_2D, HLSL_TEXTURE_CUBE, HLSL_TEXTURE_2D_ARRAY, HLSL_TEXTURE_3D, + HLSL_TEXTURE_2D_UNORM, + HLSL_TEXTURE_CUBE_UNORM, + HLSL_TEXTURE_2D_ARRAY_UNORN, + HLSL_TEXTURE_3D_UNORM, + HLSL_TEXTURE_2D_SNORM, + HLSL_TEXTURE_CUBE_SNORM, + HLSL_TEXTURE_2D_ARRAY_SNORM, + HLSL_TEXTURE_3D_SNORM, + HLSL_TEXTURE_2D_MS, HLSL_TEXTURE_2D_INT4, HLSL_TEXTURE_3D_INT4, HLSL_TEXTURE_2D_ARRAY_INT4, + HLSL_TEXTURE_2D_MS_INT4, HLSL_TEXTURE_2D_UINT4, HLSL_TEXTURE_3D_UINT4, HLSL_TEXTURE_2D_ARRAY_UINT4, + HLSL_TEXTURE_2D_MS_UINT4, // Comparison samplers @@ -50,29 +62,68 @@ enum HLSLTextureSamplerGroup 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); +// HLSL RWTexture type for GLSL read and write image type. +enum HLSLRWTextureGroup +{ + // read/write resource + HLSL_RWTEXTURE_2D_FLOAT4, + HLSL_RWTEXTURE_MIN = HLSL_RWTEXTURE_2D_FLOAT4, + HLSL_RWTEXTURE_2D_ARRAY_FLOAT4, + HLSL_RWTEXTURE_3D_FLOAT4, + HLSL_RWTEXTURE_2D_UNORM, + HLSL_RWTEXTURE_2D_ARRAY_UNORN, + HLSL_RWTEXTURE_3D_UNORM, + HLSL_RWTEXTURE_2D_SNORM, + HLSL_RWTEXTURE_2D_ARRAY_SNORM, + HLSL_RWTEXTURE_3D_SNORM, + HLSL_RWTEXTURE_2D_UINT4, + HLSL_RWTEXTURE_2D_ARRAY_UINT4, + HLSL_RWTEXTURE_3D_UINT4, + HLSL_RWTEXTURE_2D_INT4, + HLSL_RWTEXTURE_2D_ARRAY_INT4, + HLSL_RWTEXTURE_3D_INT4, + + HLSL_RWTEXTURE_UNKNOWN, + HLSL_RWTEXTURE_MAX = HLSL_RWTEXTURE_UNKNOWN +}; + +HLSLTextureGroup TextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +TString TextureString(const HLSLTextureGroup textureGroup); +TString TextureString(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +TString TextureGroupSuffix(const HLSLTextureGroup type); +TString TextureGroupSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +TString TextureTypeSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +HLSLRWTextureGroup RWTextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat); +TString RWTextureString(const HLSLRWTextureGroup textureGroup); +TString RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat); +TString RWTextureGroupSuffix(const HLSLRWTextureGroup type); +TString RWTextureGroupSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat); +TString RWTextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat); + TString SamplerString(const TBasicType type); -TString SamplerString(HLSLTextureSamplerGroup type); -// Prepends an underscore to avoid naming clashes +TString SamplerString(HLSLTextureGroup type); + +// Adds a prefix to user-defined names to avoid naming clashes. TString Decorate(const TString &string); -TString DecorateIfNeeded(const TName &name); -// Decorates and also unmangles the function name +TString DecorateVariableIfNeeded(const TName &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); TString TypeString(const TType &type); TString StructNameString(const TStructure &structure); -TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking, +TString QualifiedStructNameString(const TStructure &structure, + bool useHLSLRowMajorPacking, bool useStd140Packing); TString InterpolationString(TQualifier qualifier); TString QualifierString(TQualifier qualifier); -int HLSLTextureCoordsCount(const TBasicType samplerType); +// Parameters may need to be included in function names to disambiguate between overloaded +// functions. +TString DisambiguateFunctionName(const TIntermSequence *parameters); } -#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_ +#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 index 2461b6a438..492972b60d 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.cpp @@ -6,8 +6,12 @@ #include "compiler/translator/ValidateGlobalInitializer.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/ParseContext.h" +namespace sh +{ + namespace { @@ -32,7 +36,8 @@ class ValidateGlobalInitializerTraverser : public TIntermTraverser void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node) { - const TSymbol *sym = mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion()); + 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): @@ -40,33 +45,36 @@ void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node) 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) - { + 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; - } - 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) + // 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 + // the function call ops. + if (node->isFunctionCall()) { mIsValid = false; } @@ -92,16 +100,15 @@ bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *n } ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context) - : TIntermTraverser(true, false, false), - mContext(context), - mIsValid(true), - mIssueWarning(false) + : TIntermTraverser(true, false, false), mContext(context), mIsValid(true), mIssueWarning(false) { } -} // namespace +} // namespace -bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning) +bool ValidateGlobalInitializer(TIntermTyped *initializer, + const TParseContext *context, + bool *warning) { ValidateGlobalInitializerTraverser validate(context); initializer->traverse(&validate); @@ -110,3 +117,4 @@ bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *c return validate.isValid(); } +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h index c3d2a47eba..2e7570667a 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateGlobalInitializer.h @@ -7,10 +7,17 @@ #ifndef COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_ #define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_ +namespace sh +{ + class TIntermTyped; class TParseContext; // Returns true if the initializer is valid. -bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning); +bool ValidateGlobalInitializer(TIntermTyped *initializer, + const TParseContext *context, + bool *warning); + +} // namespace sh -#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_ +#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 ba8cdd0aa8..941f79ae51 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp @@ -5,14 +5,29 @@ // #include "compiler/translator/ValidateLimitations.h" -#include "compiler/translator/InfoSink.h" -#include "compiler/translator/InitializeParseContext.h" -#include "compiler/translator/ParseContext.h" + #include "angle_gl.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/ParseContext.h" + +namespace sh +{ namespace { +int GetLoopSymbolId(TIntermLoop *loop) +{ + // Here we assume all the operations are valid, because the loop node is + // already validated before this call. + TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence(); + TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + + return symbol->getId(); +} + // Traverses a node to check if it represents a constant index expression. // Definition: // constant-index-expressions are a superset of constant-expressions. @@ -25,10 +40,8 @@ namespace class ValidateConstIndexExpr : public TIntermTraverser { public: - ValidateConstIndexExpr(TLoopStack& stack) - : TIntermTraverser(true, false, false), - mValid(true), - mLoopStack(stack) + ValidateConstIndexExpr(const std::vector &loopSymbols) + : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols) { } @@ -41,93 +54,93 @@ class ValidateConstIndexExpr : public TIntermTraverser // constant index expression. if (mValid) { - mValid = (symbol->getQualifier() == EvqConst) || - (mLoopStack.findLoop(symbol)); + bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), + symbol->getId()) != mLoopSymbolIds.end(); + mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol; } } private: bool mValid; - TLoopStack& mLoopStack; + const std::vector mLoopSymbolIds; }; -} // namespace anonymous +// Traverses intermediate tree to ensure that the shader does not exceed the +// minimum functionality mandated in GLSL 1.0 spec, Appendix A. +class ValidateLimitationsTraverser : public TLValueTrackingTraverser +{ + public: + ValidateLimitationsTraverser(sh::GLenum shaderType, + TSymbolTable *symbolTable, + int shaderVersion, + TDiagnostics *diagnostics); -ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink) - : TIntermTraverser(true, false, false), + void visitSymbol(TIntermSymbol *node) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitLoop(Visit, TIntermLoop *) override; + + private: + void error(TSourceLoc loc, const char *reason, const char *token); + + bool withinLoopBody() const; + bool isLoopIndex(TIntermSymbol *symbol); + bool validateLoopType(TIntermLoop *node); + + bool validateForLoopHeader(TIntermLoop *node); + // If valid, return the index symbol id; Otherwise, return -1. + int validateForLoopInit(TIntermLoop *node); + bool validateForLoopCond(TIntermLoop *node, int indexSymbolId); + bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId); + + // Returns true if indexing does not exceed the minimum functionality + // mandated in GLSL 1.0 spec, Appendix A, Section 5. + bool isConstExpr(TIntermNode *node); + bool isConstIndexExpr(TIntermNode *node); + bool validateIndexing(TIntermBinary *node); + + sh::GLenum mShaderType; + TDiagnostics *mDiagnostics; + std::vector mLoopSymbolIds; +}; + +ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType, + TSymbolTable *symbolTable, + int shaderVersion, + TDiagnostics *diagnostics) + : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion), mShaderType(shaderType), - mSink(sink), - mNumErrors(0), - mValidateIndexing(true), - mValidateInnerLoops(true) + mDiagnostics(diagnostics) { + ASSERT(diagnostics); } -// static -bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop) +void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node) { - // 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) + if (isLoopIndex(node) && isLValueRequiredHere()) { - validate.mLoopStack.push(loop); - body->traverse(&validate); - validate.mLoopStack.pop(); + error(node->getLine(), + "Loop index cannot be statically assigned to within the body of the loop", + node->getSymbol().c_str()); } - return (validate.mNumErrors == 0); } -bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node) +bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node) { - // Check if loop index is modified in the loop body. - validateOperation(node, node->getLeft()); - // Check indexing. switch (node->getOp()) { - case EOpIndexDirect: - case EOpIndexIndirect: - if (mValidateIndexing) - validateIndexing(node); - break; - default: - break; - } - return true; -} - -bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node) -{ - // Check if loop index is modified in the loop body. - validateOperation(node, node->getOperand()); - - return true; -} - -bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node) -{ - switch (node->getOp()) { - case EOpFunctionCall: - validateFunctionCall(node); - break; - default: - break; + case EOpIndexDirect: + case EOpIndexIndirect: + validateIndexing(node); + break; + default: + break; } return true; } -bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) +bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node) { - if (!mValidateInnerLoops) - return true; - if (!validateLoopType(node)) return false; @@ -135,53 +148,45 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) return false; TIntermNode *body = node->getBody(); - if (body != NULL) + if (body != nullptr) { - mLoopStack.push(node); + mLoopSymbolIds.push_back(GetLoopSymbolId(node)); body->traverse(this); - mLoopStack.pop(); + mLoopSymbolIds.pop_back(); } // The loop is fully processed - no need to visit children. return false; } -void ValidateLimitations::error(TSourceLoc loc, - const char *reason, const char *token) +void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token) { - if (mSink) - { - mSink->prefix(EPrefixError); - mSink->location(loc); - (*mSink) << "'" << token << "' : " << reason << "\n"; - } - ++mNumErrors; + mDiagnostics->error(loc, reason, token); } -bool ValidateLimitations::withinLoopBody() const +bool ValidateLimitationsTraverser::withinLoopBody() const { - return !mLoopStack.empty(); + return !mLoopSymbolIds.empty(); } -bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol) +bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol) { - return mLoopStack.findLoop(symbol) != NULL; + return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->getId()) != + mLoopSymbolIds.end(); } -bool ValidateLimitations::validateLoopType(TIntermLoop *node) +bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node) { TLoopType type = node->getType(); if (type == ELoopFor) return true; // Reject while and do-while loops. - error(node->getLine(), - "This type of loop is not allowed", - type == ELoopWhile ? "while" : "do"); + error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do"); return false; } -bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) +bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node) { ASSERT(node->getType() == ELoopFor); @@ -200,10 +205,10 @@ bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) return true; } -int ValidateLimitations::validateForLoopInit(TIntermLoop *node) +int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node) { TIntermNode *init = node->getInit(); - if (init == NULL) + if (init == nullptr) { error(node->getLine(), "Missing init declaration", "for"); return -1; @@ -213,8 +218,8 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node) // init-declaration has the form: // type-specifier identifier = constant-expression // - TIntermAggregate *decl = init->getAsAggregate(); - if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) + TIntermDeclaration *decl = init->getAsDeclarationNode(); + if (decl == nullptr) { error(init->getLine(), "Invalid init declaration", "for"); return -1; @@ -227,29 +232,28 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node) return -1; } TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); - if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) + if ((declInit == nullptr) || (declInit->getOp() != EOpInitialize)) { error(decl->getLine(), "Invalid init declaration", "for"); return -1; } TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); - if (symbol == NULL) + if (symbol == nullptr) { error(declInit->getLine(), "Invalid init declaration", "for"); return -1; } // The loop index has type int or float. TBasicType type = symbol->getBasicType(); - if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) { - error(symbol->getLine(), - "Invalid type for loop index", getBasicString(type)); + if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) + { + error(symbol->getLine(), "Invalid type for loop index", getBasicString(type)); return -1; } // The loop index is initialized with constant expression. if (!isConstExpr(declInit->getRight())) { - error(declInit->getLine(), - "Loop index cannot be initialized with non-constant expression", + error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression", symbol->getSymbol().c_str()); return -1; } @@ -257,11 +261,10 @@ int ValidateLimitations::validateForLoopInit(TIntermLoop *node) return symbol->getId(); } -bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, - int indexSymbolId) +bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId) { TIntermNode *cond = node->getCondition(); - if (cond == NULL) + if (cond == nullptr) { error(node->getLine(), "Missing condition", "for"); return false; @@ -271,45 +274,42 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, // loop_index relational_operator constant_expression // TIntermBinary *binOp = cond->getAsBinaryNode(); - if (binOp == NULL) + if (binOp == nullptr) { error(node->getLine(), "Invalid condition", "for"); return false; } // Loop index should be to the left of relational operator. TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode(); - if (symbol == NULL) + if (symbol == nullptr) { error(binOp->getLine(), "Invalid condition", "for"); return false; } if (symbol->getId() != indexSymbolId) { - error(symbol->getLine(), - "Expected loop index", symbol->getSymbol().c_str()); + error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // Relational operator is one of: > >= < <= == or !=. switch (binOp->getOp()) { - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - break; - default: - error(binOp->getLine(), - "Invalid relational operator", - GetOperatorString(binOp->getOp())); - break; + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + default: + error(binOp->getLine(), "Invalid relational operator", + GetOperatorString(binOp->getOp())); + break; } // Loop index must be compared with a constant. if (!isConstExpr(binOp->getRight())) { - error(binOp->getLine(), - "Loop index cannot be compared with non-constant expression", + error(binOp->getLine(), "Loop index cannot be compared with non-constant expression", symbol->getSymbol().c_str()); return false; } @@ -317,11 +317,10 @@ bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, return true; } -bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, - int indexSymbolId) +bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId) { TIntermNode *expr = node->getExpression(); - if (expr == NULL) + if (expr == nullptr) { error(node->getLine(), "Missing expression", "for"); return false; @@ -336,60 +335,58 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, // --loop_index // The last two forms are not specified in the spec, but I am assuming // its an oversight. - TIntermUnary *unOp = expr->getAsUnaryNode(); - TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? nullptr : expr->getAsBinaryNode(); - TOperator op = EOpNull; - TIntermSymbol *symbol = NULL; - if (unOp != NULL) + TOperator op = EOpNull; + TIntermSymbol *symbol = nullptr; + if (unOp != nullptr) { - op = unOp->getOp(); + op = unOp->getOp(); symbol = unOp->getOperand()->getAsSymbolNode(); } - else if (binOp != NULL) + else if (binOp != nullptr) { - op = binOp->getOp(); + op = binOp->getOp(); symbol = binOp->getLeft()->getAsSymbolNode(); } // The operand must be loop index. - if (symbol == NULL) + if (symbol == nullptr) { error(expr->getLine(), "Invalid expression", "for"); return false; } if (symbol->getId() != indexSymbolId) { - error(symbol->getLine(), - "Expected loop index", symbol->getSymbol().c_str()); + error(symbol->getLine(), "Expected loop index", symbol->getSymbol().c_str()); return false; } // The operator is one of: ++ -- += -=. switch (op) { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - ASSERT((unOp != NULL) && (binOp == NULL)); - break; - case EOpAddAssign: - case EOpSubAssign: - ASSERT((unOp == NULL) && (binOp != NULL)); - break; - default: - error(expr->getLine(), "Invalid operator", GetOperatorString(op)); - return false; + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != nullptr) && (binOp == nullptr)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == nullptr) && (binOp != nullptr)); + break; + default: + error(expr->getLine(), "Invalid operator", GetOperatorString(op)); + return false; } // Loop index must be incremented/decremented with a constant. - if (binOp != NULL) + if (binOp != nullptr) { if (!isConstExpr(binOp->getRight())) { - error(binOp->getLine(), - "Loop index cannot be modified by non-constant expression", + error(binOp->getLine(), "Loop index cannot be modified by non-constant expression", symbol->getSymbol().c_str()); return false; } @@ -398,95 +395,31 @@ bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, return true; } -bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node) -{ - ASSERT(node->getOp() == EOpFunctionCall); - - // If not within loop body, there is nothing to check. - if (!withinLoopBody()) - return true; - - // List of param indices for which loop indices are used as argument. - typedef std::vector ParamIndex; - ParamIndex pIndex; - TIntermSequence *params = node->getSequence(); - for (TIntermSequence::size_type i = 0; i < params->size(); ++i) - { - TIntermSymbol *symbol = (*params)[i]->getAsSymbolNode(); - if (symbol && isLoopIndex(symbol)) - pIndex.push_back(i); - } - // If none of the loop indices are used as arguments, - // there is nothing to check. - if (pIndex.empty()) - return true; - - bool valid = true; - TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable; - 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 TConstParameter ¶m = function->getParam(*i); - TQualifier qual = param.type->getQualifier(); - if ((qual == EvqOut) || (qual == EvqInOut)) - { - error((*params)[*i]->getLine(), - "Loop index cannot be used as argument to a function out or inout parameter", - (*params)[*i]->getAsSymbolNode()->getSymbol().c_str()); - valid = false; - } - } - - return valid; -} - -bool ValidateLimitations::validateOperation(TIntermOperator *node, - TIntermNode* operand) -{ - // Check if loop index is modified in the loop body. - if (!withinLoopBody() || !node->isAssignment()) - return true; - - TIntermSymbol *symbol = operand->getAsSymbolNode(); - if (symbol && isLoopIndex(symbol)) - { - error(node->getLine(), - "Loop index cannot be statically assigned to within the body of the loop", - symbol->getSymbol().c_str()); - } - return true; -} - -bool ValidateLimitations::isConstExpr(TIntermNode *node) +bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node) { ASSERT(node != nullptr); return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst; } -bool ValidateLimitations::isConstIndexExpr(TIntermNode *node) +bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node) { - ASSERT(node != NULL); + ASSERT(node != nullptr); - ValidateConstIndexExpr validate(mLoopStack); + ValidateConstIndexExpr validate(mLoopSymbolIds); node->traverse(&validate); return validate.isValid(); } -bool ValidateLimitations::validateIndexing(TIntermBinary *node) +bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node) { - ASSERT((node->getOp() == EOpIndexDirect) || - (node->getOp() == EOpIndexIndirect)); + ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect)); - bool valid = true; + bool valid = true; TIntermTyped *index = node->getRight(); // The index expession must be a constant-index-expression unless // the operand is a uniform in a vertex shader. TIntermTyped *operand = node->getLeft(); - bool skip = (mShaderType == GL_VERTEX_SHADER) && - (operand->getQualifier() == EvqUniform); + bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform); if (!skip && !isConstIndexExpr(index)) { error(index->getLine(), "Index expression must be constant", "[]"); @@ -495,3 +428,17 @@ bool ValidateLimitations::validateIndexing(TIntermBinary *node) return valid; } +} // namespace anonymous + +bool ValidateLimitations(TIntermNode *root, + GLenum shaderType, + TSymbolTable *symbolTable, + int shaderVersion, + TDiagnostics *diagnostics) +{ + ValidateLimitationsTraverser validate(shaderType, symbolTable, shaderVersion, diagnostics); + root->traverse(&validate); + return diagnostics->numErrors() == 0; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h index 666e38ff5c..9149b8c216 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h @@ -8,56 +8,20 @@ #define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ #include "compiler/translator/IntermNode.h" -#include "compiler/translator/LoopInfo.h" -class TInfoSinkBase; - -// Traverses intermediate tree to ensure that the shader does not exceed the -// minimum functionality mandated in GLSL 1.0 spec, Appendix A. -class ValidateLimitations : public TIntermTraverser +namespace sh { - public: - ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink); - - int numErrors() const { return mNumErrors; } - - 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); - - bool withinLoopBody() const; - bool isLoopIndex(TIntermSymbol *symbol); - bool validateLoopType(TIntermLoop *node); - - bool validateForLoopHeader(TIntermLoop *node); - // If valid, return the index symbol id; Otherwise, return -1. - int validateForLoopInit(TIntermLoop *node); - bool validateForLoopCond(TIntermLoop *node, int indexSymbolId); - bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId); - // Returns true if none of the loop indices is used as the argument to - // the given function out or inout parameter. - bool validateFunctionCall(TIntermAggregate *node); - bool validateOperation(TIntermOperator *node, TIntermNode *operand); +class TDiagnostics; - // Returns true if indexing does not exceed the minimum functionality - // mandated in GLSL 1.0 spec, Appendix A, Section 5. - bool isConstExpr(TIntermNode *node); - bool isConstIndexExpr(TIntermNode *node); - bool validateIndexing(TIntermBinary *node); +// Returns true if the given shader does not exceed the minimum functionality mandated in GLSL ES +// 1.00 spec Appendix A. +bool ValidateLimitations(TIntermNode *root, + GLenum shaderType, + TSymbolTable *symbolTable, + int shaderVersion, + TDiagnostics *diagnostics); - sh::GLenum mShaderType; - TInfoSinkBase *mSink; - int mNumErrors; - TLoopStack mLoopStack; - bool mValidateIndexing; - bool mValidateInnerLoops; -}; +} // namespace sh -#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ +#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.cpp new file mode 100644 index 0000000000..9dccbf413f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ValidateMaxParameters checks if function definitions have more than a set number of parameters. + +#include "compiler/translator/ValidateMaxParameters.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters) +{ + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *definition = node->getAsFunctionDefinition(); + if (definition != nullptr && + definition->getFunctionPrototype()->getSequence()->size() > maxParameters) + { + return false; + } + } + return true; +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.h b/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.h new file mode 100644 index 0000000000..dec7597da4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateMaxParameters.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ValidateMaxParameters checks if function definitions have more than a set number of parameters. + +#ifndef COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ +#define COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ + +namespace sh +{ + +class TIntermBlock; + +// Return true if valid. +bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp index cd37aeacd1..26f0e81ba7 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.cpp @@ -3,64 +3,101 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations, +// out-of-range locations, that locations are specified when using multiple outputs, and YUV output +// validity. #include "compiler/translator/ValidateOutputs.h" + +#include + #include "compiler/translator/InfoSink.h" -#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/ParseContext.h" +namespace sh +{ + namespace { -void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason) +void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) { - sink.prefix(EPrefixError); - sink.location(symbol.getLine()); - sink << "'" << symbol.getSymbol() << "' : " << reason << "\n"; - (*errorCount)++; + diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str()); } -} // namespace +class ValidateOutputsTraverser : public TIntermTraverser +{ + public: + ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, int maxDrawBuffers); + + void validate(TDiagnostics *diagnostics) const; + + void visitSymbol(TIntermSymbol *) override; -ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers) + private: + int mMaxDrawBuffers; + bool mAllowUnspecifiedOutputLocationResolution; + bool mUsesFragDepth; + + typedef std::vector OutputVector; + OutputVector mOutputs; + OutputVector mUnspecifiedLocationOutputs; + OutputVector mYuvOutputs; + std::set mVisitedSymbols; +}; + +ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, + int maxDrawBuffers) : TIntermTraverser(true, false, false), mMaxDrawBuffers(maxDrawBuffers), mAllowUnspecifiedOutputLocationResolution( - IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended")) + IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)), + mUsesFragDepth(false) { } -void ValidateOutputs::visitSymbol(TIntermSymbol *symbol) +void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol) { - TString name = symbol->getSymbol(); + TString name = symbol->getSymbol(); TQualifier qualifier = symbol->getQualifier(); - if (mVisitedSymbols.count(name) == 1) + if (mVisitedSymbols.count(name.c_str()) == 1) return; - mVisitedSymbols.insert(name); + mVisitedSymbols.insert(name.c_str()); if (qualifier == EvqFragmentOut) { - if (symbol->getType().getLayoutQualifier().location == -1) + if (symbol->getType().getLayoutQualifier().location != -1) { - mUnspecifiedLocationOutputs.push_back(symbol); + mOutputs.push_back(symbol); + } + else if (symbol->getType().getLayoutQualifier().yuv == true) + { + mYuvOutputs.push_back(symbol); } else { - mOutputs.push_back(symbol); + mUnspecifiedLocationOutputs.push_back(symbol); } } + else if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT) + { + mUsesFragDepth = true; + } } -int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const +void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const { + ASSERT(diagnostics); 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); + ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6. + const size_t elementCount = + static_cast(type.isArray() ? type.getOutermostArraySize() : 1u); const size_t location = static_cast(type.getLayoutQualifier().location); ASSERT(type.getLayoutQualifier().location != -1); @@ -75,7 +112,7 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const std::stringstream strstr; strstr << "conflicting output locations with previously defined output '" << validOutputs[offsetLocation]->getSymbol() << "'"; - error(&errorCount, sink, *symbol, strstr.str().c_str()); + error(*symbol, strstr.str().c_str(), diagnostics); } else { @@ -87,9 +124,10 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const { if (elementCount > 0) { - error(&errorCount, sink, *symbol, + error(*symbol, elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS" - : "output location must be < MAX_DRAW_BUFFERS"); + : "output location must be < MAX_DRAW_BUFFERS", + diagnostics); } } } @@ -100,9 +138,37 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const { for (const auto &symbol : mUnspecifiedLocationOutputs) { - error(&errorCount, sink, *symbol, - "must explicitly specify all locations when using multiple fragment outputs"); + error(*symbol, + "must explicitly specify all locations when using multiple fragment outputs", + diagnostics); } } - return errorCount; + + if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() || + !mUnspecifiedLocationOutputs.empty())) + { + for (const auto &symbol : mYuvOutputs) + { + error(*symbol, + "not allowed to specify yuv qualifier when using depth or multiple color " + "fragment outputs", + diagnostics); + } + } +} + +} // anonymous namespace + +bool ValidateOutputs(TIntermBlock *root, + const TExtensionBehavior &extBehavior, + int maxDrawBuffers, + TDiagnostics *diagnostics) +{ + ValidateOutputsTraverser validateOutputs(extBehavior, maxDrawBuffers); + root->traverse(&validateOutputs); + int numErrorsBefore = diagnostics->numErrors(); + validateOutputs.validate(diagnostics); + return (diagnostics->numErrors() == numErrorsBefore); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h index 06f63994cd..e41ccd990c 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h @@ -3,34 +3,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations, +// out-of-range locations, that locations are specified when using multiple outputs, and YUV output +// validity. +// #ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ #define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ #include "compiler/translator/ExtensionBehavior.h" -#include "compiler/translator/IntermNode.h" - -#include -class TInfoSinkBase; - -class ValidateOutputs : public TIntermTraverser +namespace sh { - public: - ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers); - - int validateAndCountErrors(TInfoSinkBase &sink) const; - void visitSymbol(TIntermSymbol *) override; +class TIntermBlock; +class TDiagnostics; - private: - int mMaxDrawBuffers; - bool mAllowUnspecifiedOutputLocationResolution; +// Returns true if the shader has no conflicting or otherwise erroneous fragment outputs. +bool ValidateOutputs(TIntermBlock *root, + const TExtensionBehavior &extBehavior, + int maxDrawBuffers, + TDiagnostics *diagnostics); - typedef std::vector OutputVector; - OutputVector mOutputs; - OutputVector mUnspecifiedLocationOutputs; - std::set mVisitedSymbols; -}; +} // namespace sh -#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ +#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp index 9a4ed33632..9f7a264e58 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp @@ -6,21 +6,76 @@ #include "compiler/translator/ValidateSwitch.h" -#include "compiler/translator/ParseContext.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermTraverse.h" -bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context, - TIntermAggregate *statementList, const TSourceLoc &loc) +namespace sh { - ValidateSwitch validate(switchType, context); + +namespace +{ + +class ValidateSwitch : public TIntermTraverser +{ + public: + static bool validate(TBasicType switchType, + int shaderVersion, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc); + + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitDeclaration(Visit, TIntermDeclaration *) override; + bool visitBlock(Visit, TIntermBlock *) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitUnary(Visit, TIntermUnary *) override; + bool visitTernary(Visit, TIntermTernary *) override; + bool visitSwizzle(Visit, TIntermSwizzle *) override; + bool visitIfElse(Visit visit, TIntermIfElse *) override; + bool visitSwitch(Visit, TIntermSwitch *) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit, TIntermBranch *) override; + + private: + ValidateSwitch(TBasicType switchType, int shaderVersion, TDiagnostics *context); + + bool validateInternal(const TSourceLoc &loc); + + TBasicType mSwitchType; + int mShaderVersion; + TDiagnostics *mDiagnostics; + bool mCaseTypeMismatch; + bool mFirstCaseFound; + bool mStatementBeforeCase; + bool mLastStatementWasCase; + int mControlFlowDepth; + bool mCaseInsideControlFlow; + int mDefaultCount; + std::set mCasesSigned; + std::set mCasesUnsigned; + bool mDuplicateCases; +}; + +bool ValidateSwitch::validate(TBasicType switchType, + int shaderVersion, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc) +{ + ValidateSwitch validate(switchType, shaderVersion, diagnostics); ASSERT(statementList); statementList->traverse(&validate); return validate.validateInternal(loc); } -ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context) +ValidateSwitch::ValidateSwitch(TBasicType switchType, int shaderVersion, TDiagnostics *diagnostics) : TIntermTraverser(true, false, true), mSwitchType(switchType), - mContext(context), + mShaderVersion(shaderVersion), + mDiagnostics(diagnostics), mCaseTypeMismatch(false), mFirstCaseFound(false), mStatementBeforeCase(false), @@ -29,13 +84,14 @@ ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context) mCaseInsideControlFlow(false), mDefaultCount(0), mDuplicateCases(false) -{} +{ +} void ValidateSwitch::visitSymbol(TIntermSymbol *) { if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; } void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) @@ -44,14 +100,33 @@ void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) // Could be just a statement like "0;" if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; +} + +bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitBlock(Visit, TIntermBlock *) +{ + if (getParentNode() != nullptr) + { + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + } + return true; } bool ValidateSwitch::visitBinary(Visit, TIntermBinary *) { if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; return true; } @@ -59,11 +134,27 @@ bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) { if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitTernary(Visit, TIntermTernary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; return true; } -bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *) +bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *) { if (visit == PreVisit) ++mControlFlowDepth; @@ -71,7 +162,7 @@ bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *) --mControlFlowDepth; if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; return true; } @@ -79,7 +170,7 @@ bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *) { if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; // Don't go into nested switch statements return false; } @@ -89,17 +180,17 @@ bool ValidateSwitch::visitCase(Visit, TIntermCase *node) const char *nodeStr = node->hasCondition() ? "case" : "default"; if (mControlFlowDepth > 0) { - mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr); + mDiagnostics->error(node->getLine(), "label statement nested inside control flow", nodeStr); mCaseInsideControlFlow = true; } - mFirstCaseFound = true; + mFirstCaseFound = true; mLastStatementWasCase = true; if (!node->hasCondition()) { ++mDefaultCount; if (mDefaultCount > 1) { - mContext->error(node->getLine(), "duplicate default label", nodeStr); + mDiagnostics->error(node->getLine(), "duplicate default label", nodeStr); } } else @@ -113,8 +204,9 @@ bool ValidateSwitch::visitCase(Visit, TIntermCase *node) TBasicType conditionType = condition->getBasicType(); if (conditionType != mSwitchType) { - mContext->error(condition->getLine(), - "case label type does not match switch init-expression type", nodeStr); + mDiagnostics->error(condition->getLine(), + "case label type does not match switch init-expression type", + nodeStr); mCaseTypeMismatch = true; } @@ -123,7 +215,7 @@ bool ValidateSwitch::visitCase(Visit, TIntermCase *node) int iConst = condition->getIConst(0); if (mCasesSigned.find(iConst) != mCasesSigned.end()) { - mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); mDuplicateCases = true; } else @@ -136,7 +228,7 @@ bool ValidateSwitch::visitCase(Visit, TIntermCase *node) unsigned int uConst = condition->getUConst(0); if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end()) { - mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); mDuplicateCases = true; } else @@ -158,7 +250,7 @@ bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *) // This is not the statementList node, but some other node. if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; } return true; } @@ -171,7 +263,7 @@ bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *) --mControlFlowDepth; if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; return true; } @@ -179,7 +271,7 @@ bool ValidateSwitch::visitBranch(Visit, TIntermBranch *) { if (!mFirstCaseFound) mStatementBeforeCase = true; - mLastStatementWasCase = false; + mLastStatementWasCase = false; return true; } @@ -187,14 +279,41 @@ bool ValidateSwitch::validateInternal(const TSourceLoc &loc) { if (mStatementBeforeCase) { - mContext->error(loc, - "statement before the first label", "switch"); + mDiagnostics->error(loc, "statement before the first label", "switch"); } + bool lastStatementWasCaseError = false; if (mLastStatementWasCase) { - mContext->error(loc, - "no statement between the last label and the end of the switch statement", "switch"); + if (mShaderVersion == 300) + { + lastStatementWasCaseError = true; + // This error has been proposed to be made optional in GLSL ES 3.00, but dEQP tests + // still require it. + mDiagnostics->error( + loc, "no statement between the last label and the end of the switch statement", + "switch"); + } + else + { + // The error has been removed from GLSL ES 3.10. + mDiagnostics->warning( + loc, "no statement between the last label and the end of the switch statement", + "switch"); + } } - return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow && - !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases; + return !mStatementBeforeCase && !lastStatementWasCaseError && !mCaseInsideControlFlow && + !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases; +} + +} // anonymous namespace + +bool ValidateSwitchStatementList(TBasicType switchType, + int shaderVersion, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc) +{ + return ValidateSwitch::validate(switchType, shaderVersion, diagnostics, statementList, loc); } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h index ddbefc5619..2d2dd70f78 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h @@ -7,46 +7,22 @@ #ifndef COMPILER_TRANSLATOR_VALIDATESWITCH_H_ #define COMPILER_TRANSLATOR_VALIDATESWITCH_H_ -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" -class TParseContext; - -class ValidateSwitch : public TIntermTraverser +namespace sh { - public: - // Check for errors and output messages any remaining errors on the context. - // Returns true if there are no errors. - static bool validate(TBasicType switchType, TParseContext *context, - TIntermAggregate *statementList, const TSourceLoc &loc); - - void visitSymbol(TIntermSymbol *) override; - void visitConstantUnion(TIntermConstantUnion *) override; - bool visitBinary(Visit, TIntermBinary *) override; - bool visitUnary(Visit, TIntermUnary *) override; - bool visitSelection(Visit visit, TIntermSelection *) override; - bool visitSwitch(Visit, TIntermSwitch *) override; - bool visitCase(Visit, TIntermCase *node) override; - bool visitAggregate(Visit, TIntermAggregate *) override; - bool visitLoop(Visit visit, TIntermLoop *) override; - bool visitBranch(Visit, TIntermBranch *) override; - - private: - ValidateSwitch(TBasicType switchType, TParseContext *context); +class TDiagnostics; +class TIntermBlock; - bool validateInternal(const TSourceLoc &loc); +// Check for errors and output error messages on the context. +// Returns true if there are no errors. +bool ValidateSwitchStatementList(TBasicType switchType, + int shaderVersion, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc); - TBasicType mSwitchType; - TParseContext *mContext; - bool mCaseTypeMismatch; - bool mFirstCaseFound; - bool mStatementBeforeCase; - bool mLastStatementWasCase; - int mControlFlowDepth; - bool mCaseInsideControlFlow; - int mDefaultCount; - std::set mCasesSigned; - std::set mCasesUnsigned; - bool mDuplicateCases; -}; +} // namespace sh -#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ +#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.cpp new file mode 100644 index 0000000000..9c36fcea78 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.cpp @@ -0,0 +1,174 @@ +// +// Copyright (c) 2002-2017 The ANGLE Project 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 ValidateVaryingLocations function checks if there exists location conflicts on shader +// varyings. +// + +#include "ValidateVaryingLocations.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) +{ + diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str()); +} + +int GetLocationCount(const TIntermSymbol *varying, bool ignoreVaryingArraySize) +{ + const auto &varyingType = varying->getType(); + if (varyingType.getStruct() != nullptr) + { + ASSERT(!varyingType.isArray()); + int totalLocation = 0; + for (const auto *field : varyingType.getStruct()->fields()) + { + const auto *fieldType = field->type(); + ASSERT(fieldType->getStruct() == nullptr && !fieldType->isArray()); + + totalLocation += fieldType->getSecondarySize(); + } + return totalLocation; + } + // [GL_OES_shader_io_blocks SPEC Chapter 4.4.1] + // Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation + // evaluation inputs all have an additional level of arrayness relative to other shader inputs + // and outputs. This outer array level is removed from the type before considering how many + // locations the type consumes. + else if (ignoreVaryingArraySize) + { + // Array-of-arrays cannot be inputs or outputs of a geometry shader. + // (GL_OES_geometry_shader SPEC issues(5)) + ASSERT(!varyingType.isArrayOfArrays()); + return varyingType.getSecondarySize(); + } + else + { + return varyingType.getSecondarySize() * static_cast(varyingType.getArraySizeProduct()); + } +} + +using VaryingVector = std::vector; + +void ValidateShaderInterface(TDiagnostics *diagnostics, + VaryingVector &varyingVector, + bool ignoreVaryingArraySize) +{ + // Location conflicts can only happen when there are two or more varyings in varyingVector. + if (varyingVector.size() <= 1) + { + return; + } + + std::map locationMap; + for (const TIntermSymbol *varying : varyingVector) + { + const int location = varying->getType().getLayoutQualifier().location; + ASSERT(location >= 0); + + const int elementCount = GetLocationCount(varying, ignoreVaryingArraySize); + for (int elementIndex = 0; elementIndex < elementCount; ++elementIndex) + { + const int offsetLocation = location + elementIndex; + if (locationMap.find(offsetLocation) != locationMap.end()) + { + std::stringstream strstr; + strstr << "'" << varying->getSymbol() + << "' conflicting location with previously defined '" + << locationMap[offsetLocation]->getSymbol() << "'"; + error(*varying, strstr.str().c_str(), diagnostics); + } + else + { + locationMap[offsetLocation] = varying; + } + } + } +} + +class ValidateVaryingLocationsTraverser : public TIntermTraverser +{ + public: + ValidateVaryingLocationsTraverser(GLenum shaderType); + void validate(TDiagnostics *diagnostics); + + private: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + + VaryingVector mInputVaryingsWithLocation; + VaryingVector mOutputVaryingsWithLocation; + GLenum mShaderType; +}; + +ValidateVaryingLocationsTraverser::ValidateVaryingLocationsTraverser(GLenum shaderType) + : TIntermTraverser(true, false, false), mShaderType(shaderType) +{ +} + +bool ValidateVaryingLocationsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + ASSERT(!sequence.empty()); + + const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode(); + if (symbol == nullptr) + { + return false; + } + + // Collect varyings that have explicit 'location' qualifiers. + const TQualifier qualifier = symbol->getQualifier(); + if (symbol->getType().getLayoutQualifier().location != -1) + { + if (IsVaryingIn(qualifier)) + { + mInputVaryingsWithLocation.push_back(symbol); + } + else if (IsVaryingOut(qualifier)) + { + mOutputVaryingsWithLocation.push_back(symbol); + } + } + + return false; +} + +bool ValidateVaryingLocationsTraverser::visitFunctionDefinition(Visit visit, + TIntermFunctionDefinition *node) +{ + // We stop traversing function definitions because varyings cannot be defined in a function. + return false; +} + +void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics) +{ + ASSERT(diagnostics); + + ValidateShaderInterface(diagnostics, mInputVaryingsWithLocation, + mShaderType == GL_GEOMETRY_SHADER_OES); + ValidateShaderInterface(diagnostics, mOutputVaryingsWithLocation, false); +} + +} // anonymous namespace + +bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType) +{ + ValidateVaryingLocationsTraverser varyingValidator(shaderType); + root->traverse(&varyingValidator); + int numErrorsBefore = diagnostics->numErrors(); + varyingValidator.validate(diagnostics); + return (diagnostics->numErrors() == numErrorsBefore); +} + +} // namespace sh \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.h b/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.h new file mode 100644 index 0000000000..1e53977c68 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateVaryingLocations.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-2017 The ANGLE Project 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 ValidateVaryingLocations function checks if there exists location conflicts on shader +// varyings. +// + +#ifndef COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_ +#define COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_ + +#include "GLSLANG/ShaderVars.h" + +namespace sh +{ + +class TIntermBlock; +class TDiagnostics; + +bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType); + +} // namespace sh + +#endif \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp deleted file mode 100644 index 3b6aa6a68e..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp +++ /dev/null @@ -1,673 +0,0 @@ -// -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "angle_gl.h" -#include "compiler/translator/SymbolTable.h" -#include "compiler/translator/VariableInfo.h" -#include "compiler/translator/util.h" -#include "common/utilities.h" - -namespace sh -{ - -namespace -{ - -BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) -{ - switch (blockStorage) - { - case EbsPacked: return BLOCKLAYOUT_PACKED; - case EbsShared: return BLOCKLAYOUT_SHARED; - case EbsStd140: return BLOCKLAYOUT_STANDARD; - default: UNREACHABLE(); return BLOCKLAYOUT_SHARED; - } -} - -void ExpandUserDefinedVariable(const ShaderVariable &variable, - const std::string &name, - const std::string &mappedName, - bool markStaticUse, - std::vector *expanded); - -void ExpandVariable(const ShaderVariable &variable, - const std::string &name, - const std::string &mappedName, - bool markStaticUse, - std::vector *expanded) -{ - if (variable.isStruct()) - { - if (variable.isArray()) - { - for (unsigned int elementIndex = 0; elementIndex < variable.elementCount(); - elementIndex++) - { - std::string lname = name + ::ArrayString(elementIndex); - std::string lmappedName = mappedName + ::ArrayString(elementIndex); - ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded); - } - } - else - { - ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded); - } - } - else - { - ShaderVariable expandedVar = variable; - - expandedVar.name = name; - expandedVar.mappedName = mappedName; - - // Mark all expanded fields as used if the parent is used - if (markStaticUse) - { - expandedVar.staticUse = true; - } - - if (expandedVar.isArray()) - { - expandedVar.name += "[0]"; - expandedVar.mappedName += "[0]"; - } - - expanded->push_back(expandedVar); - } -} - -void ExpandUserDefinedVariable(const ShaderVariable &variable, - const std::string &name, - const std::string &mappedName, - bool markStaticUse, - std::vector *expanded) -{ - ASSERT(variable.isStruct()); - - const std::vector &fields = variable.fields; - - for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) - { - const ShaderVariable &field = fields[fieldIndex]; - ExpandVariable(field, - name + "." + field.name, - mappedName + "." + field.mappedName, - markStaticUse, - expanded); - } -} - -template -VarT *FindVariable(const TString &name, - std::vector *infoList) -{ - // TODO(zmo): optimize this function. - for (size_t ii = 0; ii < infoList->size(); ++ii) - { - if ((*infoList)[ii].name.c_str() == name) - return &((*infoList)[ii]); - } - - return NULL; -} - -} - -CollectVariables::CollectVariables(std::vector *attribs, - std::vector *outputVariables, - std::vector *uniforms, - std::vector *varyings, - std::vector *interfaceBlocks, - ShHashFunction64 hashFunction, - const TSymbolTable &symbolTable) - : TIntermTraverser(true, false, false), - mAttribs(attribs), - mOutputVariables(outputVariables), - mUniforms(uniforms), - mVaryings(varyings), - mInterfaceBlocks(interfaceBlocks), - mDepthRangeAdded(false), - mPointCoordAdded(false), - mFrontFacingAdded(false), - mFragCoordAdded(false), - mInstanceIDAdded(false), - mPositionAdded(false), - mPointSizeAdded(false), - mLastFragDataAdded(false), - mFragColorAdded(false), - mFragDataAdded(false), - mFragDepthEXTAdded(false), - mFragDepthAdded(false), - mSecondaryFragColorEXTAdded(false), - mSecondaryFragDataEXTAdded(false), - mHashFunction(hashFunction), - mSymbolTable(symbolTable) -{ -} - -// We want to check whether a uniform/varying is statically used -// because we only count the used ones in packing computing. -// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count -// toward varying counting if they are statically used in a fragment -// shader. -void CollectVariables::visitSymbol(TIntermSymbol *symbol) -{ - ASSERT(symbol != NULL); - ShaderVariable *var = NULL; - const TString &symbolName = symbol->getSymbol(); - - if (IsVarying(symbol->getQualifier())) - { - var = FindVariable(symbolName, mVaryings); - } - else if (symbol->getType().getBasicType() == EbtInterfaceBlock) - { - 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()) - { - case EvqAttribute: - case EvqVertexIn: - var = FindVariable(symbolName, mAttribs); - break; - case EvqFragmentOut: - var = FindVariable(symbolName, mOutputVariables); - break; - case EvqUniform: - { - const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); - if (interfaceBlock) - { - InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); - ASSERT(namedBlock); - var = FindVariable(symbolName, &namedBlock->fields); - - // Set static use on the parent interface block here - namedBlock->staticUse = true; - } - else - { - var = FindVariable(symbolName, mUniforms); - } - - // It's an internal error to reference an undefined user uniform - ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var); - } - break; - case EvqFragCoord: - if (!mFragCoordAdded) - { - Varying info; - const char kName[] = "gl_FragCoord"; - 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; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mFragCoordAdded = true; - } - return; - case EvqFrontFacing: - if (!mFrontFacingAdded) - { - Varying info; - const char kName[] = "gl_FrontFacing"; - info.name = kName; - info.mappedName = kName; - info.type = GL_BOOL; - info.arraySize = 0; - info.precision = GL_NONE; - info.staticUse = true; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mFrontFacingAdded = true; - } - return; - case EvqPointCoord: - if (!mPointCoordAdded) - { - Varying info; - const char kName[] = "gl_PointCoord"; - info.name = kName; - info.mappedName = kName; - info.type = GL_FLOAT_VEC2; - info.arraySize = 0; - info.precision = GL_MEDIUM_FLOAT; // Defined by spec. - info.staticUse = true; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mPointCoordAdded = true; - } - return; - case EvqInstanceID: - if (!mInstanceIDAdded) - { - Attribute info; - const char kName[] = "gl_InstanceID"; - info.name = kName; - info.mappedName = kName; - info.type = GL_INT; - info.arraySize = 0; - info.precision = GL_HIGH_INT; // Defined by spec. - info.staticUse = true; - info.location = -1; - mAttribs->push_back(info); - mInstanceIDAdded = true; - } - return; - case EvqPosition: - if (!mPositionAdded) - { - Varying info; - const char kName[] = "gl_Position"; - info.name = kName; - info.mappedName = kName; - info.type = GL_FLOAT_VEC4; - info.arraySize = 0; - info.precision = GL_HIGH_FLOAT; // Defined by spec. - info.staticUse = true; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mPositionAdded = true; - } - return; - case EvqPointSize: - if (!mPointSizeAdded) - { - Varying info; - const char kName[] = "gl_PointSize"; - info.name = kName; - info.mappedName = kName; - info.type = GL_FLOAT; - info.arraySize = 0; - info.precision = GL_MEDIUM_FLOAT; // Defined by spec. - info.staticUse = true; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mPointSizeAdded = true; - } - return; - case EvqLastFragData: - if (!mLastFragDataAdded) - { - Varying info; - const char kName[] = "gl_LastFragData"; - info.name = kName; - info.mappedName = kName; - info.type = GL_FLOAT_VEC4; - info.arraySize = static_cast(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst(); - info.precision = GL_MEDIUM_FLOAT; // Defined by spec. - info.staticUse = true; - info.isInvariant = mSymbolTable.isVaryingInvariant(kName); - mVaryings->push_back(info); - mLastFragDataAdded = true; - } - return; - 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; - } - } - if (var) - { - var->staticUse = true; - } -} - -class NameHashingTraverser : public GetVariableTraverser -{ - public: - NameHashingTraverser(ShHashFunction64 hashFunction, - const TSymbolTable &symbolTable) - : GetVariableTraverser(symbolTable), - mHashFunction(hashFunction) - {} - - private: - void visitVariable(ShaderVariable *variable) override - { - TString stringName = TString(variable->name.c_str()); - variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str(); - } - - ShHashFunction64 mHashFunction; -}; - -// Attributes, which cannot have struct fields, are a special case -template <> -void CollectVariables::visitVariable(const TIntermSymbol *variable, - std::vector *infoList) const -{ - ASSERT(variable); - const TType &type = variable->getType(); - ASSERT(!type.getStruct()); - - Attribute 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 -{ - 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 -{ - InterfaceBlock interfaceBlock; - const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock(); - ASSERT(blockType); - - interfaceBlock.name = blockType->name().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 - for (const TField *field : blockType->fields()) - { - const TType &fieldType = *field->type(); - - NameHashingTraverser traverser(mHashFunction, mSymbolTable); - traverser.traverse(fieldType, field->name(), &interfaceBlock.fields); - - interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); - } - - infoList->push_back(interfaceBlock); -} - -template -void CollectVariables::visitVariable(const TIntermSymbol *variable, - std::vector *infoList) const -{ - NameHashingTraverser traverser(mHashFunction, mSymbolTable); - traverser.traverse(variable->getType(), variable->getSymbol(), infoList); -} - -template -void CollectVariables::visitInfoList(const TIntermSequence &sequence, - std::vector *infoList) const -{ - for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++) - { - const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode(); - // The only case in which the sequence will not contain a - // TIntermSymbol node is initialization. It will contain a - // TInterBinary node in that case. Since attributes, uniforms, - // and varyings cannot be initialized in a shader, we must have - // only TIntermSymbol nodes in the sequence. - ASSERT(variable != NULL); - visitVariable(variable, infoList); - } -} - -bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node) -{ - bool visitChildren = true; - - switch (node->getOp()) - { - case EOpDeclaration: - { - const TIntermSequence &sequence = *(node->getSequence()); - ASSERT(!sequence.empty()); - - const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); - TQualifier qualifier = typedNode.getQualifier(); - - if (typedNode.getBasicType() == EbtInterfaceBlock) - { - visitInfoList(sequence, mInterfaceBlocks); - visitChildren = false; - } - else if (qualifier == EvqAttribute || qualifier == EvqVertexIn || - qualifier == EvqFragmentOut || qualifier == EvqUniform || - IsVarying(qualifier)) - { - switch (qualifier) - { - case EvqAttribute: - case EvqVertexIn: - visitInfoList(sequence, mAttribs); - break; - case EvqFragmentOut: - visitInfoList(sequence, mOutputVariables); - break; - case EvqUniform: - visitInfoList(sequence, mUniforms); - break; - default: - visitInfoList(sequence, mVaryings); - break; - } - - visitChildren = false; - } - break; - } - default: break; - } - - return visitChildren; -} - -bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode) -{ - if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) - { - // NOTE: we do not determine static use for individual blocks of an array - TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); - ASSERT(blockNode); - - TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); - ASSERT(constantUnion); - - const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock(); - InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); - ASSERT(namedBlock); - namedBlock->staticUse = true; - - unsigned int fieldIndex = constantUnion->getUConst(0); - ASSERT(fieldIndex < namedBlock->fields.size()); - namedBlock->fields[fieldIndex].staticUse = true; - return false; - } - - return true; -} - -void ExpandUniforms(const std::vector &compact, - std::vector *expanded) -{ - for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++) - { - const ShaderVariable &variable = compact[variableIndex]; - ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded); - } -} - -} diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h deleted file mode 100644 index 9498e9b3a0..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_VARIABLEINFO_H_ -#define COMPILER_TRANSLATOR_VARIABLEINFO_H_ - -#include - -#include "compiler/translator/IntermNode.h" - -class TSymbolTable; - -namespace sh -{ - -// Traverses intermediate tree to collect all attributes, uniforms, varyings. -class CollectVariables : public TIntermTraverser -{ - public: - CollectVariables(std::vector *attribs, - std::vector *outputVariables, - std::vector *uniforms, - std::vector *varyings, - std::vector *interfaceBlocks, - ShHashFunction64 hashFunction, - const TSymbolTable &symbolTable); - - void visitSymbol(TIntermSymbol *symbol) override; - bool visitAggregate(Visit, TIntermAggregate *node) override; - bool visitBinary(Visit visit, TIntermBinary *binaryNode) override; - - private: - template - void visitVariable(const TIntermSymbol *variable, std::vector *infoList) const; - - template - void visitInfoList(const TIntermSequence &sequence, std::vector *infoList) const; - - std::vector *mAttribs; - std::vector *mOutputVariables; - std::vector *mUniforms; - std::vector *mVaryings; - std::vector *mInterfaceBlocks; - - std::map mInterfaceBlockFields; - - bool mDepthRangeAdded; - bool mPointCoordAdded; - bool mFrontFacingAdded; - bool mFragCoordAdded; - - bool mInstanceIDAdded; - bool mPositionAdded; - bool mPointSizeAdded; - bool mLastFragDataAdded; - bool mFragColorAdded; - bool mFragDataAdded; - bool mFragDepthEXTAdded; - bool mFragDepthAdded; - bool mSecondaryFragColorEXTAdded; - bool mSecondaryFragDataEXTAdded; - - ShHashFunction64 mHashFunction; - - const TSymbolTable &mSymbolTable; -}; - -// Expand struct uniforms to flattened lists of split variables -void ExpandUniforms(const std::vector &compact, - std::vector *expanded); - -} - -#endif // COMPILER_TRANSLATOR_VARIABLEINFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp b/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp index e69052162a..6dd396ff02 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.cpp @@ -3,6 +3,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// Check whether variables fit within packing limits according to the packing rules from the GLSL ES +// 1.00.17 spec, Appendix A, section 7. #include @@ -11,259 +13,401 @@ #include "compiler/translator/VariablePacker.h" #include "common/utilities.h" -int VariablePacker::GetNumComponentsPerRow(sh::GLenum type) +namespace sh { - switch (type) + +namespace +{ + +// Expand the variable so that struct variables are split into their individual fields. +// Will not set the mappedName or staticUse fields on the expanded variables. +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + std::vector *expanded); + +void ExpandStructVariable(const ShaderVariable &variable, + const std::string &name, + std::vector *expanded) +{ + ASSERT(variable.isStruct()); + + const std::vector &fields = variable.fields; + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) { - case GL_FLOAT_MAT4: - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT2x4: - case GL_FLOAT_MAT3x4: - case GL_FLOAT_MAT4x2: - case GL_FLOAT_MAT4x3: - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_BOOL_VEC4: - case GL_UNSIGNED_INT_VEC4: - return 4; - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT2x3: - case GL_FLOAT_MAT3x2: - case GL_FLOAT_VEC3: - case GL_INT_VEC3: - case GL_BOOL_VEC3: - case GL_UNSIGNED_INT_VEC3: - return 3; - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - case GL_BOOL_VEC2: - case GL_UNSIGNED_INT_VEC2: - return 2; - default: - ASSERT(gl::VariableComponentCount(type) == 1); - return 1; + const ShaderVariable &field = fields[fieldIndex]; + ExpandVariable(field, name + "." + field.name, expanded); } } -int VariablePacker::GetNumRows(sh::GLenum type) +void ExpandStructArrayVariable(const ShaderVariable &variable, + unsigned int arrayNestingIndex, + const std::string &name, + std::vector *expanded) { - switch (type) + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) { - case GL_FLOAT_MAT4: - case GL_FLOAT_MAT2x4: - case GL_FLOAT_MAT3x4: - case GL_FLOAT_MAT4x3: - case GL_FLOAT_MAT4x2: - return 4; - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT2x3: - case GL_FLOAT_MAT3x2: - return 3; - case GL_FLOAT_MAT2: - return 2; - default: - ASSERT(gl::VariableRowCount(type) == 1); - return 1; + const std::string elementName = name + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < variable.arraySizes.size()) + { + ExpandStructArrayVariable(variable, arrayNestingIndex + 1u, elementName, expanded); + } + else + { + ExpandStructVariable(variable, elementName, expanded); + } } } +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + std::vector *expanded) +{ + if (variable.isStruct()) + { + if (variable.isArray()) + { + ExpandStructArrayVariable(variable, 0u, name, expanded); + } + else + { + ExpandStructVariable(variable, name, expanded); + } + } + else + { + ShaderVariable expandedVar = variable; + expandedVar.name = name; + + expanded->push_back(expandedVar); + } +} + +int GetVariablePackingRows(const ShaderVariable &variable) +{ + return GetTypePackingRows(variable.type) * variable.getArraySizeProduct(); +} + +class VariablePacker +{ + public: + bool checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors, + std::vector *variables); + + private: + static const int kNumColumns = 4; + static const unsigned kColumnMask = (1 << kNumColumns) - 1; + + unsigned makeColumnFlags(int column, int numComponentsPerRow); + void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); + bool searchColumn(int column, int numRows, int *destRow, int *destSize); + + int topNonFullRow_; + int bottomNonFullRow_; + int maxRows_; + std::vector rows_; +}; + struct TVariableInfoComparer { bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const { int lhsSortOrder = gl::VariableSortOrder(lhs.type); int rhsSortOrder = gl::VariableSortOrder(rhs.type); - if (lhsSortOrder != rhsSortOrder) { + if (lhsSortOrder != rhsSortOrder) + { return lhsSortOrder < rhsSortOrder; } // Sort by largest first. - return lhs.arraySize > rhs.arraySize; + return lhs.getArraySizeProduct() > rhs.getArraySizeProduct(); } }; unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) { - return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & - kColumnMask) >> column; + return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column; } void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) { unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); - for (int r = 0; r < numRows; ++r) { + for (int r = 0; r < numRows; ++r) + { int row = topRow + r; ASSERT((rows_[row] & columnFlags) == 0); rows_[row] |= columnFlags; } } -bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize) +bool VariablePacker::searchColumn(int column, int numRows, int *destRow, int *destSize) { ASSERT(destRow); - for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; - ++topNonFullRow_) { + for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; ++topNonFullRow_) + { } - for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; - --bottomNonFullRow_) { + for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; --bottomNonFullRow_) + { } - if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) { + if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) + { return false; } unsigned columnFlags = makeColumnFlags(column, 1); - int topGoodRow = 0; - int smallestGoodTop = -1; + int topGoodRow = 0; + int smallestGoodTop = -1; int smallestGoodSize = maxRows_ + 1; - int bottomRow = bottomNonFullRow_ + 1; - bool found = false; - for (int row = topNonFullRow_; row <= bottomRow; ++row) { + int bottomRow = bottomNonFullRow_ + 1; + bool found = false; + for (int row = topNonFullRow_; row <= bottomRow; ++row) + { bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; - if (rowEmpty) { - if (!found) { + if (rowEmpty) + { + if (!found) + { topGoodRow = row; - found = true; + found = true; } - } else { - if (found) { + } + else + { + if (found) + { int size = row - topGoodRow; - if (size >= numRows && size < smallestGoodSize) { + if (size >= numRows && size < smallestGoodSize) + { smallestGoodSize = size; - smallestGoodTop = topGoodRow; + smallestGoodTop = topGoodRow; } } found = false; } } - if (smallestGoodTop < 0) { + if (smallestGoodTop < 0) + { return false; } *destRow = smallestGoodTop; - if (destSize) { + if (destSize) + { *destSize = smallestGoodSize; } return true; } -template -bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors, - const std::vector &in_variables) +bool VariablePacker::checkExpandedVariablesWithinPackingLimits( + unsigned int maxVectors, + std::vector *variables) { ASSERT(maxVectors > 0); - maxRows_ = maxVectors; - topNonFullRow_ = 0; + maxRows_ = maxVectors; + topNonFullRow_ = 0; bottomNonFullRow_ = maxRows_ - 1; - std::vector variables(in_variables); // Check whether each variable fits in the available vectors. - for (size_t i = 0; i < variables.size(); i++) { - const sh::ShaderVariable &variable = variables[i]; - if (variable.elementCount() > maxVectors / GetNumRows(variable.type)) { + for (const sh::ShaderVariable &variable : *variables) + { + // Structs should have been expanded before reaching here. + ASSERT(!variable.isStruct()); + if (variable.getArraySizeProduct() > maxVectors / GetTypePackingRows(variable.type)) + { return false; } } // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific // order by type, then by size of array, largest first. - std::sort(variables.begin(), variables.end(), TVariableInfoComparer()); + std::sort(variables->begin(), variables->end(), TVariableInfoComparer()); rows_.clear(); rows_.resize(maxVectors, 0); // Packs the 4 column variables. size_t ii = 0; - for (; ii < variables.size(); ++ii) { - const sh::ShaderVariable &variable = variables[ii]; - if (GetNumComponentsPerRow(variable.type) != 4) { + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 4) + { break; } - topNonFullRow_ += GetNumRows(variable.type) * variable.elementCount(); + topNonFullRow_ += GetVariablePackingRows(variable); } - if (topNonFullRow_ > maxRows_) { + if (topNonFullRow_ > maxRows_) + { return false; } // Packs the 3 column variables. int num3ColumnRows = 0; - for (; ii < variables.size(); ++ii) { - const sh::ShaderVariable &variable = variables[ii]; - if (GetNumComponentsPerRow(variable.type) != 3) { + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 3) + { break; } - num3ColumnRows += GetNumRows(variable.type) * variable.elementCount(); + num3ColumnRows += GetVariablePackingRows(variable); } - if (topNonFullRow_ + num3ColumnRows > maxRows_) { + if (topNonFullRow_ + num3ColumnRows > maxRows_) + { return false; } fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); // Packs the 2 column variables. - int top2ColumnRow = topNonFullRow_ + num3ColumnRows; - int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; + int top2ColumnRow = topNonFullRow_ + num3ColumnRows; + int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; int rowsAvailableInColumns01 = twoColumnRowsAvailable; int rowsAvailableInColumns23 = twoColumnRowsAvailable; - for (; ii < variables.size(); ++ii) { - const sh::ShaderVariable &variable = variables[ii]; - if (GetNumComponentsPerRow(variable.type) != 2) { + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 2) + { break; } - int numRows = GetNumRows(variable.type) * variable.elementCount(); - if (numRows <= rowsAvailableInColumns01) { + int numRows = GetVariablePackingRows(variable); + if (numRows <= rowsAvailableInColumns01) + { rowsAvailableInColumns01 -= numRows; - } else if (numRows <= rowsAvailableInColumns23) { + } + else if (numRows <= rowsAvailableInColumns23) + { rowsAvailableInColumns23 -= numRows; - } else { + } + else + { return false; } } - int numRowsUsedInColumns01 = - twoColumnRowsAvailable - rowsAvailableInColumns01; - int numRowsUsedInColumns23 = - twoColumnRowsAvailable - rowsAvailableInColumns23; + int numRowsUsedInColumns01 = twoColumnRowsAvailable - rowsAvailableInColumns01; + int numRowsUsedInColumns23 = twoColumnRowsAvailable - rowsAvailableInColumns23; fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); - fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, - 2, 2); + fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 2, 2); // Packs the 1 column variables. - for (; ii < variables.size(); ++ii) { - const sh::ShaderVariable &variable = variables[ii]; - ASSERT(1 == GetNumComponentsPerRow(variable.type)); - int numRows = GetNumRows(variable.type) * variable.elementCount(); + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + ASSERT(1 == GetTypePackingComponentsPerRow(variable.type)); + int numRows = GetVariablePackingRows(variable); int smallestColumn = -1; - int smallestSize = maxRows_ + 1; - int topRow = -1; - for (int column = 0; column < kNumColumns; ++column) { - int row = 0; + int smallestSize = maxRows_ + 1; + int topRow = -1; + for (int column = 0; column < kNumColumns; ++column) + { + int row = 0; int size = 0; - if (searchColumn(column, numRows, &row, &size)) { - if (size < smallestSize) { - smallestSize = size; + if (searchColumn(column, numRows, &row, &size)) + { + if (size < smallestSize) + { + smallestSize = size; smallestColumn = column; - topRow = row; + topRow = row; } } } - if (smallestColumn < 0) { + if (smallestColumn < 0) + { return false; } fillColumns(topRow, numRows, smallestColumn, 1); } - ASSERT(variables.size() == ii); + ASSERT(variables->size() == ii); return true; } -// Instantiate all possible variable packings -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector &); +} // anonymous namespace + +int GetTypePackingComponentsPerRow(sh::GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + case GL_UNSIGNED_INT_VEC4: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + case GL_UNSIGNED_INT_VEC3: + return 3; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + case GL_UNSIGNED_INT_VEC2: + return 2; + default: + ASSERT(gl::VariableComponentCount(type) == 1); + return 1; + } +} + +int GetTypePackingRows(sh::GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_MAT4x2: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + return 3; + case GL_FLOAT_MAT2: + return 2; + default: + ASSERT(gl::VariableRowCount(type) == 1); + return 1; + } +} + +template +bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector &variables) +{ + VariablePacker packer; + std::vector expandedVariables; + for (const ShaderVariable &variable : variables) + { + ExpandVariable(variable, variable.name, &expandedVariables); + } + return packer.checkExpandedVariablesWithinPackingLimits(maxVectors, &expandedVariables); +} + +template bool CheckVariablesInPackingLimits( + unsigned int maxVectors, + const std::vector &variables); +template bool CheckVariablesInPackingLimits(unsigned int maxVectors, + const std::vector &variables); + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h index 9c80eea618..36b2104cd0 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h @@ -3,39 +3,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // +// Check whether variables fit within packing limits according to the packing rules from the GLSL ES +// 1.00.17 spec, Appendix A, section 7. #ifndef COMPILER_TRANSLATOR_VARIABLEPACKER_H_ #define COMPILER_TRANSLATOR_VARIABLEPACKER_H_ #include -#include "compiler/translator/VariableInfo.h" -class VariablePacker { - public: - // Returns true if the passed in variables pack in maxVectors following - // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. - template - bool CheckVariablesWithinPackingLimits(unsigned int maxVectors, - const std::vector &in_variables); +#include - // Gets how many components in a row a data type takes. - static int GetNumComponentsPerRow(sh::GLenum type); +namespace sh +{ - // Gets how many rows a data type takes. - static int GetNumRows(sh::GLenum type); +// Gets how many components in a row a data type takes. +int GetTypePackingComponentsPerRow(sh::GLenum type); - private: - static const int kNumColumns = 4; - static const unsigned kColumnMask = (1 << kNumColumns) - 1; +// Gets how many rows a data type takes. +int GetTypePackingRows(sh::GLenum type); - unsigned makeColumnFlags(int column, int numComponentsPerRow); - void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); - bool searchColumn(int column, int numRows, int* destRow, int* destSize); +// Returns true if the passed in variables pack in maxVectors. +// T should be ShaderVariable or one of the subclasses of ShaderVariable. +template +bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector &variables); - int topNonFullRow_; - int bottomNonFullRow_; - int maxRows_; - std::vector rows_; -}; +} // namespace sh -#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ +#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.cpp b/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.cpp new file mode 100644 index 0000000000..1e79a60991 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.cpp @@ -0,0 +1,284 @@ +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// VectorizeVectorScalarArithmetic.cpp: Turn some arithmetic operations that operate on a float +// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary +// operations inside vector constructors are also turned into vector operations. +// +// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA +// driver version 387.92. It works around the most common occurrences of the bug. + +#include "compiler/translator/VectorizeVectorScalarArithmetic.h" + +#include + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class VectorizeVectorScalarArithmeticTraverser : public TIntermTraverser +{ + public: + VectorizeVectorScalarArithmeticTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), mReplaced(false) + { + } + + bool didReplaceScalarsWithVectors() { return mReplaced; } + void nextIteration() + { + mReplaced = false; + mModifiedBlocks.clear(); + } + + protected: + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + private: + // These helpers should only be called from visitAggregate when visiting a constructor. + // argBinary is the only argument of the constructor. + void replaceMathInsideConstructor(TIntermAggregate *node, TIntermBinary *argBinary); + void replaceAssignInsideConstructor(const TIntermAggregate *node, + const TIntermBinary *argBinary); + + static TIntermTyped *Vectorize(TIntermTyped *node, + TType vectorType, + TIntermTraverser::OriginalNode *originalNodeFate); + + bool mReplaced; + std::set mModifiedBlocks; +}; + +TIntermTyped *VectorizeVectorScalarArithmeticTraverser::Vectorize( + TIntermTyped *node, + TType vectorType, + TIntermTraverser::OriginalNode *originalNodeFate) +{ + ASSERT(node->isScalar()); + vectorType.setQualifier(EvqTemporary); + TIntermSequence vectorConstructorArgs; + vectorConstructorArgs.push_back(node); + TIntermAggregate *vectorized = + TIntermAggregate::CreateConstructor(vectorType, &vectorConstructorArgs); + TIntermTyped *vectorizedFolded = vectorized->fold(nullptr); + if (originalNodeFate != nullptr) + { + if (vectorizedFolded != vectorized) + { + *originalNodeFate = OriginalNode::IS_DROPPED; + } + else + { + *originalNodeFate = OriginalNode::BECOMES_CHILD; + } + } + return vectorizedFolded; +} + +bool VectorizeVectorScalarArithmeticTraverser::visitBinary(Visit /*visit*/, TIntermBinary *node) +{ + TIntermTyped *left = node->getLeft(); + TIntermTyped *right = node->getRight(); + ASSERT(left); + ASSERT(right); + switch (node->getOp()) + { + case EOpAdd: + case EOpAddAssign: + // Only these specific ops are necessary to turn into vector ops. + break; + default: + return true; + } + if (node->getBasicType() != EbtFloat) + { + // Only float ops have reproduced the bug. + return true; + } + if (left->isScalar() && right->isVector()) + { + ASSERT(!node->isAssignment()); + ASSERT(!right->isArray()); + OriginalNode originalNodeFate; + TIntermTyped *leftVectorized = Vectorize(left, right->getType(), &originalNodeFate); + queueReplacementWithParent(node, left, leftVectorized, originalNodeFate); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere + // in the tree may still be replaced. + return false; + } + else if (left->isVector() && right->isScalar()) + { + OriginalNode originalNodeFate; + TIntermTyped *rightVectorized = Vectorize(right, left->getType(), &originalNodeFate); + queueReplacementWithParent(node, right, rightVectorized, originalNodeFate); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere + // in the tree may still be replaced. + return false; + } + return true; +} + +void VectorizeVectorScalarArithmeticTraverser::replaceMathInsideConstructor( + TIntermAggregate *node, + TIntermBinary *argBinary) +{ + // Turn: + // a * b + // into: + // gvec(a) * gvec(b) + + TIntermTyped *left = argBinary->getLeft(); + TIntermTyped *right = argBinary->getRight(); + ASSERT(left->isScalar() && right->isScalar()); + + TType leftVectorizedType = left->getType(); + leftVectorizedType.setPrimarySize(static_cast(node->getType().getNominalSize())); + TIntermTyped *leftVectorized = Vectorize(left, leftVectorizedType, nullptr); + TType rightVectorizedType = right->getType(); + rightVectorizedType.setPrimarySize( + static_cast(node->getType().getNominalSize())); + TIntermTyped *rightVectorized = Vectorize(right, rightVectorizedType, nullptr); + + TIntermBinary *newArg = new TIntermBinary(argBinary->getOp(), leftVectorized, rightVectorized); + queueReplacementWithParent(node, argBinary, newArg, OriginalNode::IS_DROPPED); +} + +void VectorizeVectorScalarArithmeticTraverser::replaceAssignInsideConstructor( + const TIntermAggregate *node, + const TIntermBinary *argBinary) +{ + // Turn: + // gvec(a *= b); + // into: + // // This is inserted into the parent block: + // gvec s0 = gvec(a); + // + // // This goes where the gvec constructor used to be: + // ((s0 *= b, a = s0.x), s0); + + TIntermTyped *left = argBinary->getLeft(); + TIntermTyped *right = argBinary->getRight(); + ASSERT(left->isScalar() && right->isScalar()); + ASSERT(!left->hasSideEffects()); + + TType vecType = node->getType(); + vecType.setQualifier(EvqTemporary); + + nextTemporaryId(); + // gvec s0 = gvec(a); + // s0 is called "tempAssignmentTarget" below. + TIntermTyped *tempAssignmentTargetInitializer = Vectorize(left->deepCopy(), vecType, nullptr); + TIntermDeclaration *tempAssignmentTargetDeclaration = + createTempInitDeclaration(tempAssignmentTargetInitializer); + + // s0 *= b + TOperator compoundAssignmentOp = argBinary->getOp(); + if (compoundAssignmentOp == EOpMulAssign) + { + compoundAssignmentOp = EOpVectorTimesScalarAssign; + } + TIntermBinary *replacementCompoundAssignment = + new TIntermBinary(compoundAssignmentOp, createTempSymbol(vecType), right->deepCopy()); + + // s0.x + TVector swizzleXOffset; + swizzleXOffset.push_back(0); + TIntermSwizzle *tempAssignmentTargetX = + new TIntermSwizzle(createTempSymbol(vecType), swizzleXOffset); + // a = s0.x + TIntermBinary *replacementAssignBackToTarget = + new TIntermBinary(EOpAssign, left->deepCopy(), tempAssignmentTargetX); + + // s0 *= b, a = s0.x + TIntermBinary *replacementSequenceLeft = + new TIntermBinary(EOpComma, replacementCompoundAssignment, replacementAssignBackToTarget); + // (s0 *= b, a = s0.x), s0 + TIntermBinary *replacementSequence = + new TIntermBinary(EOpComma, replacementSequenceLeft, createTempSymbol(vecType)); + + insertStatementInParentBlock(tempAssignmentTargetDeclaration); + queueReplacement(replacementSequence, OriginalNode::IS_DROPPED); +} + +bool VectorizeVectorScalarArithmeticTraverser::visitAggregate(Visit /*visit*/, + TIntermAggregate *node) +{ + // Transform scalar binary expressions inside vector constructors. + if (!node->isConstructor() || !node->isVector() || node->getSequence()->size() != 1) + { + return true; + } + TIntermTyped *argument = node->getSequence()->back()->getAsTyped(); + ASSERT(argument); + if (!argument->isScalar() || argument->getBasicType() != EbtFloat) + { + return true; + } + TIntermBinary *argBinary = argument->getAsBinaryNode(); + if (!argBinary) + { + return true; + } + + // Only specific ops are necessary to change. + switch (argBinary->getOp()) + { + case EOpMul: + case EOpDiv: + { + replaceMathInsideConstructor(node, argBinary); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes + // elsewhere in the tree may still be replaced. + return false; + } + case EOpMulAssign: + case EOpDivAssign: + { + // The case where the left side has side effects is too complicated to deal with, so we + // leave that be. + if (!argBinary->getLeft()->hasSideEffects()) + { + const TIntermBlock *parentBlock = getParentBlock(); + // We can't do more than one insertion to the same block on the same traversal. + if (mModifiedBlocks.find(parentBlock) == mModifiedBlocks.end()) + { + replaceAssignInsideConstructor(node, argBinary); + mModifiedBlocks.insert(parentBlock); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. + // However, nodes elsewhere in the tree may still be replaced. + return false; + } + } + break; + } + default: + return true; + } + return true; +} + +} // anonymous namespace + +void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable) +{ + VectorizeVectorScalarArithmeticTraverser traverser(symbolTable); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + traverser.updateTree(); + } while (traverser.didReplaceScalarsWithVectors()); +} + +} // namespace sh \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.h b/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.h new file mode 100644 index 0000000000..69f092e039 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/VectorizeVectorScalarArithmetic.h @@ -0,0 +1,25 @@ +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// VectorizeVectorScalarArithmetic.h: Turn some arithmetic operations that operate on a float +// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary +// operations inside vector constructors are also turned into vector operations. +// +// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA +// driver version 387.92. It works around the most common occurrences of the bug. + +#ifndef COMPILER_TRANSLATOR_VECTORIZEVECTORSCALARARITHMETIC_H_ +#define COMPILER_TRANSLATOR_VECTORIZEVECTORSCALARARITHMETIC_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VECTORIZEVECTORSCALARARITHMETIC_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp index c8718daa10..81688765b8 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp @@ -6,22 +6,40 @@ #include "compiler/translator/VersionGLSL.h" +#include "angle_gl.h" + +namespace sh +{ + 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; + 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; } } @@ -42,9 +60,7 @@ int ShaderOutputTypeToGLSLVersion(ShShaderOutput output) // GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that // are built-in types, entire structures or arrays... are all l-values." // -TVersionGLSL::TVersionGLSL(sh::GLenum type, - const TPragma &pragma, - ShShaderOutput output) +TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output) : TIntermTraverser(true, false, false) { mVersion = ShaderOutputTypeToGLSLVersion(output); @@ -52,6 +68,10 @@ TVersionGLSL::TVersionGLSL(sh::GLenum type, { ensureVersionIsAtLeast(GLSL_VERSION_120); } + if (type == GL_COMPUTE_SHADER) + { + ensureVersionIsAtLeast(GLSL_VERSION_430); + } } void TVersionGLSL::visitSymbol(TIntermSymbol *node) @@ -62,75 +82,57 @@ void TVersionGLSL::visitSymbol(TIntermSymbol *node) } } -bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node) +bool TVersionGLSL::visitDeclaration(Visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + if (sequence.front()->getAsTyped()->getType().isInvariant()) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + } + return true; +} + +bool TVersionGLSL::visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node) { - bool visitChildren = true; + ensureVersionIsAtLeast(GLSL_VERSION_120); + return true; +} - switch (node->getOp()) +bool TVersionGLSL::visitFunctionPrototype(Visit, TIntermFunctionPrototype *node) +{ + const TIntermSequence ¶ms = *(node->getSequence()); + for (TIntermSequence::const_iterator iter = params.begin(); iter != params.end(); ++iter) { - case EOpSequence: - // We need to visit sequence children to get to global or inner scope. - visitChildren = true; - break; - case EOpDeclaration: + const TIntermTyped *param = (*iter)->getAsTyped(); + if (param->isArray()) { - const TIntermSequence &sequence = *(node->getSequence()); - if (sequence.front()->getAsTyped()->getType().isInvariant()) + TQualifier qualifier = param->getQualifier(); + if ((qualifier == EvqOut) || (qualifier == EvqInOut)) { ensureVersionIsAtLeast(GLSL_VERSION_120); + break; } - break; } - case EOpInvariantDeclaration: - ensureVersionIsAtLeast(GLSL_VERSION_120); - break; - case EOpParameters: - { - const TIntermSequence ¶ms = *(node->getSequence()); - for (TIntermSequence::const_iterator iter = params.begin(); - iter != params.end(); ++iter) - { - const TIntermTyped *param = (*iter)->getAsTyped(); - if (param->isArray()) - { - TQualifier qualifier = param->getQualifier(); - if ((qualifier == EvqOut) || (qualifier == EvqInOut)) - { - ensureVersionIsAtLeast(GLSL_VERSION_120); - break; - } - } - } - // Fully processed. No need to visit children. - visitChildren = false; - break; - } - case EOpConstructMat2: - case EOpConstructMat2x3: - case EOpConstructMat2x4: - case EOpConstructMat3x2: - case EOpConstructMat3: - case EOpConstructMat3x4: - case EOpConstructMat4x2: - case EOpConstructMat4x3: - case EOpConstructMat4: + } + // Fully processed. No need to visit children. + return false; +} + +bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node) +{ + if (node->getOp() == EOpConstruct && node->getType().isMatrix()) + { + const TIntermSequence &sequence = *(node->getSequence()); + if (sequence.size() == 1) { - const TIntermSequence &sequence = *(node->getSequence()); - if (sequence.size() == 1) + TIntermTyped *typed = sequence.front()->getAsTyped(); + if (typed && typed->isMatrix()) { - TIntermTyped *typed = sequence.front()->getAsTyped(); - if (typed && typed->isMatrix()) - { - ensureVersionIsAtLeast(GLSL_VERSION_120); - } + ensureVersionIsAtLeast(GLSL_VERSION_120); } - break; } - default: - break; } - - return visitChildren; + return true; } void TVersionGLSL::ensureVersionIsAtLeast(int version) @@ -138,3 +140,4 @@ void TVersionGLSL::ensureVersionIsAtLeast(int version) mVersion = std::max(version, mVersion); } +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h index c41069d42d..8b82eb9615 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h @@ -7,10 +7,13 @@ #ifndef COMPILER_TRANSLATOR_VERSIONGLSL_H_ #define COMPILER_TRANSLATOR_VERSIONGLSL_H_ -#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/Pragma.h" +namespace sh +{ + static const int GLSL_VERSION_110 = 110; static const int GLSL_VERSION_120 = 120; static const int GLSL_VERSION_130 = 130; @@ -56,8 +59,11 @@ class TVersionGLSL : public TIntermTraverser // Else 110 is returned. int getVersion() const { return mVersion; } - void visitSymbol(TIntermSymbol *) override; - bool visitAggregate(Visit, TIntermAggregate *) override; + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node) override; + bool visitFunctionPrototype(Visit, TIntermFunctionPrototype *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; private: void ensureVersionIsAtLeast(int version); @@ -65,4 +71,6 @@ class TVersionGLSL : public TIntermTraverser int mVersion; }; +} // namespace sh + #endif // COMPILER_TRANSLATOR_VERSIONGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.cpp b/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.cpp new file mode 100644 index 0000000000..85a11c998d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.cpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped +// variables there to make the AST compatible with HLSL output. +// +// switch (init) +// { +// case 0: +// float f; +// default: +// f = 1.0; +// } +// +// becomes +// +// { +// float f; +// switch (init) +// { +// case 0: +// default: +// f = 1.0; +// } +// } + +#include "compiler/translator/WrapSwitchStatementsInBlocks.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser +{ + public: + WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false), mDidWrap(false) + { + } + + bool visitSwitch(Visit visit, TIntermSwitch *node) override; + + bool didWrap() const { return mDidWrap; } + + private: + bool mDidWrap; +}; + +bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node) +{ + std::vector declarations; + TIntermSequence *statementList = node->getStatementList()->getSequence(); + for (TIntermNode *statement : *statementList) + { + TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode(); + if (asDeclaration) + { + declarations.push_back(asDeclaration); + } + } + if (declarations.empty()) + { + // We don't need to wrap the switch if it doesn't contain declarations as its direct + // descendants. + return true; + } + + TIntermBlock *wrapperBlock = new TIntermBlock(); + for (TIntermDeclaration *declaration : declarations) + { + // SeparateDeclarations should have already been run. + ASSERT(declaration->getSequence()->size() == 1); + + TIntermDeclaration *declarationInBlock = new TIntermDeclaration(); + TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode(); + if (declaratorAsSymbol) + { + // This is a simple declaration like: "float f;" + // Remove the declaration from inside the switch and put it in the wrapping block. + TIntermSequence emptyReplacement; + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry( + node->getStatementList(), declaration, emptyReplacement)); + + declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy()); + } + else + { + // This is an init declaration like: "float f = 0.0;" + // Change the init declaration inside the switch into an assignment and put a plain + // declaration in the wrapping block. + TIntermBinary *declaratorAsBinary = + declaration->getSequence()->at(0)->getAsBinaryNode(); + ASSERT(declaratorAsBinary); + + TIntermBinary *initAssignment = new TIntermBinary( + EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight()); + + queueReplacementWithParent(node->getStatementList(), declaration, initAssignment, + OriginalNode::IS_DROPPED); + + declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy()); + } + wrapperBlock->appendStatement(declarationInBlock); + } + + wrapperBlock->appendStatement(node); + queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD); + mDidWrap = true; + + // Should be fine to process multiple switch statements, even nesting ones in the same + // traversal. + return true; +} + +} // anonymous namespace + +// Wrap switch statements in the AST into blocks when needed. +bool WrapSwitchStatementsInBlocks(TIntermBlock *root) +{ + WrapSwitchStatementsInBlocksTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); + return traverser.didWrap(); +} + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.h b/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.h new file mode 100644 index 0000000000..bc0179926d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/WrapSwitchStatementsInBlocks.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WrapSwitchStatementsInBlocks.h: Wrap switch statements in blocks and declare all switch-scoped +// variables there to make the AST compatible with HLSL output. + +#ifndef COMPILER_TRANSLATOR_WRAPSWITCHSTATEMENTSINBLOCKS_H_ +#define COMPILER_TRANSLATOR_WRAPSWITCHSTATEMENTSINBLOCKS_H_ + +namespace sh +{ + +class TIntermBlock; + +// Wrap switch statements in the AST into blocks when needed. Returns true if the AST was changed. +bool WrapSwitchStatementsInBlocks(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_WRAPSWITCHSTATEMENTSINBLOCKS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp index ba6322848e..fd8c450c20 100644 --- a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp @@ -15,24 +15,105 @@ namespace sh { -BlockLayoutEncoder::BlockLayoutEncoder() - : mCurrentOffset(0) +namespace { +bool IsRowMajorLayout(const InterfaceBlockField &var) +{ + return var.isRowMajorLayout; +} + +bool IsRowMajorLayout(const ShaderVariable &var) +{ + return false; +} + +template +void GetUniformBlockStructMemberInfo(const std::vector &fields, + const std::string &fieldName, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockInfoOut) +{ + encoder->enterAggregateType(); + GetUniformBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut); + encoder->exitAggregateType(); +} + +template +void GetUniformBlockStructArrayMemberInfo(const VarT &field, + unsigned int arrayNestingIndex, + const std::string &arrayName, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockInfoOut) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string elementName = arrayName + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < field.arraySizes.size()) + { + GetUniformBlockStructArrayMemberInfo(field, arrayNestingIndex + 1u, elementName, + encoder, inRowMajorLayout, blockInfoOut); + } + else + { + GetUniformBlockStructMemberInfo(field.fields, elementName, encoder, inRowMajorLayout, + blockInfoOut); + } + } } -BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix) +template +void GetUniformBlockArrayOfArraysMemberInfo(const VarT &field, + unsigned int arrayNestingIndex, + const std::string &arrayName, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockInfoOut) +{ + const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string elementName = arrayName + ArrayString(arrayElement); + if (arrayNestingIndex + 2u < field.arraySizes.size()) + { + GetUniformBlockArrayOfArraysMemberInfo(field, arrayNestingIndex + 1u, elementName, + encoder, inRowMajorLayout, blockInfoOut); + } + else + { + std::vector innermostArraySize( + 1u, field.getNestedArraySize(arrayNestingIndex + 1u)); + (*blockInfoOut)[elementName] = + encoder->encodeType(field.type, innermostArraySize, inRowMajorLayout); + } + } +} + +} // anonymous namespace + +BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) +{ +} + +BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix) { int arrayStride; int matrixStride; - getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride); + getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride); const BlockMemberInfo memberInfo(static_cast(mCurrentOffset * BytesPerComponent), static_cast(arrayStride * BytesPerComponent), static_cast(matrixStride * BytesPerComponent), isRowMajorMatrix); - advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride); + advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride); return memberInfo; } @@ -68,48 +149,56 @@ void Std140BlockEncoder::exitAggregateType() nextRegister(); } -void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) { // We assume we are only dealing with 4 byte components (no doubles or half-words currently) ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); size_t baseAlignment = 0; - int matrixStride = 0; - int arrayStride = 0; + int matrixStride = 0; + int arrayStride = 0; if (gl::IsMatrixType(type)) { baseAlignment = ComponentsPerRegister; - matrixStride = ComponentsPerRegister; + matrixStride = ComponentsPerRegister; - if (arraySize > 0) + if (!arraySizes.empty()) { const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - arrayStride = ComponentsPerRegister * numRegisters; + arrayStride = ComponentsPerRegister * numRegisters; } } - else if (arraySize > 0) + else if (!arraySizes.empty()) { baseAlignment = ComponentsPerRegister; - arrayStride = ComponentsPerRegister; + arrayStride = ComponentsPerRegister; } else { const int numComponents = gl::VariableComponentCount(type); - baseAlignment = (numComponents == 3 ? 4u : static_cast(numComponents)); + baseAlignment = (numComponents == 3 ? 4u : static_cast(numComponents)); } mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); *matrixStrideOut = matrixStride; - *arrayStrideOut = arrayStride; + *arrayStrideOut = arrayStride; } -void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +void Std140BlockEncoder::advanceOffset(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) { - if (arraySize > 0) + if (!arraySizes.empty()) { - mCurrentOffset += arrayStride * arraySize; + mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes); } else if (gl::IsMatrixType(type)) { @@ -123,4 +212,70 @@ void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool } } +template +void GetUniformBlockInfo(const std::vector &fields, + const std::string &prefix, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockInfoOut) +{ + for (const VarT &field : fields) + { + // Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be + // included. + if (gl::IsSamplerType(field.type)) + { + continue; + } + + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + + if (field.isStruct()) + { + bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + + if (field.isArray()) + { + GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout, + blockInfoOut); + } + else + { + GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout, + blockInfoOut); + } + } + else if (field.isArrayOfArrays()) + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + GetUniformBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder, isRowMajorMatrix, + blockInfoOut); + } + else + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + (*blockInfoOut)[fieldName] = + encoder->encodeType(field.type, field.arraySizes, isRowMajorMatrix); + } + } } + +template void GetUniformBlockInfo(const std::vector &, + const std::string &, + sh::BlockLayoutEncoder *, + bool, + BlockLayoutMap *); + +template void GetUniformBlockInfo(const std::vector &, + const std::string &, + sh::BlockLayoutEncoder *, + bool, + BlockLayoutMap *); + +template void GetUniformBlockInfo(const std::vector &, + const std::string &, + sh::BlockLayoutEncoder *, + bool, + BlockLayoutMap *); + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.h b/src/3rdparty/angle/src/compiler/translator/blocklayout.h index dd5fe07376..2b7acf4e60 100644 --- a/src/3rdparty/angle/src/compiler/translator/blocklayout.h +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.h @@ -11,6 +11,7 @@ #define COMMON_BLOCKLAYOUT_H_ #include +#include #include #include "angle_gl.h" @@ -24,42 +25,64 @@ struct Uniform; struct Varying; struct InterfaceBlock; -struct COMPILER_EXPORT BlockMemberInfo +struct BlockMemberInfo { - BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {} + BlockMemberInfo() + : offset(-1), + arrayStride(-1), + matrixStride(-1), + isRowMajorMatrix(false), + topLevelArrayStride(-1) + { + } BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) : offset(offset), arrayStride(arrayStride), matrixStride(matrixStride), - isRowMajorMatrix(isRowMajorMatrix) - {} + isRowMajorMatrix(isRowMajorMatrix), + topLevelArrayStride(-1) + { + } - static BlockMemberInfo getDefaultBlockInfo() + BlockMemberInfo(int offset, + int arrayStride, + int matrixStride, + bool isRowMajorMatrix, + int topLevelArrayStride) + : offset(offset), + arrayStride(arrayStride), + matrixStride(matrixStride), + isRowMajorMatrix(isRowMajorMatrix), + topLevelArrayStride(topLevelArrayStride) { - return BlockMemberInfo(-1, -1, -1, false); } + static BlockMemberInfo getDefaultBlockInfo() { return BlockMemberInfo(-1, -1, -1, false, -1); } + int offset; int arrayStride; int matrixStride; bool isRowMajorMatrix; + int topLevelArrayStride; // Only used for shader storage block members. }; -class COMPILER_EXPORT BlockLayoutEncoder +class BlockLayoutEncoder { public: BlockLayoutEncoder(); virtual ~BlockLayoutEncoder() {} - BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix); + BlockMemberInfo encodeType(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix); size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } virtual void enterAggregateType() = 0; - virtual void exitAggregateType() = 0; + virtual void exitAggregateType() = 0; - static const size_t BytesPerComponent = 4u; + static const size_t BytesPerComponent = 4u; static const unsigned int ComponentsPerRegister = 4u; static size_t getBlockRegister(const BlockMemberInfo &info); @@ -70,14 +93,22 @@ class COMPILER_EXPORT BlockLayoutEncoder void nextRegister(); - virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; - virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; + virtual void getBlockLayoutInfo(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) = 0; + virtual void advanceOffset(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) = 0; }; // Block layout according to the std140 block layout // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification -class COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder +class Std140BlockEncoder : public BlockLayoutEncoder { public: Std140BlockEncoder(); @@ -87,17 +118,27 @@ class COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder protected: void getBlockLayoutInfo(GLenum type, - unsigned int arraySize, + const std::vector &arraySizes, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; void advanceOffset(GLenum type, - unsigned int arraySize, + const std::vector &arraySizes, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; }; -} +using BlockLayoutMap = std::map; + +// Only valid to call with ShaderVariable, InterfaceBlockField and Uniform. +template +void GetUniformBlockInfo(const std::vector &fields, + const std::string &prefix, + sh::BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockLayoutMap); + +} // namespace sh -#endif // COMMON_BLOCKLAYOUT_H_ +#endif // COMMON_BLOCKLAYOUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp index 43119248eb..867821f1ea 100644 --- a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp @@ -15,9 +15,8 @@ namespace sh { -HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy) - : mEncoderStrategy(strategy), - mTransposeMatrices(false) +HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices) + : mEncoderStrategy(strategy), mTransposeMatrices(transposeMatrices) { } @@ -30,7 +29,11 @@ void HLSLBlockEncoder::exitAggregateType() { } -void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); @@ -38,14 +41,12 @@ void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); int matrixStride = 0; - int arrayStride = 0; + int arrayStride = 0; // if variables are not to be packed, or we're about to // pack a matrix or array, skip to the start of the next // register - if (!isPacked() || - gl::IsMatrixType(type) || - arraySize > 0) + if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty()) { nextRegister(); } @@ -54,13 +55,13 @@ void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, { matrixStride = ComponentsPerRegister; - if (arraySize > 0) + if (!arraySizes.empty()) { const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - arrayStride = ComponentsPerRegister * numRegisters; + arrayStride = ComponentsPerRegister * numRegisters; } } - else if (arraySize > 0) + else if (!arraySizes.empty()) { arrayStride = ComponentsPerRegister; } @@ -74,22 +75,26 @@ void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, } *matrixStrideOut = matrixStride; - *arrayStrideOut = arrayStride; + *arrayStrideOut = arrayStride; } -void HLSLBlockEncoder::advanceOffset(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +void HLSLBlockEncoder::advanceOffset(GLenum typeIn, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) { GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); - if (arraySize > 0) + if (!arraySizes.empty()) { - mCurrentOffset += arrayStride * (arraySize - 1); + mCurrentOffset += arrayStride * (gl::ArraySizeProduct(arraySizes) - 1); } if (gl::IsMatrixType(type)) { ASSERT(matrixStride == ComponentsPerRegister); - const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); mCurrentOffset += ComponentsPerRegister * (numRegisters - 1); mCurrentOffset += numComponents; @@ -109,7 +114,8 @@ void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) mCurrentOffset += (numRegisters * ComponentsPerRegister); } -HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType) +HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor( + ShShaderOutput outputType) { switch (outputType) { @@ -129,7 +135,7 @@ void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder * { if (variable.isStruct()) { - for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++) + for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++) { encoder->enterAggregateType(); @@ -144,28 +150,17 @@ void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder * else { // We operate only on varyings and uniforms, which do not have matrix layout qualifiers - encoder->encodeType(variable.type, variable.arraySize, false); + encoder->encodeType(variable.type, variable.arraySizes, false); } } -unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices) -{ - HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED); - encoder.setTransposeMatrices(transposeMatrices); - HLSLVariableRegisterCount(variable, &encoder); - - const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); - return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); -} - unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) { - HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType)); - encoder.setTransposeMatrices(true); + HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType), true); HLSLVariableRegisterCount(variable, &encoder); const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); - return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); -} - + return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / + registerBytes); } +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h index c61cb1ae57..8f4a51a906 100644 --- a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h @@ -24,7 +24,7 @@ namespace sh // The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED // for everything else (D3D10+ constant blocks and all attributes/varyings). -class COMPILER_EXPORT HLSLBlockEncoder : public BlockLayoutEncoder +class HLSLBlockEncoder : public BlockLayoutEncoder { public: enum HLSLBlockEncoderStrategy @@ -33,30 +33,36 @@ class COMPILER_EXPORT HLSLBlockEncoder : public BlockLayoutEncoder ENCODE_LOOSE }; - HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy); + HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices); - virtual void enterAggregateType(); - virtual void exitAggregateType(); + void enterAggregateType() override; + void exitAggregateType() override; void skipRegisters(unsigned int numRegisters); bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; } - void setTransposeMatrices(bool enabled) { mTransposeMatrices = enabled; } static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType); protected: - virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); - virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); + void getBlockLayoutInfo(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) override; + void advanceOffset(GLenum type, + const std::vector &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) override; HLSLBlockEncoderStrategy mEncoderStrategy; bool mTransposeMatrices; }; -// This method returns the number of used registers for a ShaderVariable. It is dependent on the HLSLBlockEncoder -// class to count the number of used registers in a struct (which are individually packed according to the same rules). -COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices); -COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); - +// This method returns the number of used registers for a ShaderVariable. It is dependent on the +// HLSLBlockEncoder class to count the number of used registers in a struct (which are individually +// packed according to the same rules). +unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); } -#endif // COMMON_BLOCKLAYOUTHLSL_H_ +#endif // COMMON_BLOCKLAYOUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/compilerdebug.cpp b/src/3rdparty/angle/src/compiler/translator/compilerdebug.cpp deleted file mode 100644 index 10cbe43b8d..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/compilerdebug.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// debug.cpp: Debugging utilities. - -#include "compiler/translator/compilerdebug.h" - -#include -#include - -#include "compiler/translator/InitializeParseContext.h" -#include "compiler/translator/ParseContext.h" - -#ifdef TRACE_ENABLED -static const int kTraceBufferLen = 1024; - -extern "C" { -void Trace(const char *format, ...) { - if (!format) return; - - TParseContext* parseContext = GetGlobalParseContext(); - if (parseContext) { - char buf[kTraceBufferLen]; - va_list args; - va_start(args, format); - vsnprintf(buf, kTraceBufferLen, format, args); - va_end(args); - - parseContext->trace(buf); - } -} -} // extern "C" -#endif // TRACE_ENABLED - diff --git a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h b/src/3rdparty/angle/src/compiler/translator/compilerdebug.h deleted file mode 100644 index 84a12ad2f8..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// debug.h: Debugging utilities. - -#ifndef COMPILER_TRANSLATOR_COMPILERDEBUG_H_ -#define COMPILER_TRANSLATOR_COMPILERDEBUG_H_ - -#include - -#ifdef _DEBUG -#define TRACE_ENABLED // define to enable debug message tracing -#endif // _DEBUG - -// Outputs text to the debug log -#ifdef TRACE_ENABLED - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus -void Trace(const char* format, ...); -#ifdef __cplusplus -} -#endif // __cplusplus - -#else // TRACE_ENABLED - -#define Trace(...) ((void)0) - -#endif // TRACE_ENABLED - -// A macro asserting a condition and outputting failures to the debug log -#define ASSERT(expression) do { \ - if(!(expression)) \ - Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ - assert(expression); \ -} while(0) - -#define UNIMPLEMENTED() do { \ - Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \ - assert(false); \ -} while(0) - -#define UNREACHABLE() do { \ - Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ - assert(false); \ -} while(0) - -#endif // COMPILER_TRANSLATOR_COMPILERDEBUG_H_ - diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp deleted file mode 100644 index 4dee0dbd2e..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.cpp +++ /dev/null @@ -1,95 +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. -// - -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/depgraph/DependencyGraphBuilder.h" - -TDependencyGraph::TDependencyGraph(TIntermNode* intermNode) -{ - TDependencyGraphBuilder::build(intermNode, this); -} - -TDependencyGraph::~TDependencyGraph() -{ - for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter) - { - TGraphNode* node = *iter; - delete node; - } -} - -TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall, - int argumentNumber) -{ - TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber); - mAllNodes.push_back(argument); - return argument; -} - -TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall) -{ - TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall); - mAllNodes.push_back(functionCall); - if (functionCall->getIntermFunctionCall()->isUserDefined()) - mUserDefinedFunctionCalls.push_back(functionCall); - return functionCall; -} - -TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol) -{ - TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId()); - - TGraphSymbol* symbol = NULL; - - if (iter != mSymbolIdMap.end()) { - TSymbolIdPair pair = *iter; - symbol = pair.second; - } else { - symbol = new TGraphSymbol(intermSymbol); - mAllNodes.push_back(symbol); - - TSymbolIdPair pair(intermSymbol->getId(), symbol); - mSymbolIdMap.insert(pair); - - // We save all sampler symbols in a collection, so we can start graph traversals from them quickly. - if (IsSampler(intermSymbol->getBasicType())) - mSamplerSymbols.push_back(symbol); - } - - return symbol; -} - -TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection) -{ - TGraphSelection* selection = new TGraphSelection(intermSelection); - mAllNodes.push_back(selection); - return selection; -} - -TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop) -{ - TGraphLoop* loop = new TGraphLoop(intermLoop); - mAllNodes.push_back(loop); - return loop; -} - -TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp) -{ - TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp); - mAllNodes.push_back(logicalOp); - return logicalOp; -} - -const char* TGraphLogicalOp::getOpString() const -{ - const char* opString = NULL; - switch (getIntermLogicalOp()->getOp()) { - case EOpLogicalAnd: opString = "and"; break; - case EOpLogicalOr: opString = "or"; break; - default: opString = "unknown"; break; - } - return opString; -} diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h deleted file mode 100644 index 2f7f7b9ab8..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h +++ /dev/null @@ -1,199 +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. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ - -#include "compiler/translator/IntermNode.h" - -#include -#include - -class TGraphNode; -class TGraphParentNode; -class TGraphArgument; -class TGraphFunctionCall; -class TGraphSymbol; -class TGraphSelection; -class TGraphLoop; -class TGraphLogicalOp; -class TDependencyGraphTraverser; -class TDependencyGraphOutput; - -typedef std::set TGraphNodeSet; -typedef std::vector TGraphNodeVector; -typedef std::vector TGraphSymbolVector; -typedef std::vector TFunctionCallVector; - -// -// Base class for all dependency graph nodes. -// -class TGraphNode { -public: - TGraphNode(TIntermNode* node) : intermNode(node) {} - virtual ~TGraphNode() {} - virtual void traverse(TDependencyGraphTraverser* graphTraverser); -protected: - TIntermNode* intermNode; -}; - -// -// Base class for dependency graph nodes that may have children. -// -class TGraphParentNode : public TGraphNode { -public: - TGraphParentNode(TIntermNode* node) : TGraphNode(node) {} - ~TGraphParentNode() override {} - void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; - -private: - TGraphNodeSet mDependentNodes; -}; - -// -// Handle function call arguments. -// -class TGraphArgument : public TGraphParentNode { -public: - TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber) - : TGraphParentNode(intermFunctionCall) - , mArgumentNumber(argumentNumber) {} - ~TGraphArgument() override {} - const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } - int getArgumentNumber() const { return mArgumentNumber; } - void traverse(TDependencyGraphTraverser *graphTraverser) override; - -private: - int mArgumentNumber; -}; - -// -// Handle function calls. -// -class TGraphFunctionCall : public TGraphParentNode { -public: - TGraphFunctionCall(TIntermAggregate* intermFunctionCall) - : TGraphParentNode(intermFunctionCall) {} - ~TGraphFunctionCall() override {} - const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle symbols. -// -class TGraphSymbol : public TGraphParentNode { -public: - TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {} - ~TGraphSymbol() override {} - const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle if statements and ternary operators. -// -class TGraphSelection : public TGraphNode { -public: - TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {} - ~TGraphSelection() override {} - const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle for, do-while, and while loops. -// -class TGraphLoop : public TGraphNode { -public: - TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {} - ~TGraphLoop() override {} - const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle logical and, or. -// -class TGraphLogicalOp : public TGraphNode { -public: - TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {} - ~TGraphLogicalOp() override {} - const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); } - const char* getOpString() const; - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// A dependency graph of symbols, function calls, conditions etc. -// -// This class provides an interface to the entry points of the dependency graph. -// -// Dependency graph nodes should be created by using one of the provided "create..." methods. -// This class (and nobody else) manages the memory of the created nodes. -// Nodes may not be removed after being added, so all created nodes will exist while the -// TDependencyGraph instance exists. -// -class TDependencyGraph { -public: - TDependencyGraph(TIntermNode* intermNode); - ~TDependencyGraph(); - const TGraphNodeVector &allNodes() const { return mAllNodes; } - const TGraphSymbolVector &samplerSymbols() const { return mSamplerSymbols; } - const TFunctionCallVector &userDefinedFunctionCalls() const - { - return mUserDefinedFunctionCalls; - } - - TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber); - TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall); - TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol); - TGraphSelection* createSelection(TIntermSelection* intermSelection); - TGraphLoop* createLoop(TIntermLoop* intermLoop); - TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp); -private: - typedef TMap TSymbolIdMap; - typedef std::pair TSymbolIdPair; - - TGraphNodeVector mAllNodes; - TGraphSymbolVector mSamplerSymbols; - TFunctionCallVector mUserDefinedFunctionCalls; - TSymbolIdMap mSymbolIdMap; -}; - -// -// For traversing the dependency graph. Users should derive from this, -// put their traversal specific data in it, and then pass it to a -// traverse method. -// -// When using this, just fill in the methods for nodes you want visited. -// -class TDependencyGraphTraverser : angle::NonCopyable { -public: - TDependencyGraphTraverser() : mDepth(0) {} - virtual ~TDependencyGraphTraverser() {} - - virtual void visitSymbol(TGraphSymbol* symbol) {}; - virtual void visitArgument(TGraphArgument* selection) {}; - virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {}; - virtual void visitSelection(TGraphSelection* selection) {}; - virtual void visitLoop(TGraphLoop* loop) {}; - virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {}; - - int getDepth() const { return mDepth; } - void incrementDepth() { ++mDepth; } - void decrementDepth() { --mDepth; } - - void clearVisited() { mVisited.clear(); } - void markVisited(TGraphNode* node) { mVisited.insert(node); } - bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); } -private: - int mDepth; - TGraphNodeSet mVisited; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp deleted file mode 100644 index 1aeb822d51..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp +++ /dev/null @@ -1,255 +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. -// - -#include "compiler/translator/depgraph/DependencyGraphBuilder.h" - -void TDependencyGraphBuilder::build(TIntermNode *node, TDependencyGraph *graph) -{ - TDependencyGraphBuilder builder(graph); - builder.build(node); -} - -bool TDependencyGraphBuilder::visitAggregate( - Visit visit, TIntermAggregate *intermAggregate) -{ - switch (intermAggregate->getOp()) - { - case EOpFunction: - visitFunctionDefinition(intermAggregate); - break; - case EOpFunctionCall: - visitFunctionCall(intermAggregate); - break; - default: - visitAggregateChildren(intermAggregate); - break; - } - return false; -} - -void TDependencyGraphBuilder::visitFunctionDefinition( - TIntermAggregate *intermAggregate) -{ - // Currently, we do not support user defined functions. - if (intermAggregate->getName() != "main(") - return; - - visitAggregateChildren(intermAggregate); -} - -// Takes an expression like "f(x)" and creates a dependency graph like -// "x -> argument 0 -> function call". -void TDependencyGraphBuilder::visitFunctionCall( - TIntermAggregate *intermFunctionCall) -{ - TGraphFunctionCall *functionCall = - mGraph->createFunctionCall(intermFunctionCall); - - // Run through the function call arguments. - int argumentNumber = 0; - TIntermSequence *intermArguments = intermFunctionCall->getSequence(); - for (TIntermSequence::const_iterator iter = intermArguments->begin(); - iter != intermArguments->end(); - ++iter, ++argumentNumber) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - TIntermNode *intermArgument = *iter; - intermArgument->traverse(this); - - if (TParentNodeSet *argumentNodes = mNodeSets.getTopSet()) - { - TGraphArgument *argument = mGraph->createArgument( - intermFunctionCall, argumentNumber); - connectMultipleNodesToSingleNode(argumentNodes, argument); - argument->addDependentNode(functionCall); - } - } - - // Push the leftmost symbol of this function call into the current set of - // dependent symbols to represent the result of this function call. - // Thus, an expression like "y = f(x)" will yield a dependency graph like - // "x -> argument 0 -> function call -> y". - // This line essentially passes the function call node back up to an earlier - // visitAssignment call, which will create the connection "function call -> y". - mNodeSets.insertIntoTopSet(functionCall); -} - -void TDependencyGraphBuilder::visitAggregateChildren( - TIntermAggregate *intermAggregate) -{ - TIntermSequence *sequence = intermAggregate->getSequence(); - for (TIntermSequence::const_iterator iter = sequence->begin(); - iter != sequence->end(); ++iter) - { - TIntermNode *intermChild = *iter; - intermChild->traverse(this); - } -} - -void TDependencyGraphBuilder::visitSymbol(TIntermSymbol *intermSymbol) -{ - // Push this symbol into the set of dependent symbols for the current - // assignment or condition that we are traversing. - TGraphSymbol *symbol = mGraph->getOrCreateSymbol(intermSymbol); - mNodeSets.insertIntoTopSet(symbol); - - // If this symbol is the current leftmost symbol under an assignment, replace - // the previous leftmost symbol with this symbol. - if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) - { - mLeftmostSymbols.pop(); - mLeftmostSymbols.push(symbol); - } -} - -bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary *intermBinary) -{ - TOperator op = intermBinary->getOp(); - if (op == EOpInitialize || intermBinary->isAssignment()) - visitAssignment(intermBinary); - else if (op == EOpLogicalAnd || op == EOpLogicalOr) - visitLogicalOp(intermBinary); - else - visitBinaryChildren(intermBinary); - - return false; -} - -void TDependencyGraphBuilder::visitAssignment(TIntermBinary *intermAssignment) -{ - TIntermTyped *intermLeft = intermAssignment->getLeft(); - if (!intermLeft) - return; - - TGraphSymbol *leftmostSymbol = NULL; - - { - TNodeSetMaintainer nodeSetMaintainer(this); - - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree); - intermLeft->traverse(this); - leftmostSymbol = mLeftmostSymbols.top(); - - // After traversing the left subtree of this assignment, we should - // have found a real leftmost symbol, and the leftmost symbol should - // not be a placeholder. - ASSERT(leftmostSymbol != &mLeftSubtree); - ASSERT(leftmostSymbol != &mRightSubtree); - } - - if (TIntermTyped *intermRight = intermAssignment->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } - - if (TParentNodeSet *assignmentNodes = mNodeSets.getTopSet()) - connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol); - } - - // Push the leftmost symbol of this assignment into the current set of dependent - // symbols to represent the result of this assignment. - // An expression like "a = (b = c)" will yield a dependency graph like - // "c -> b -> a". - // This line essentially passes the leftmost symbol of the nested assignment - // ("b" in this example) back up to the earlier visitAssignment call for the - // outer assignment, which will create the connection "b -> a". - mNodeSets.insertIntoTopSet(leftmostSymbol); -} - -void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary *intermLogicalOp) -{ - if (TIntermTyped *intermLeft = intermLogicalOp->getLeft()) - { - TNodeSetPropagatingMaintainer nodeSetMaintainer(this); - - intermLeft->traverse(this); - if (TParentNodeSet *leftNodes = mNodeSets.getTopSet()) - { - TGraphLogicalOp *logicalOp = mGraph->createLogicalOp(intermLogicalOp); - connectMultipleNodesToSingleNode(leftNodes, logicalOp); - } - } - - if (TIntermTyped *intermRight = intermLogicalOp->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } -} - -void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary *intermBinary) -{ - if (TIntermTyped *intermLeft = intermBinary->getLeft()) - intermLeft->traverse(this); - - if (TIntermTyped *intermRight = intermBinary->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } -} - -bool TDependencyGraphBuilder::visitSelection( - Visit visit, TIntermSelection *intermSelection) -{ - if (TIntermNode *intermCondition = intermSelection->getCondition()) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - intermCondition->traverse(this); - if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) - { - TGraphSelection *selection = mGraph->createSelection(intermSelection); - connectMultipleNodesToSingleNode(conditionNodes, selection); - } - } - - if (TIntermNode *intermTrueBlock = intermSelection->getTrueBlock()) - intermTrueBlock->traverse(this); - - if (TIntermNode *intermFalseBlock = intermSelection->getFalseBlock()) - intermFalseBlock->traverse(this); - - return false; -} - -bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop *intermLoop) -{ - if (TIntermTyped *intermCondition = intermLoop->getCondition()) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - intermCondition->traverse(this); - if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) - { - TGraphLoop *loop = mGraph->createLoop(intermLoop); - connectMultipleNodesToSingleNode(conditionNodes, loop); - } - } - - if (TIntermNode* intermBody = intermLoop->getBody()) - intermBody->traverse(this); - - if (TIntermTyped *intermExpression = intermLoop->getExpression()) - intermExpression->traverse(this); - - return false; -} - - -void TDependencyGraphBuilder::connectMultipleNodesToSingleNode( - TParentNodeSet *nodes, TGraphNode *node) const -{ - for (TParentNodeSet::const_iterator iter = nodes->begin(); - iter != nodes->end(); ++iter) - { - TGraphParentNode *currentNode = *iter; - currentNode->addDependentNode(node); - } -} diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h deleted file mode 100644 index c7b54f66b7..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h +++ /dev/null @@ -1,199 +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. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ - -#include "compiler/translator/depgraph/DependencyGraph.h" - -// -// Creates a dependency graph of symbols, function calls, conditions etc. by -// traversing a intermediate tree. -// -class TDependencyGraphBuilder : public TIntermTraverser -{ - public: - static void build(TIntermNode *node, TDependencyGraph *graph); - - 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; - typedef std::set TParentNodeSet; - - // - // For collecting the dependent nodes of assignments, conditions, etc. - // while traversing the intermediate tree. - // - // This data structure is stack of sets. Each set contains dependency graph - // parent nodes. - // - class TNodeSetStack - { - public: - TNodeSetStack() {}; - ~TNodeSetStack() { clear(); } - - // This should only be called after a pushSet. - // Returns NULL if the top set is empty. - TParentNodeSet *getTopSet() const - { - ASSERT(!mNodeSets.empty()); - TParentNodeSet *topSet = mNodeSets.top(); - return !topSet->empty() ? topSet : NULL; - } - - void pushSet() { mNodeSets.push(new TParentNodeSet()); } - void popSet() - { - ASSERT(!mNodeSets.empty()); - delete mNodeSets.top(); - mNodeSets.pop(); - } - - // Pops the top set and adds its contents to the new top set. - // This should only be called after a pushSet. - // If there is no set below the top set, the top set is just deleted. - void popSetIntoNext() - { - ASSERT(!mNodeSets.empty()); - TParentNodeSet *oldTopSet = mNodeSets.top(); - mNodeSets.pop(); - - if (!mNodeSets.empty()) - { - TParentNodeSet *newTopSet = mNodeSets.top(); - newTopSet->insert(oldTopSet->begin(), oldTopSet->end()); - } - - delete oldTopSet; - } - - // Does nothing if there is no top set. - // This can be called when there is no top set if we are visiting - // symbols that are not under an assignment or condition. - // We don't need to track those symbols. - void insertIntoTopSet(TGraphParentNode *node) - { - if (mNodeSets.empty()) - return; - - mNodeSets.top()->insert(node); - } - - void clear() - { - while (!mNodeSets.empty()) - popSet(); - } - - private: - typedef std::stack TParentNodeSetStack; - - TParentNodeSetStack mNodeSets; - }; - - // - // An instance of this class pushes a new node set when instantiated. - // When the instance goes out of scope, it and pops the node set. - // - class TNodeSetMaintainer : angle::NonCopyable - { - public: - TNodeSetMaintainer(TDependencyGraphBuilder *factory) - : mSets(factory->mNodeSets) - { - mSets.pushSet(); - } - ~TNodeSetMaintainer() { mSets.popSet(); } - protected: - TNodeSetStack &mSets; - }; - - // - // An instance of this class pushes a new node set when instantiated. - // When the instance goes out of scope, it and pops the top node set and adds - // its contents to the new top node set. - // - class TNodeSetPropagatingMaintainer : angle::NonCopyable - { - public: - TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory) - : mSets(factory->mNodeSets) - { - mSets.pushSet(); - } - ~TNodeSetPropagatingMaintainer() { mSets.popSetIntoNext(); } - protected: - TNodeSetStack &mSets; - }; - - // - // An instance of this class keeps track of the leftmost symbol while we're - // exploring an assignment. - // It will push the placeholder symbol kLeftSubtree when instantiated under a - // left subtree, and kRightSubtree under a right subtree. - // When it goes out of scope, it will pop the leftmost symbol at the top of the - // scope. - // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with - // a real symbol. - // kRightSubtree will never be replaced by a real symbol because we are tracking - // the leftmost symbol. - // - class TLeftmostSymbolMaintainer : angle::NonCopyable - { - public: - TLeftmostSymbolMaintainer( - TDependencyGraphBuilder *factory, TGraphSymbol &subtree) - : mLeftmostSymbols(factory->mLeftmostSymbols) - { - mNeedsPlaceholderSymbol = - mLeftmostSymbols.empty() || mLeftmostSymbols.top() != &subtree; - if (mNeedsPlaceholderSymbol) - mLeftmostSymbols.push(&subtree); - } - - ~TLeftmostSymbolMaintainer() - { - if (mNeedsPlaceholderSymbol) - mLeftmostSymbols.pop(); - } - - protected: - TSymbolStack& mLeftmostSymbols; - bool mNeedsPlaceholderSymbol; - }; - - TDependencyGraphBuilder(TDependencyGraph *graph) - : TIntermTraverser(true, false, false), - mLeftSubtree(NULL), - mRightSubtree(NULL), - mGraph(graph) {} - void build(TIntermNode *intermNode) { intermNode->traverse(this); } - - void connectMultipleNodesToSingleNode( - TParentNodeSet *nodes, TGraphNode *node) const; - - void visitAssignment(TIntermBinary *); - void visitLogicalOp(TIntermBinary *); - void visitBinaryChildren(TIntermBinary *); - void visitFunctionDefinition(TIntermAggregate *); - void visitFunctionCall(TIntermAggregate *intermFunctionCall); - void visitAggregateChildren(TIntermAggregate *); - - TGraphSymbol mLeftSubtree; - TGraphSymbol mRightSubtree; - - TDependencyGraph *mGraph; - TNodeSetStack mNodeSets; - TSymbolStack mLeftmostSymbols; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp deleted file mode 100644 index 32a2f30141..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp +++ /dev/null @@ -1,64 +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. -// - -#include "compiler/translator/depgraph/DependencyGraphOutput.h" - -void TDependencyGraphOutput::outputIndentation() -{ - for (int i = 0; i < getDepth(); ++i) - mSink << " "; -} - -void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter) -{ - outputIndentation(); - mSink << "argument " << parameter->getArgumentNumber() << " of call to " - << parameter->getIntermFunctionCall()->getName() << "\n"; -} - -void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall) -{ - outputIndentation(); - mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n"; -} - -void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol) -{ - outputIndentation(); - mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: " - << symbol->getIntermSymbol()->getId() << ")\n"; -} - -void TDependencyGraphOutput::visitSelection(TGraphSelection* selection) -{ - outputIndentation(); - mSink << "selection\n"; -} - -void TDependencyGraphOutput::visitLoop(TGraphLoop* loop) -{ - outputIndentation(); - mSink << "loop condition\n"; -} - -void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp) -{ - outputIndentation(); - mSink << "logical " << logicalOp->getOpString() << "\n"; -} - -void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph) -{ - mSink << "\n"; - - for (auto symbol : graph.allNodes()) - { - mSink << "--- Dependency graph spanning tree ---\n"; - clearVisited(); - symbol->traverse(this); - mSink << "\n"; - } -} diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h deleted file mode 100644 index b201e0a671..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h +++ /dev/null @@ -1,31 +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. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ - -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/InfoSink.h" - -class TDependencyGraphOutput : public TDependencyGraphTraverser -{ - public: - TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {} - void visitSymbol(TGraphSymbol* symbol) override; - void visitArgument(TGraphArgument* parameter) override; - void visitFunctionCall(TGraphFunctionCall* functionCall) override; - void visitSelection(TGraphSelection* selection) override; - void visitLoop(TGraphLoop* loop) override; - void visitLogicalOp(TGraphLogicalOp* logicalOp) override; - - void outputAllSpanningTrees(TDependencyGraph& graph); - private: - void outputIndentation(); - - TInfoSinkBase& mSink; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp deleted file mode 100644 index 197fde97e2..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp +++ /dev/null @@ -1,69 +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. -// - -#include "compiler/translator/depgraph/DependencyGraph.h" - -// These methods do a breadth-first traversal through the graph and mark visited nodes. - -void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->markVisited(this); -} - -void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser) -{ - TGraphNode::traverse(graphTraverser); - - graphTraverser->incrementDepth(); - - // Visit the parent node's children. - for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin(); - iter != mDependentNodes.end(); - ++iter) - { - TGraphNode* node = *iter; - if (!graphTraverser->isVisited(node)) - node->traverse(graphTraverser); - } - - graphTraverser->decrementDepth(); -} - -void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitArgument(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitFunctionCall(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitSymbol(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitSelection(this); - TGraphNode::traverse(graphTraverser); -} - -void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitLoop(this); - TGraphNode::traverse(graphTraverser); -} - -void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitLogicalOp(this); - TGraphNode::traverse(graphTraverser); -} diff --git a/src/3rdparty/angle/src/compiler/translator/emulated_builtin_function_data_hlsl.json b/src/3rdparty/angle/src/compiler/translator/emulated_builtin_function_data_hlsl.json new file mode 100644 index 0000000000..32e500fe67 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/emulated_builtin_function_data_hlsl.json @@ -0,0 +1,1382 @@ +[ + { + "op":"mod", + "return_type":"float", + "args":[ + "float x", + "float y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float2", + "args":[ + "float2 x", + "float2 y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float2", + "args":[ + "float2 x", + "float y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float3", + "args":[ + "float3 x", + "float3 y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float3", + "args":[ + "float3 x", + "float y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float4", + "args":[ + "float4 x", + "float4 y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"mod", + "return_type":"float4", + "args":[ + "float4 x", + "float y" + ], + "body":[ + "return x - y * floor(x / y);" + ] + }, + { + "op":"frexp", + "return_type":"float", + "args":[ + "float x", + "out int exp" + ], + "body":[ + "float fexp;", + "float mantissa = frexp(abs(x), fexp) * sign(x);", + "exp = int(fexp);", + "return mantissa;" + ] + }, + { + "op":"frexp", + "return_type":"float2", + "args":[ + "float2 x", + "out int2 exp" + ], + "body":[ + "float2 fexp;", + "float2 mantissa = frexp(abs(x), fexp) * sign(x);", + "exp = int2(fexp);", + "return mantissa;" + ] + }, + { + "op":"frexp", + "return_type":"float3", + "args":[ + "float3 x", + "out int3 exp" + ], + "body":[ + "float3 fexp;", + "float3 mantissa = frexp(abs(x), fexp) * sign(x);", + "exp = int3(fexp);", + "return mantissa;" + ] + }, + { + "op":"frexp", + "return_type":"float4", + "args":[ + "float4 x", + "out int4 exp" + ], + "body":[ + "float4 fexp;", + "float4 mantissa = frexp(abs(x), fexp) * sign(x);", + "exp = int4(fexp);", + "return mantissa;" + ] + }, + { + "op":"ldexp", + "return_type":"float", + "args":[ + "float x", + "int exp" + ], + "body":[ + "return ldexp(x, float(exp));" + ] + }, + { + "op":"ldexp", + "return_type":"float2", + "args":[ + "float2 x", + "int2 exp" + ], + "body":[ + "return ldexp(x, float2(exp));" + ] + }, + { + "op":"ldexp", + "return_type":"float3", + "args":[ + "float3 x", + "int3 exp" + ], + "body":[ + "return ldexp(x, float3(exp));" + ] + }, + { + "op":"ldexp", + "return_type":"float4", + "args":[ + "float4 x", + "int4 exp" + ], + "body":[ + "return ldexp(x, float4(exp));" + ] + }, + { + "op":"faceforward", + "return_type":"float", + "args":[ + "float N", + "float I", + "float Nref" + ], + "body":[ + "if(dot(Nref, I) >= 0)", + "{", + " return -N;", + "}", + "else", + "{", + " return N;", + "}" + ] + }, + { + "op":"faceforward", + "return_type":"float2", + "args":[ + "float2 N", + "float2 I", + "float2 Nref" + ], + "body":[ + "if(dot(Nref, I) >= 0)", + "{", + " return -N;", + "}", + "else", + "{", + " return N;", + "}" + ] + }, + { + "op":"faceforward", + "return_type":"float3", + "args":[ + "float3 N", + "float3 I", + "float3 Nref" + ], + "body":[ + "if(dot(Nref, I) >= 0)", + "{", + " return -N;", + "}", + "else", + "{", + " return N;", + "}" + ] + }, + { + "op":"faceforward", + "return_type":"float4", + "args":[ + "float4 N", + "float4 I", + "float4 Nref" + ], + "body":[ + "if(dot(Nref, I) >= 0)", + "{", + " return -N;", + "}", + "else", + "{", + " return N;", + "}" + ] + }, + { + "op":"atan", + "return_type":"float", + "args":[ + "float y", + "float x" + ], + "body":[ + "if(x == 0 && y == 0) x = 1;", + "return atan2(y, x);" + ] + }, + { + "op":"atan", + "return_type":"float2", + "args":[ + "float2 y", + "float2 x" + ], + "body":[ + "if(x[0] == 0 && y[0] == 0) x[0] = 1;", + "if(x[1] == 0 && y[1] == 0) x[1] = 1;", + "return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));" + ] + }, + { + "op":"atan", + "return_type":"float3", + "args":[ + "float3 y", + "float3 x" + ], + "body":[ + "if(x[0] == 0 && y[0] == 0) x[0] = 1;", + "if(x[1] == 0 && y[1] == 0) x[1] = 1;", + "if(x[2] == 0 && y[2] == 0) x[2] = 1;", + "return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));" + ] + }, + { + "op":"atan", + "return_type":"float4", + "args":[ + "float4 y", + "float4 x" + ], + "body":[ + "if(x[0] == 0 && y[0] == 0) x[0] = 1;", + "if(x[1] == 0 && y[1] == 0) x[1] = 1;", + "if(x[2] == 0 && y[2] == 0) x[2] = 1;", + "if(x[3] == 0 && y[3] == 0) x[3] = 1;", + "return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], ", + "x[2]), atan2(y[3], x[3]));" + ] + }, + { + "op":"asinh", + "return_type":"float", + "args":[ + "in float x" + ], + "body":[ + "return log(x + sqrt(pow(x, 2.0) + 1.0));" + ] + }, + { + "op":"asinh", + "return_type":"float2", + "args":[ + "in float2 x" + ], + "body":[ + "return log(x + sqrt(pow(x, 2.0) + 1.0));" + ] + }, + { + "op":"asinh", + "return_type":"float3", + "args":[ + "in float3 x" + ], + "body":[ + "return log(x + sqrt(pow(x, 2.0) + 1.0));" + ] + }, + { + "op":"asinh", + "return_type":"float4", + "args":[ + "in float4 x" + ], + "body":[ + "return log(x + sqrt(pow(x, 2.0) + 1.0));" + ] + }, + { + "op":"acosh", + "return_type":"float", + "args":[ + "in float x" + ], + "body":[ + "return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));" + ] + }, + { + "op":"acosh", + "return_type":"float2", + "args":[ + "in float2 x" + ], + "body":[ + "return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));" + ] + }, + { + "op":"acosh", + "return_type":"float3", + "args":[ + "in float3 x" + ], + "body":[ + "return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));" + ] + }, + { + "op":"acosh", + "return_type":"float4", + "args":[ + "in float4 x" + ], + "body":[ + "return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));" + ] + }, + { + "op":"atanh", + "return_type":"float", + "args":[ + "in float x" + ], + "body":[ + "return 0.5 * log((1.0 + x) / (1.0 - x));" + ] + }, + { + "op":"atanh", + "return_type":"float2", + "args":[ + "in float2 x" + ], + "body":[ + "return 0.5 * log((1.0 + x) / (1.0 - x));" + ] + }, + { + "op":"atanh", + "return_type":"float3", + "args":[ + "in float3 x" + ], + "body":[ + "return 0.5 * log((1.0 + x) / (1.0 - x));" + ] + }, + { + "op":"atanh", + "return_type":"float4", + "args":[ + "in float4 x" + ], + "body":[ + "return 0.5 * log((1.0 + x) / (1.0 - x));" + ] + }, + { + "op":"roundEven", + "return_type":"float", + "args":[ + "in float x" + ], + "body":[ + "return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);" + ] + }, + { + "op":"roundEven", + "return_type":"float2", + "args":[ + "in float2 x" + ], + "body":[ + "float2 v;", + "v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);", + "v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);", + "return v;" + ] + }, + { + "op":"roundEven", + "return_type":"float3", + "args":[ + "in float3 x" + ], + "body":[ + "float3 v;", + "v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);", + "v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);", + "v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);", + "return v;" + ] + }, + { + "op":"roundEven", + "return_type":"float4", + "args":[ + "in float4 x" + ], + "body":[ + "float4 v;", + "v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);", + "v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);", + "v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);", + "v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);", + "return v;" + ] + }, + { + "op":"packSnorm2x16", + "return_type":"uint", + "args":[ + "in float2 v" + ], + "helper":[ + "int webgl_toSnorm16(in float x) {", + " return int(round(clamp(x, -1.0, 1.0) * 32767.0));", + "}" + ], + "body":[ + "int x = webgl_toSnorm16(v.x);", + "int y = webgl_toSnorm16(v.y);", + "return (asuint(y) << 16) | (asuint(x) & 0xffffu);" + ] + }, + { + "op":"packUnorm2x16", + "return_type":"uint", + "args":[ + "in float2 v" + ], + "helper":[ + "uint webgl_toUnorm16(in float x) {", + " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));", + "}" + ], + "body":[ + "uint x = webgl_toUnorm16(v.x);", + "uint y = webgl_toUnorm16(v.y);", + "return (y << 16) | x;" + ] + }, + { + "op":"packHalf2x16", + "return_type":"uint", + "args":[ + "in float2 v" + ], + "body":[ + "uint x = f32tof16(v.x);", + "uint y = f32tof16(v.y);", + "return (y << 16) | x;" + ] + }, + { + "op":"unpackSnorm2x16", + "return_type":"float2", + "args":[ + "in uint u" + ], + "helper":[ + "float webgl_fromSnorm16(in uint x) {", + " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);", + " return clamp(float(xi) / 32767.0, -1.0, 1.0);", + "}" + ], + "body":[ + "uint y = (u >> 16);", + "uint x = u;", + "return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));" + ] + }, + { + "op":"unpackUnorm2x16", + "return_type":"float2", + "args":[ + "in uint u" + ], + "helper":[ + "float webgl_fromUnorm16(in uint x) {", + " return float(x) / 65535.0;", + "}" + ], + "body":[ + "uint y = (u >> 16);", + "uint x = u & 0xffffu;", + "return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));" + ] + }, + { + "op":"unpackHalf2x16", + "return_type":"float2", + "args":[ + "in uint u" + ], + "body":[ + "uint y = (u >> 16);", + "uint x = u & 0xffffu;", + "return float2(f16tof32(x), f16tof32(y));" + ] + }, + { + "op":"packSnorm4x8", + "return_type":"uint", + "args":[ + "in float4 v" + ], + "helper":[ + "int webgl_toSnorm8(in float x) {", + " return int(round(clamp(x, -1.0, 1.0) * 127.0));", + "}" + ], + "body":[ + "int x = webgl_toSnorm8(v.x);", + "int y = webgl_toSnorm8(v.y);", + "int z = webgl_toSnorm8(v.z);", + "int w = webgl_toSnorm8(v.w);", + "return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) ", + "| ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);" + ] + }, + { + "op":"packUnorm4x8", + "return_type":"uint", + "args":[ + "in float4 v" + ], + "helper":[ + "uint webgl_toUnorm8(in float x) {", + " return uint(round(clamp(x, 0.0, 1.0) * 255.0));", + "}" + ], + "body":[ + "uint x = webgl_toUnorm8(v.x);", + "uint y = webgl_toUnorm8(v.y);", + "uint z = webgl_toUnorm8(v.z);", + "uint w = webgl_toUnorm8(v.w);", + "return (w << 24) | (z << 16) | (y << 8) | x;" + ] + }, + { + "op":"unpackSnorm4x8", + "return_type":"float4", + "args":[ + "in uint u" + ], + "helper":[ + "float webgl_fromSnorm8(in uint x) {", + " int xi = asint(x & 0x7fu) - asint(x & 0x80u);", + " return clamp(float(xi) / 127.0, -1.0, 1.0);", + "}" + ], + "body":[ + "uint w = (u >> 24);", + "uint z = (u >> 16);", + "uint y = (u >> 8);", + "uint x = u;", + "return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), ", + "webgl_fromSnorm8(z), webgl_fromSnorm8(w));" + ] + }, + { + "op":"unpackUnorm4x8", + "return_type":"float4", + "args":[ + "in uint u" + ], + "helper":[ + "float webgl_fromUnorm8(in uint x) {", + " return float(x) / 255.0;", + "}" + ], + "body":[ + "uint w = (u >> 24) & 0xffu;", + "uint z = (u >> 16) & 0xffu;", + "uint y = (u >> 8) & 0xffu;", + "uint x = u & 0xffu;", + "return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), ", + "webgl_fromUnorm8(z), webgl_fromUnorm8(w));" + ] + }, + { + "comment":[ + "The matrix resulting from outer product needs to be transposed", + "(matrices are stored as transposed to simplify element access in HLSL).", + "So the function should return transpose(c * r) where c is a column vector", + "and r is a row vector. This can be simplified by using the following", + "formula:", + "transpose(c * r) = transpose(r) * transpose(c)", + "transpose(r) and transpose(c) are in a sense free, since to get the", + "transpose of r, we simply can build a column matrix out of the original", + "vector instead of a row matrix." + ], + "op":"outerProduct", + "return_type":"float2x2", + "args":[ + "in float2 c", + "in float2 r" + ], + "body":[ + "return mul(float2x1(r), float1x2(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float3x3", + "args":[ + "in float3 c", + "in float3 r" + ], + "body":[ + "return mul(float3x1(r), float1x3(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float4x4", + "args":[ + "in float4 c", + "in float4 r" + ], + "body":[ + "return mul(float4x1(r), float1x4(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float2x3", + "args":[ + "in float3 c", + "in float2 r" + ], + "body":[ + "return mul(float2x1(r), float1x3(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float3x2", + "args":[ + "in float2 c", + "in float3 r" + ], + "body":[ + "return mul(float3x1(r), float1x2(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float2x4", + "args":[ + "in float4 c", + "in float2 r" + ], + "body":[ + "return mul(float2x1(r), float1x4(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float4x2", + "args":[ + "in float2 c", + "in float4 r" + ], + "body":[ + "return mul(float4x1(r), float1x2(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float3x4", + "args":[ + "in float4 c", + "in float3 r" + ], + "body":[ + "return mul(float3x1(r), float1x4(c));" + ] + }, + { + "op":"outerProduct", + "return_type":"float4x3", + "args":[ + "in float3 c", + "in float4 r" + ], + "body":[ + "return mul(float4x1(r), float1x3(c));" + ] + }, + { + "comment":[ + "Remember here that the parameter matrix is actually the transpose", + "of the matrix that we're trying to invert, and the resulting matrix", + "should also be the transpose of the inverse.", + "When accessing the parameter matrix with m[a][b] it can be thought of so", + "that a is the column and b is the row of the matrix that we're inverting.", + "We calculate the inverse as the adjugate matrix divided by the", + "determinant of the matrix being inverted. However, as the result needs", + "to be transposed, we actually use of the transpose of the adjugate matrix", + "which happens to be the cofactor matrix. That's stored in 'cof'.", + "We don't need to care about divide-by-zero since results are undefined", + "for singular or poorly-conditioned matrices." + ], + "op":"inverse", + "return_type":"float2x2", + "args":[ + "in float2x2 m" + ], + "body":[ + "float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };", + "return cof / determinant(transpose(m));" + ] + }, + { + "comment":[ + "cofAB is the cofactor for column A and row B." + ], + "op":"inverse", + "return_type":"float3x3", + "args":[ + "in float3x3 m" + ], + "body":[ + "float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];", + "float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);", + "float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];", + "float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);", + "float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];", + "float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);", + "float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];", + "float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);", + "float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];", + "float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };", + "return cof / determinant(transpose(m));" + ] + }, + { + "op":"inverse", + "return_type":"float4x4", + "args":[ + "in float4x4 m" + ], + "body":[ + "float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * ", + "m[1][2] * m[2][3]", + " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * ", + "m[1][3];", + "float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * ", + "m[1][2] * m[2][3]", + " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * ", + "m[1][3]);", + "float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * ", + "m[1][1] * m[2][3]", + " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * ", + "m[1][3];", + "float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * ", + "m[1][1] * m[2][2]", + " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * ", + "m[1][2]);", + "float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * ", + "m[0][2] * m[2][3]", + " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * ", + "m[0][3]);", + "float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * ", + "m[0][2] * m[2][3]", + " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * ", + "m[0][3];", + "float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * ", + "m[0][1] * m[2][3]", + " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * ", + "m[0][3]);", + "float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * ", + "m[0][1] * m[2][2]", + " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * ", + "m[0][2];", + "float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * ", + "m[0][2] * m[1][3]", + " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * ", + "m[0][3];", + "float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * ", + "m[0][2] * m[1][3]", + " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * ", + "m[0][3]);", + "float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * ", + "m[0][1] * m[1][3]", + " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * ", + "m[0][3];", + "float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * ", + "m[0][1] * m[1][2]", + " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * ", + "m[0][2]);", + "float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * ", + "m[0][2] * m[1][3]", + " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * ", + "m[0][3]);", + "float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * ", + "m[0][2] * m[1][3]", + " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * ", + "m[0][3];", + "float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * ", + "m[0][1] * m[1][3]", + " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * ", + "m[0][3]);", + "float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * ", + "m[0][1] * m[1][2]", + " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * ", + "m[0][2];", + "float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,", + " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };", + "return cof / determinant(transpose(m));" + ] + }, + { + "comment":[ + "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." + ], + "op":"mix", + "return_type":"float", + "args":[ + "float x", + "float y", + "bool a" + ], + "body":[ + "return a ? y : x;" + ] + }, + { + "op":"mix", + "return_type":"float2", + "args":[ + "float2 x", + "float2 y", + "bool2 a" + ], + "body":[ + "return a ? y : x;" + ] + }, + { + "op":"mix", + "return_type":"float3", + "args":[ + "float3 x", + "float3 y", + "bool3 a" + ], + "body":[ + "return a ? y : x;" + ] + }, + { + "op":"mix", + "return_type":"float4", + "args":[ + "float4 x", + "float4 y", + "bool4 a" + ], + "body":[ + "return a ? y : x;" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"uint", + "args":[ + "uint value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return 0u;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "return (value & mask) >> offset;" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"uint2", + "args":[ + "uint2 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return uint2(0u, 0u);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "return (value & mask) >> offset;" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"uint3", + "args":[ + "uint3 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return uint3(0u, 0u, 0u);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "return (value & mask) >> offset;" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"uint4", + "args":[ + "uint4 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return uint4(0u, 0u, 0u, 0u);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "return (value & mask) >> offset;" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"int", + "args":[ + "int value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return 0;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint resultUnsigned = (asuint(value) & mask) >> offset;", + "if (bits != 32 && (resultUnsigned & maskMsb) != 0)", + "{", + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;", + " resultUnsigned |= higherBitsMask;", + "}", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"int2", + "args":[ + "int2 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return int2(0, 0);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint2 resultUnsigned = (asuint(value) & mask) >> offset;", + "if (bits != 32)", + "{", + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;", + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;", + "}", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"int3", + "args":[ + "int3 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return int3(0, 0, 0);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint3 resultUnsigned = (asuint(value) & mask) >> offset;", + "if (bits != 32)", + "{", + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;", + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;", + "}", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldExtract", + "return_type":"int4", + "args":[ + "int4 value", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return int4(0, 0, 0, 0);", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint mask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint4 resultUnsigned = (asuint(value) & mask) >> offset;", + "if (bits != 32)", + "{", + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;", + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;", + "}", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"uint", + "args":[ + "uint base", + "uint insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "return (base & baseMask) | ((insert << offset) & insertMask);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"uint2", + "args":[ + "uint2 base", + "uint2 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "return (base & baseMask) | ((insert << offset) & insertMask);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"uint3", + "args":[ + "uint3 base", + "uint3 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "return (base & baseMask) | ((insert << offset) & insertMask);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"uint4", + "args":[ + "uint4 base", + "uint4 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "return (base & baseMask) | ((insert << offset) & insertMask);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"int", + "args":[ + "int base", + "int insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ", + " insertMask);", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"int2", + "args":[ + "int2 base", + "int2 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ", + " insertMask);", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"int3", + "args":[ + "int3 base", + "int3 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ", + " insertMask);", + "return asint(resultUnsigned);" + ] + }, + { + "op":"bitfieldInsert", + "return_type":"int4", + "args":[ + "int4 base", + "int4 insert", + "int offset", + "int bits" + ], + "body":[ + "if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)", + "{", + " return base;", + "}", + "uint maskMsb = (1u << (bits - 1));", + "uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;", + "uint baseMask = ~insertMask;", + "uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & ", + "insertMask);", + "return asint(resultUnsigned);" + ] + }, + { + "op":"uaddCarry", + "return_type":"uint", + "args":[ + "uint x", + "uint y", + "out uint carry" + ], + "body":[ + "carry = uint(x > (0xffffffffu - y));", + "return x + y;" + ] + }, + { + "op":"uaddCarry", + "return_type":"uint2", + "args":[ + "uint2 x", + "uint2 y", + "out uint2 carry" + ], + "body":[ + "carry = uint2(x > (0xffffffffu - y));", + "return x + y;" + ] + }, + { + "op":"uaddCarry", + "return_type":"uint3", + "args":[ + "uint3 x", + "uint3 y", + "out uint3 carry" + ], + "body":[ + "carry = uint3(x > (0xffffffffu - y));", + "return x + y;" + ] + }, + { + "op":"uaddCarry", + "return_type":"uint4", + "args":[ + "uint4 x", + "uint4 y", + "out uint4 carry" + ], + "body":[ + "carry = uint4(x > (0xffffffffu - y));", + "return x + y;" + ] + }, + { + "op":"usubBorrow", + "return_type":"uint", + "args":[ + "uint x", + "uint y", + "out uint borrow" + ], + "body":[ + "borrow = uint(x < y);", + "return x - y;" + ] + }, + { + "op":"usubBorrow", + "return_type":"uint2", + "args":[ + "uint2 x", + "uint2 y", + "out uint2 borrow" + ], + "body":[ + "borrow = uint2(x < y);", + "return x - y;" + ] + }, + { + "op":"usubBorrow", + "return_type":"uint3", + "args":[ + "uint3 x", + "uint3 y", + "out uint3 borrow" + ], + "body":[ + "borrow = uint3(x < y);", + "return x - y;" + ] + }, + { + "op":"usubBorrow", + "return_type":"uint4", + "args":[ + "uint4 x", + "uint4 y", + "out uint4 borrow" + ], + "body":[ + "borrow = uint4(x < y);", + "return x - y;" + ] + } +] diff --git a/src/3rdparty/angle/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp b/src/3rdparty/angle/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp new file mode 100644 index 0000000000..288da5e0f5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp @@ -0,0 +1,859 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_emulated_builtin_function_tables.py using data from +// emulated_builtin_function_data_hlsl.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// emulated_builtin_functions_hlsl: +// HLSL code for emulating GLSL builtin functions not present in HLSL. + +#include "compiler/translator/BuiltInFunctionEmulator.h" + +namespace sh +{ + +namespace +{ + +struct FunctionPair +{ + constexpr FunctionPair(const MiniFunctionId &idIn, const char *bodyIn) : id(idIn), body(bodyIn) + { + } + + MiniFunctionId id; + const char *body; +}; + +constexpr FunctionPair g_hlslFunctions[] = { + {{EOpMod, ParamType::Float1, ParamType::Float1}, + "float mod_emu(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float2, ParamType::Float2}, + "float2 mod_emu(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float2, ParamType::Float1}, + "float2 mod_emu(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float3, ParamType::Float3}, + "float3 mod_emu(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float3, ParamType::Float1}, + "float3 mod_emu(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float4, ParamType::Float4}, + "float4 mod_emu(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpMod, ParamType::Float4, ParamType::Float1}, + "float4 mod_emu(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {{EOpFrexp, ParamType::Float1, ParamType::Int1}, + "float frexp_emu(float x, out int exp)\n" + "{\n" + " float fexp;\n" + " float mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int(fexp);\n" + " return mantissa;\n" + "}\n"}, + {{EOpFrexp, ParamType::Float2, ParamType::Int2}, + "float2 frexp_emu(float2 x, out int2 exp)\n" + "{\n" + " float2 fexp;\n" + " float2 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int2(fexp);\n" + " return mantissa;\n" + "}\n"}, + {{EOpFrexp, ParamType::Float3, ParamType::Int3}, + "float3 frexp_emu(float3 x, out int3 exp)\n" + "{\n" + " float3 fexp;\n" + " float3 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int3(fexp);\n" + " return mantissa;\n" + "}\n"}, + {{EOpFrexp, ParamType::Float4, ParamType::Int4}, + "float4 frexp_emu(float4 x, out int4 exp)\n" + "{\n" + " float4 fexp;\n" + " float4 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int4(fexp);\n" + " return mantissa;\n" + "}\n"}, + {{EOpLdexp, ParamType::Float1, ParamType::Int1}, + "float ldexp_emu(float x, int exp)\n" + "{\n" + " return ldexp(x, float(exp));\n" + "}\n"}, + {{EOpLdexp, ParamType::Float2, ParamType::Int2}, + "float2 ldexp_emu(float2 x, int2 exp)\n" + "{\n" + " return ldexp(x, float2(exp));\n" + "}\n"}, + {{EOpLdexp, ParamType::Float3, ParamType::Int3}, + "float3 ldexp_emu(float3 x, int3 exp)\n" + "{\n" + " return ldexp(x, float3(exp));\n" + "}\n"}, + {{EOpLdexp, ParamType::Float4, ParamType::Int4}, + "float4 ldexp_emu(float4 x, int4 exp)\n" + "{\n" + " return ldexp(x, float4(exp));\n" + "}\n"}, + {{EOpFaceforward, ParamType::Float1, ParamType::Float1, ParamType::Float1}, + "float faceforward_emu(float N, float I, float Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {{EOpFaceforward, ParamType::Float2, ParamType::Float2, ParamType::Float2}, + "float2 faceforward_emu(float2 N, float2 I, float2 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {{EOpFaceforward, ParamType::Float3, ParamType::Float3, ParamType::Float3}, + "float3 faceforward_emu(float3 N, float3 I, float3 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {{EOpFaceforward, ParamType::Float4, ParamType::Float4, ParamType::Float4}, + "float4 faceforward_emu(float4 N, float4 I, float4 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {{EOpAtan, ParamType::Float1, ParamType::Float1}, + "float atan_emu(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" + " return atan2(y, x);\n" + "}\n"}, + {{EOpAtan, ParamType::Float2, ParamType::Float2}, + "float2 atan_emu(float2 y, float2 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" + "}\n"}, + {{EOpAtan, ParamType::Float3, ParamType::Float3}, + "float3 atan_emu(float3 y, float3 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" + "}\n"}, + {{EOpAtan, ParamType::Float4, ParamType::Float4}, + "float4 atan_emu(float4 y, float4 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" + " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], \n" + " x[2]), atan2(y[3], x[3]));\n" + "}\n"}, + {{EOpAsinh, ParamType::Float1}, + "float asinh_emu(in float x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {{EOpAsinh, ParamType::Float2}, + "float2 asinh_emu(in float2 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {{EOpAsinh, ParamType::Float3}, + "float3 asinh_emu(in float3 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {{EOpAsinh, ParamType::Float4}, + "float4 asinh_emu(in float4 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {{EOpAcosh, ParamType::Float1}, + "float acosh_emu(in float x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {{EOpAcosh, ParamType::Float2}, + "float2 acosh_emu(in float2 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {{EOpAcosh, ParamType::Float3}, + "float3 acosh_emu(in float3 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {{EOpAcosh, ParamType::Float4}, + "float4 acosh_emu(in float4 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {{EOpAtanh, ParamType::Float1}, + "float atanh_emu(in float x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {{EOpAtanh, ParamType::Float2}, + "float2 atanh_emu(in float2 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {{EOpAtanh, ParamType::Float3}, + "float3 atanh_emu(in float3 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {{EOpAtanh, ParamType::Float4}, + "float4 atanh_emu(in float4 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {{EOpRoundEven, ParamType::Float1}, + "float roundEven_emu(in float x)\n" + "{\n" + " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n" + "}\n"}, + {{EOpRoundEven, ParamType::Float2}, + "float2 roundEven_emu(in float2 x)\n" + "{\n" + " float2 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " return v;\n" + "}\n"}, + {{EOpRoundEven, ParamType::Float3}, + "float3 roundEven_emu(in float3 x)\n" + "{\n" + " float3 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " return v;\n" + "}\n"}, + {{EOpRoundEven, ParamType::Float4}, + "float4 roundEven_emu(in float4 x)\n" + "{\n" + " float4 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n" + " return v;\n" + "}\n"}, + {{EOpPackSnorm2x16, ParamType::Float2}, + "int webgl_toSnorm16(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n" + "}\n" + "uint packSnorm2x16_emu(in float2 v)\n" + "{\n" + " int x = webgl_toSnorm16(v.x);\n" + " int y = webgl_toSnorm16(v.y);\n" + " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n" + "}\n"}, + {{EOpPackUnorm2x16, ParamType::Float2}, + "uint webgl_toUnorm16(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n" + "}\n" + "uint packUnorm2x16_emu(in float2 v)\n" + "{\n" + " uint x = webgl_toUnorm16(v.x);\n" + " uint y = webgl_toUnorm16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"}, + {{EOpPackHalf2x16, ParamType::Float2}, + "uint packHalf2x16_emu(in float2 v)\n" + "{\n" + " uint x = f32tof16(v.x);\n" + " uint y = f32tof16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"}, + {{EOpUnpackSnorm2x16, ParamType::Uint1}, + "float webgl_fromSnorm16(in uint x) {\n" + " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n" + " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" + "}\n" + "float2 unpackSnorm2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u;\n" + " return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n" + "}\n"}, + {{EOpUnpackUnorm2x16, ParamType::Uint1}, + "float webgl_fromUnorm16(in uint x) {\n" + " return float(x) / 65535.0;\n" + "}\n" + "float2 unpackUnorm2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n" + "}\n"}, + {{EOpUnpackHalf2x16, ParamType::Uint1}, + "float2 unpackHalf2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(f16tof32(x), f16tof32(y));\n" + "}\n"}, + {{EOpPackSnorm4x8, ParamType::Float4}, + "int webgl_toSnorm8(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 127.0));\n" + "}\n" + "uint packSnorm4x8_emu(in float4 v)\n" + "{\n" + " int x = webgl_toSnorm8(v.x);\n" + " int y = webgl_toSnorm8(v.y);\n" + " int z = webgl_toSnorm8(v.z);\n" + " int w = webgl_toSnorm8(v.w);\n" + " return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) \n" + " | ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n" + "}\n"}, + {{EOpPackUnorm4x8, ParamType::Float4}, + "uint webgl_toUnorm8(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n" + "}\n" + "uint packUnorm4x8_emu(in float4 v)\n" + "{\n" + " uint x = webgl_toUnorm8(v.x);\n" + " uint y = webgl_toUnorm8(v.y);\n" + " uint z = webgl_toUnorm8(v.z);\n" + " uint w = webgl_toUnorm8(v.w);\n" + " return (w << 24) | (z << 16) | (y << 8) | x;\n" + "}\n"}, + {{EOpUnpackSnorm4x8, ParamType::Uint1}, + "float webgl_fromSnorm8(in uint x) {\n" + " int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n" + " return clamp(float(xi) / 127.0, -1.0, 1.0);\n" + "}\n" + "float4 unpackSnorm4x8_emu(in uint u)\n" + "{\n" + " uint w = (u >> 24);\n" + " uint z = (u >> 16);\n" + " uint y = (u >> 8);\n" + " uint x = u;\n" + " return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), \n" + " webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n" + "}\n"}, + {{EOpUnpackUnorm4x8, ParamType::Uint1}, + "float webgl_fromUnorm8(in uint x) {\n" + " return float(x) / 255.0;\n" + "}\n" + "float4 unpackUnorm4x8_emu(in uint u)\n" + "{\n" + " uint w = (u >> 24) & 0xffu;\n" + " uint z = (u >> 16) & 0xffu;\n" + " uint y = (u >> 8) & 0xffu;\n" + " uint x = u & 0xffu;\n" + " return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), \n" + " webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n" + "}\n"}, + // The matrix resulting from outer product needs to be transposed + // (matrices are stored as transposed to simplify element access in HLSL). + // So the function should return transpose(c * r) where c is a column vector + // and r is a row vector. This can be simplified by using the following + // formula: + // transpose(c * r) = transpose(r) * transpose(c) + // transpose(r) and transpose(c) are in a sense free, since to get the + // transpose of r, we simply can build a column matrix out of the original + // vector instead of a row matrix. + {{EOpOuterProduct, ParamType::Float2, ParamType::Float2}, + "float2x2 outerProduct_emu(in float2 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x2(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float3, ParamType::Float3}, + "float3x3 outerProduct_emu(in float3 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x3(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float4, ParamType::Float4}, + "float4x4 outerProduct_emu(in float4 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x4(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float3, ParamType::Float2}, + "float2x3 outerProduct_emu(in float3 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x3(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float2, ParamType::Float3}, + "float3x2 outerProduct_emu(in float2 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x2(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float4, ParamType::Float2}, + "float2x4 outerProduct_emu(in float4 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x4(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float2, ParamType::Float4}, + "float4x2 outerProduct_emu(in float2 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x2(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float4, ParamType::Float3}, + "float3x4 outerProduct_emu(in float4 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x4(c));\n" + "}\n"}, + {{EOpOuterProduct, ParamType::Float3, ParamType::Float4}, + "float4x3 outerProduct_emu(in float3 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x3(c));\n" + "}\n"}, + // Remember here that the parameter matrix is actually the transpose + // of the matrix that we're trying to invert, and the resulting matrix + // should also be the transpose of the inverse. + // When accessing the parameter matrix with m[a][b] it can be thought of so + // that a is the column and b is the row of the matrix that we're inverting. + // We calculate the inverse as the adjugate matrix divided by the + // determinant of the matrix being inverted. However, as the result needs + // to be transposed, we actually use of the transpose of the adjugate matrix + // which happens to be the cofactor matrix. That's stored in 'cof'. + // We don't need to care about divide-by-zero since results are undefined + // for singular or poorly-conditioned matrices. + {{EOpInverse, ParamType::Mat2}, + "float2x2 inverse_emu(in float2x2 m)\n" + "{\n" + " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + // cofAB is the cofactor for column A and row B. + {{EOpInverse, ParamType::Mat3}, + "float3x3 inverse_emu(in float3x3 m)\n" + "{\n" + " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n" + " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n" + " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n" + " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n" + " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n" + " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n" + " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n" + " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n" + " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n" + " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + {{EOpInverse, ParamType::Mat4}, + "float4x4 inverse_emu(in float4x4 m)\n" + "{\n" + " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * \n" + " m[1][2] * m[2][3]\n" + " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * \n" + " m[1][3];\n" + " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * \n" + " m[1][2] * m[2][3]\n" + " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * \n" + " m[1][3]);\n" + " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * \n" + " m[1][1] * m[2][3]\n" + " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * \n" + " m[1][3];\n" + " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * \n" + " m[1][1] * m[2][2]\n" + " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * \n" + " m[1][2]);\n" + " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * \n" + " m[0][2] * m[2][3]\n" + " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * \n" + " m[0][3]);\n" + " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * \n" + " m[0][2] * m[2][3]\n" + " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * \n" + " m[0][3];\n" + " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * \n" + " m[0][1] * m[2][3]\n" + " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * \n" + " m[0][3]);\n" + " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * \n" + " m[0][1] * m[2][2]\n" + " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * \n" + " m[0][2];\n" + " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * \n" + " m[0][3];\n" + " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * \n" + " m[0][3]);\n" + " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * \n" + " m[0][1] * m[1][3]\n" + " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * \n" + " m[0][3];\n" + " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * \n" + " m[0][1] * m[1][2]\n" + " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * \n" + " m[0][2]);\n" + " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * \n" + " m[0][3]);\n" + " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * \n" + " m[0][3];\n" + " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * \n" + " m[0][1] * m[1][3]\n" + " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * \n" + " m[0][3]);\n" + " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * \n" + " m[0][1] * m[1][2]\n" + " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * \n" + " m[0][2];\n" + " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,\n" + " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + // 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. + {{EOpMix, ParamType::Float1, ParamType::Float1, ParamType::Bool1}, + "float mix_emu(float x, float y, bool a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {{EOpMix, ParamType::Float2, ParamType::Float2, ParamType::Bool2}, + "float2 mix_emu(float2 x, float2 y, bool2 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {{EOpMix, ParamType::Float3, ParamType::Float3, ParamType::Bool3}, + "float3 mix_emu(float3 x, float3 y, bool3 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {{EOpMix, ParamType::Float4, ParamType::Float4, ParamType::Bool4}, + "float4 mix_emu(float4 x, float4 y, bool4 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Uint1, ParamType::Int1, ParamType::Int1}, + "uint bitfieldExtract_emu(uint value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return 0u;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Uint2, ParamType::Int1, ParamType::Int1}, + "uint2 bitfieldExtract_emu(uint2 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint2(0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Uint3, ParamType::Int1, ParamType::Int1}, + "uint3 bitfieldExtract_emu(uint3 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint3(0u, 0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Uint4, ParamType::Int1, ParamType::Int1}, + "uint4 bitfieldExtract_emu(uint4 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint4(0u, 0u, 0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Int1, ParamType::Int1, ParamType::Int1}, + "int bitfieldExtract_emu(int value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return 0;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32 && (resultUnsigned & maskMsb) != 0)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Int2, ParamType::Int1, ParamType::Int1}, + "int2 bitfieldExtract_emu(int2 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int2(0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint2 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Int3, ParamType::Int1, ParamType::Int1}, + "int3 bitfieldExtract_emu(int3 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int3(0, 0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint3 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldExtract, ParamType::Int4, ParamType::Int1, ParamType::Int1}, + "int4 bitfieldExtract_emu(int4 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int4(0, 0, 0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint4 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Uint1, ParamType::Uint1, ParamType::Int1, ParamType::Int1}, + "uint bitfieldInsert_emu(uint base, uint insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Uint2, ParamType::Uint2, ParamType::Int1, ParamType::Int1}, + "uint2 bitfieldInsert_emu(uint2 base, uint2 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Uint3, ParamType::Uint3, ParamType::Int1, ParamType::Int1}, + "uint3 bitfieldInsert_emu(uint3 base, uint3 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Uint4, ParamType::Uint4, ParamType::Int1, ParamType::Int1}, + "uint4 bitfieldInsert_emu(uint4 base, uint4 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Int1, ParamType::Int1, ParamType::Int1, ParamType::Int1}, + "int bitfieldInsert_emu(int base, int insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Int2, ParamType::Int2, ParamType::Int1, ParamType::Int1}, + "int2 bitfieldInsert_emu(int2 base, int2 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Int3, ParamType::Int3, ParamType::Int1, ParamType::Int1}, + "int3 bitfieldInsert_emu(int3 base, int3 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpBitfieldInsert, ParamType::Int4, ParamType::Int4, ParamType::Int1, ParamType::Int1}, + "int4 bitfieldInsert_emu(int4 base, int4 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {{EOpUaddCarry, ParamType::Uint1, ParamType::Uint1, ParamType::Uint1}, + "uint uaddCarry_emu(uint x, uint y, out uint carry)\n" + "{\n" + " carry = uint(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {{EOpUaddCarry, ParamType::Uint2, ParamType::Uint2, ParamType::Uint2}, + "uint2 uaddCarry_emu(uint2 x, uint2 y, out uint2 carry)\n" + "{\n" + " carry = uint2(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {{EOpUaddCarry, ParamType::Uint3, ParamType::Uint3, ParamType::Uint3}, + "uint3 uaddCarry_emu(uint3 x, uint3 y, out uint3 carry)\n" + "{\n" + " carry = uint3(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {{EOpUaddCarry, ParamType::Uint4, ParamType::Uint4, ParamType::Uint4}, + "uint4 uaddCarry_emu(uint4 x, uint4 y, out uint4 carry)\n" + "{\n" + " carry = uint4(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {{EOpUsubBorrow, ParamType::Uint1, ParamType::Uint1, ParamType::Uint1}, + "uint usubBorrow_emu(uint x, uint y, out uint borrow)\n" + "{\n" + " borrow = uint(x < y);\n" + " return x - y;\n" + "}\n"}, + {{EOpUsubBorrow, ParamType::Uint2, ParamType::Uint2, ParamType::Uint2}, + "uint2 usubBorrow_emu(uint2 x, uint2 y, out uint2 borrow)\n" + "{\n" + " borrow = uint2(x < y);\n" + " return x - y;\n" + "}\n"}, + {{EOpUsubBorrow, ParamType::Uint3, ParamType::Uint3, ParamType::Uint3}, + "uint3 usubBorrow_emu(uint3 x, uint3 y, out uint3 borrow)\n" + "{\n" + " borrow = uint3(x < y);\n" + " return x - y;\n" + "}\n"}, + {{EOpUsubBorrow, ParamType::Uint4, ParamType::Uint4, ParamType::Uint4}, + "uint4 usubBorrow_emu(uint4 x, uint4 y, out uint4 borrow)\n" + "{\n" + " borrow = uint4(x < y);\n" + " return x - y;\n" + "}\n"}, +}; +} // anonymous namespace + +const char *FindHLSLFunction(const FunctionId &functionID) +{ + for (size_t index = 0; index < ArraySize(g_hlslFunctions); ++index) + { + const auto &function = g_hlslFunctions[index]; + if (function.id == functionID) + { + return function.body; + } + } + + return nullptr; +} +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.h b/src/3rdparty/angle/src/compiler/translator/glslang.h index 0555e96d45..e54c31ba3e 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.h +++ b/src/3rdparty/angle/src/compiler/translator/glslang.h @@ -7,14 +7,18 @@ #ifndef COMPILER_TRANSLATOR_GLSLANG_H_ #define COMPILER_TRANSLATOR_GLSLANG_H_ +namespace sh +{ class TParseContext; -extern int glslang_initialize(TParseContext* context); -extern int glslang_finalize(TParseContext* context); +} + +extern int glslang_initialize(sh::TParseContext *context); +extern int glslang_finalize(sh::TParseContext *context); extern int glslang_scan(size_t count, - const char* const string[], + const char *const string[], const int length[], - TParseContext* context); -extern int glslang_parse(TParseContext* context); + sh::TParseContext *context); +extern int glslang_parse(sh::TParseContext *context); -#endif // COMPILER_TRANSLATOR_GLSLANG_H_ +#endif // COMPILER_TRANSLATOR_GLSLANG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.l b/src/3rdparty/angle/src/compiler/translator/glslang.l index d09358dd8a..858ffd96bb 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.l +++ b/src/3rdparty/angle/src/compiler/translator/glslang.l @@ -22,6 +22,8 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). // This file is auto-generated by generate_parser.sh. DO NOT EDIT! +/* clang-format off */ + // Ignore errors in auto-generated code. #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" @@ -44,6 +46,9 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). #include "compiler/preprocessor/Token.h" #include "compiler/translator/util.h" #include "compiler/translator/length_limits.h" + +using namespace sh; + #include "glslang_tab.h" /* windows only pragma */ @@ -71,10 +76,16 @@ static int reserved_word(yyscan_t yyscanner); static int ES2_reserved_ES3_keyword(TParseContext *context, int token); static int ES2_keyword_ES3_reserved(TParseContext *context, int token); static int ES2_ident_ES3_keyword(TParseContext *context, int token); +static int ES2_ident_ES3_keyword_multiview_keyword(TParseContext *context, int token); +static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); +static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); +static int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token); +static int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token); static int uint_constant(TParseContext *context); static int int_constant(TParseContext *context); static int float_constant(yyscan_t yyscanner); static int floatsuffix_check(TParseContext* context); +static int yuvcscstandardext_constant(TParseContext *context); %} %option noyywrap nounput never-interactive @@ -103,6 +114,7 @@ O [0-7] "attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } "const" { return CONST_QUAL; } "uniform" { return UNIFORM; } +"buffer" { return ES2_and_ES3_ident_ES3_1_keyword(context, BUFFER); } "varying" { return ES2_keyword_ES3_reserved(context, VARYING); } "break" { return BREAK; } @@ -124,6 +136,7 @@ O [0-7] "in" { return IN_QUAL; } "out" { return OUT_QUAL; } "inout" { return INOUT_QUAL; } +"shared" { return ES2_and_ES3_ident_ES3_1_keyword(context, SHARED); } "float" { return FLOAT_TYPE; } "int" { return INT_TYPE; } @@ -171,29 +184,52 @@ O [0-7] "sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } "sampler2DRect" { return SAMPLER2DRECT; } "sampler2DArray" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); } +"sampler2DMS" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, SAMPLER2DMS); } "isampler2D" { return ES2_ident_ES3_keyword(context, ISAMPLER2D); } "isampler3D" { return ES2_ident_ES3_keyword(context, ISAMPLER3D); } "isamplerCube" { return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); } "isampler2DArray" { return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); } +"isampler2DMS" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, ISAMPLER2DMS); } "usampler2D" { return ES2_ident_ES3_keyword(context, USAMPLER2D); } "usampler3D" { return ES2_ident_ES3_keyword(context, USAMPLER3D); } "usamplerCube" { return ES2_ident_ES3_keyword(context, USAMPLERCUBE); } "usampler2DArray" { return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); } +"usampler2DMS" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, USAMPLER2DMS); } "sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } "samplerCubeShadow" { return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); } "sampler2DArrayShadow" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } +"__samplerExternal2DY2YEXT" { return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, SAMPLEREXTERNAL2DY2YEXT); } "struct" { return STRUCT; } -"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); } +"layout" { return ES2_ident_ES3_keyword_multiview_keyword(context, LAYOUT); } + +"yuvCscStandardEXT" { return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, YUVCSCSTANDARDEXT); } +"itu_601" { return yuvcscstandardext_constant(context); } +"itu_601_full_range" { return yuvcscstandardext_constant(context); } +"itu_709" { return yuvcscstandardext_constant(context); } + +"image2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2D); } +"iimage2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2D); } +"uimage2D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2D); } +"image2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2DARRAY); } +"iimage2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2DARRAY); } +"uimage2DArray" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2DARRAY); } +"image3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE3D); } +"uimage3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE3D); } +"iimage3D" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE3D); } +"iimageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGECUBE); } +"uimageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGECUBE); } +"imageCube" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); } +"readonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); } +"writeonly" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); } +"coherent" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, COHERENT); } +"restrict" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, RESTRICT); } +"volatile" { return ES2_and_ES3_reserved_ES3_1_keyword(context, VOLATILE); } +"atomic_uint" { return ES2_ident_ES3_reserved_ES3_1_keyword(context, ATOMICUINT); } /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ -"coherent" | -"restrict" | -"readonly" | -"writeonly" | "resource" | -"atomic_uint" | "noperspective" | "patch" | "sample" | @@ -204,23 +240,11 @@ O [0-7] "filter" | "image1D" | -"image2D" | -"image3D" | -"imageCube" | "iimage1D" | -"iimage2D" | -"iimage3D" | -"iimageCube" | "uimage1D" | -"uimage2D" | -"uimage3D" | -"uimageCube" | "image1DArray" | -"image2DArray" | "iimage1DArray" | -"iimage2DArray" | "uimage1DArray" | -"uimage2DArray" | "image1DShadow" | "image2DShadow" | "image1DArrayShadow" | @@ -240,9 +264,6 @@ O [0-7] "samplerBuffer" | "isamplerBuffer" | "usamplerBuffer" | -"sampler2DMS" | -"isampler2DMS" | -"usampler2DMS" | "sampler2DMSArray" | "isampler2DMSArray" | "usampler2DMSArray" { @@ -278,7 +299,6 @@ O [0-7] "inline" | "noinline" | -"volatile" | "public" | "static" | "extern" | @@ -390,6 +410,10 @@ O [0-7] return FIELD_SELECTION; } [ \t\v\f\r] {} +. { + yyextra->error(*yylloc, "Illegal character at fieldname start", yytext); + return 0; +} [ \t\v\n\f\r] { } <*><> { yyterminate(); } @@ -431,8 +455,7 @@ int check_type(yyscan_t yyscanner) { int reserved_word(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; - yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); - yyextra->recover(); + yyextra->error(*yylloc, "Illegal use of reserved word", yytext); return 0; } @@ -460,6 +483,24 @@ int ES2_keyword_ES3_reserved(TParseContext *context, int token) return token; } +int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() < 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + else if (context->getShaderVersion() == 300) + { + return reserved_word(yyscanner); + } + + return token; +} + int ES2_ident_ES3_keyword(TParseContext *context, int token) { struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); @@ -475,19 +516,76 @@ int ES2_ident_ES3_keyword(TParseContext *context, int token) return token; } +int ES2_ident_ES3_keyword_multiview_keyword(TParseContext *context, int token) +{ + 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 + // except when multiview extension is enabled + if (context->getShaderVersion() < 300 && !context->isExtensionEnabled(TExtension::OVR_multiview)) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return token; +} + +int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() < 310) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token) +{ + 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 and GLSL ES 3.00, so could be used as an identifier/type name + if (context->getShaderVersion() < 310) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return token; +} + +int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name + if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(extension)) + { + return token; + } + + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + int uint_constant(TParseContext *context) { struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); if (context->getShaderVersion() < 300) { - context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); - context->recover(); + context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext); return 0; } if (!atoi_clamp(yytext, &(yylval->lex.u))) - yyextra->error(*yylloc, "Integer overflow", yytext, ""); + yyextra->error(*yylloc, "Integer overflow", yytext); return UINTCONSTANT; } @@ -499,21 +597,19 @@ int floatsuffix_check(TParseContext* context) if (context->getShaderVersion() < 300) { context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); - context->recover(); return 0; } std::string text = yytext; text.resize(text.size() - 1); if (!strtof_clamp(text, &(yylval->lex.f))) - yyextra->warning(*yylloc, "Float overflow", yytext, ""); + yyextra->warning(*yylloc, "Float overflow", yytext); return(FLOATCONSTANT); } void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { context->error(*lloc, reason, yyget_text(scanner)); - context->recover(); } int int_constant(TParseContext *context) { @@ -523,9 +619,9 @@ int int_constant(TParseContext *context) { if (!atoi_clamp(yytext, &u)) { if (context->getShaderVersion() >= 300) - yyextra->error(*yylloc, "Integer overflow", yytext, ""); + yyextra->error(*yylloc, "Integer overflow", yytext); else - yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + yyextra->warning(*yylloc, "Integer overflow", yytext); } yylval->lex.i = static_cast(u); return INTCONSTANT; @@ -535,10 +631,26 @@ int float_constant(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; if (!strtof_clamp(yytext, &(yylval->lex.f))) - yyextra->warning(*yylloc, "Float overflow", yytext, ""); + yyextra->warning(*yylloc, "Float overflow", yytext); return FLOATCONSTANT; } +int yuvcscstandardext_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name + if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(TExtension::EXT_YUV_target)) + { + yylval->lex.string = NewPoolTString(yytext); + return YUVCSCSTANDARDEXTCONSTANT; + } + + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + int glslang_initialize(TParseContext* context) { yyscan_t scanner = NULL; if (yylex_init_extra(context, &scanner)) @@ -574,13 +686,12 @@ int glslang_scan(size_t count, const char* const string[], const int length[], const TExtensionBehavior& extBehavior = context->extensionBehavior(); for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end(); ++iter) { - preprocessor->predefineMacro(iter->first.c_str(), 1); + preprocessor->predefineMacro(GetExtensionNameString(iter->first), 1); } if (context->getFragmentPrecisionHigh()) preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); - preprocessor->setMaxTokenSize(GetGlobalMaxTokenSize(context->getShaderSpec())); + preprocessor->setMaxTokenSize(sh::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 aba2706311..3e506caac8 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.y +++ b/src/3rdparty/angle/src/compiler/translator/glslang.y @@ -22,6 +22,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). // This file is auto-generated by generate_parser.sh. DO NOT EDIT! +// clang-format off + // Ignore errors in auto-generated code. #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" @@ -44,6 +46,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #define YYENABLE_NLS 0 +using namespace sh; + %} %expect 1 /* One shift reduce conflict because of if | else */ %parse-param {TParseContext* context} @@ -70,22 +74,30 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). struct { TOperator op; union { - TIntermNode* intermNode; + TIntermNode *intermNode; TIntermNodePair nodePair; - TIntermTyped* intermTypedNode; - TIntermAggregate* intermAggregate; - TIntermSwitch* intermSwitch; - TIntermCase* intermCase; + TIntermFunctionCallOrMethod callOrMethodPair; + TIntermTyped *intermTypedNode; + TIntermAggregate *intermAggregate; + TIntermBlock *intermBlock; + TIntermDeclaration *intermDeclaration; + TIntermFunctionPrototype *intermFunctionPrototype; + TIntermSwitch *intermSwitch; + TIntermCase *intermCase; }; union { + TVector *arraySizes; + TTypeSpecifierNonArray typeSpecifierNonArray; TPublicType type; TPrecision precision; TLayoutQualifier layoutQualifier; TQualifier qualifier; - TFunction* function; + TFunction *function; TParameter param; - TField* field; - TFieldList* fieldList; + TField *field; + TFieldList *fieldList; + TQualifierWrapperBase *qualifierWrapper; + TTypeQualifierBuilder *typeQualifierBuilder; }; } interm; } @@ -112,29 +124,37 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons #define VERTEX_ONLY(S, L) { \ if (context->getShaderType() != GL_VERTEX_SHADER) { \ - context->error(L, " supported in vertex shaders only ", S); \ - context->recover(); \ + context->error(L, " supported in vertex shaders only", S); \ } \ } -#define FRAG_ONLY(S, L) { \ - if (context->getShaderType() != GL_FRAGMENT_SHADER) { \ - context->error(L, " supported in fragment shaders only ", S); \ - context->recover(); \ +#define COMPUTE_ONLY(S, L) { \ + if (context->getShaderType() != GL_COMPUTE_SHADER) { \ + context->error(L, " supported in compute shaders only", S); \ } \ } #define ES2_ONLY(S, L) { \ if (context->getShaderVersion() != 100) { \ - context->error(L, " supported in GLSL ES 1.00 only ", S); \ - context->recover(); \ + context->error(L, " supported in GLSL ES 1.00 only", S); \ + } \ +} + +#define ES3_OR_NEWER(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() < 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 and above only", TOKEN); \ } \ } -#define ES3_ONLY(TOKEN, LINE, REASON) { \ - if (context->getShaderVersion() != 300) { \ - context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ - context->recover(); \ +#define ES3_OR_NEWER_OR_MULTIVIEW(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() < 300 && !context->isExtensionEnabled(TExtension::OVR_multiview)) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 and above only", TOKEN); \ + } \ +} + +#define ES3_1_ONLY(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() != 310) { \ + context->error(LINE, REASON " supported in GLSL ES 3.10 only", TOKEN); \ } \ } %} @@ -143,15 +163,22 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons %token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE %token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT %token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4 -%token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM BUFFER VARYING %token MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 %token CENTROID FLAT SMOOTH +%token READONLY WRITEONLY COHERENT RESTRICT VOLATILE SHARED %token STRUCT VOID_TYPE WHILE %token SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY %token ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY %token USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY +%token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS %token SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW +%token SAMPLEREXTERNAL2DY2YEXT +%token IMAGE2D IIMAGE2D UIMAGE2D IMAGE3D IIMAGE3D UIMAGE3D IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY +%token IMAGECUBE IIMAGECUBE UIMAGECUBE +%token ATOMICUINT %token LAYOUT +%token YUVCSCSTANDARDEXT YUVCSCSTANDARDEXTCONSTANT %token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT %token FIELD_SELECTION @@ -166,7 +193,7 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons %token LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION %type identifier -%type assignment_operator unary_operator +%type assignment_operator unary_operator %type variable_identifier primary_expression postfix_expression %type expression integer_expression assignment_expression %type unary_expression multiplicative_expression additive_expression @@ -174,11 +201,12 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons %type conditional_expression constant_expression %type logical_or_expression logical_xor_expression logical_and_expression %type shift_expression and_expression exclusive_or_expression inclusive_or_expression -%type function_call initializer condition conditionopt +%type function_call initializer -%type translation_unit function_definition -%type statement simple_statement -%type statement_list compound_statement compound_statement_no_new_scope +%type condition conditionopt +%type translation_unit +%type function_definition statement simple_statement +%type statement_list compound_statement_with_scope compound_statement_no_new_scope %type declaration_statement selection_statement expression_statement %type declaration external_declaration %type for_init_statement @@ -188,14 +216,22 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons %type iteration_statement jump_statement statement_no_new_scope statement_with_scope %type single_declaration init_declarator_list -%type parameter_declaration parameter_declarator parameter_type_specifier -%type parameter_qualifier parameter_type_qualifier -%type layout_qualifier layout_qualifier_id_list layout_qualifier_id +%type parameter_declaration parameter_declarator parameter_type_specifier +%type layout_qualifier_id_list layout_qualifier_id + +// Note: array_specifier guaranteed to be non-null. +%type array_specifier + +%type fully_specified_type type_specifier %type precision_qualifier -%type type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier -%type type_specifier_no_prec type_specifier_nonarray -%type struct_specifier +%type layout_qualifier +%type interpolation_qualifier +%type storage_qualifier single_type_qualifier invariant_qualifier +%type type_qualifier + +%type type_specifier_nonarray struct_specifier +%type type_specifier_no_prec %type struct_declarator %type struct_declarator_list struct_declaration struct_declaration_list %type function_header function_declarator function_identifier @@ -229,22 +265,31 @@ primary_expression | INTCONSTANT { TConstantUnion *unionArray = new TConstantUnion[1]; unionArray->setIConst($1.i); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1); + $$ = context->addScalarLiteral(unionArray, @1); } | UINTCONSTANT { TConstantUnion *unionArray = new TConstantUnion[1]; unionArray->setUConst($1.u); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1); + $$ = context->addScalarLiteral(unionArray, @1); } | FLOATCONSTANT { TConstantUnion *unionArray = new TConstantUnion[1]; unionArray->setFConst($1.f); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1); + $$ = context->addScalarLiteral(unionArray, @1); } | BOOLCONSTANT { TConstantUnion *unionArray = new TConstantUnion[1]; unionArray->setBConst($1.b); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1); + $$ = context->addScalarLiteral(unionArray, @1); + } + | YUVCSCSTANDARDEXTCONSTANT { + if (!context->checkCanUseExtension(@1, TExtension::EXT_YUV_target)) + { + context->error(@1, "unsupported value", $1.string->c_str()); + } + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setYuvCscStandardEXTConst(getYuvCscStandardEXT($1.string->c_str())); + $$ = context->addScalarLiteral(unionArray, @1); } | LEFT_PAREN expression RIGHT_PAREN { $$ = $2; @@ -274,32 +319,26 @@ postfix_expression integer_expression : expression { - if (context->integerErrorCheck($1, "[]")) - context->recover(); + context->checkIsScalarInteger($1, "[]"); $$ = $1; } ; function_call : function_call_or_method { - bool fatalError = false; - $$ = context->addFunctionCallOrMethod($1.function, $1.nodePair.node1, $1.nodePair.node2, @1, &fatalError); - if (fatalError) - { - YYERROR; - } + $$ = context->addFunctionCallOrMethod($1.function, $1.callOrMethodPair.arguments, $1.callOrMethodPair.thisNode, @1); } ; function_call_or_method : function_call_generic { $$ = $1; - $$.nodePair.node2 = nullptr; + $$.callOrMethodPair.thisNode = nullptr; } | postfix_expression DOT function_call_generic { - ES3_ONLY("", @3, "methods"); + ES3_OR_NEWER("", @3, "methods"); $$ = $3; - $$.nodePair.node2 = $1; + $$.callOrMethodPair.thisNode = $1; } ; @@ -315,26 +354,23 @@ function_call_generic function_call_header_no_parameters : function_call_header VOID_TYPE { $$.function = $1; - $$.nodePair.node1 = nullptr; + $$.callOrMethodPair.arguments = context->createEmptyArgumentsList(); } | function_call_header { $$.function = $1; - $$.nodePair.node1 = nullptr; + $$.callOrMethodPair.arguments = context->createEmptyArgumentsList(); } ; function_call_header_with_parameters : function_call_header assignment_expression { - const TType *type = new TType($2->getType()); - $1->addParameter(TConstParameter(type)); + $$.callOrMethodPair.arguments = context->createEmptyArgumentsList(); $$.function = $1; - $$.nodePair.node1 = context->intermediate.makeAggregate($2, @2); + $$.callOrMethodPair.arguments->push_back($2); } | function_call_header_with_parameters COMMA assignment_expression { - const TType *type = new TType($3->getType()); - $1.function->addParameter(TConstParameter(type)); $$.function = $1.function; - $$.nodePair.node1 = context->intermediate.growAggregate($1.intermNode, $3, @2); + $$.callOrMethodPair.arguments->push_back($3); } ; @@ -348,24 +384,13 @@ function_call_header function_identifier : type_specifier_no_prec { - if ($1.array) { - ES3_ONLY("[]", @1, "array constructor"); - } $$ = context->addConstructorFunc($1); } | IDENTIFIER { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); - const TType *type = TCache::getType(EbtVoid, EbpUndefined); - TFunction *function = new TFunction($1.string, type); - $$ = function; + $$ = context->addNonConstructorFunc($1.string, @1); } | FIELD_SELECTION { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); - const TType *type = TCache::getType(EbtVoid, EbpUndefined); - TFunction *function = new TFunction($1.string, type); - $$ = function; + $$ = context->addNonConstructorFunc($1.string, @1); } ; @@ -380,21 +405,18 @@ unary_expression $$ = context->addUnaryMathLValue(EOpPreDecrement, $2, @1); } | unary_operator unary_expression { - if ($1.op != EOpNull) { - $$ = context->addUnaryMath($1.op, $2, @1); - } else - $$ = $2; + $$ = context->addUnaryMath($1, $2, @1); } ; // Grammar Note: No traditional style type casts. unary_operator - : PLUS { $$.op = EOpPositive; } - | DASH { $$.op = EOpNegative; } - | BANG { $$.op = EOpLogicalNot; } + : PLUS { $$ = EOpPositive; } + | DASH { $$ = EOpNegative; } + | BANG { $$ = EOpLogicalNot; } | TILDE { - ES3_ONLY("~", @$, "bit-wise operator"); - $$.op = EOpBitwiseNot; + ES3_OR_NEWER("~", @$, "bit-wise operator"); + $$ = EOpBitwiseNot; } ; // Grammar Note: No '*' or '&' unary ops. Pointers are not supported. @@ -408,7 +430,7 @@ multiplicative_expression $$ = context->addBinaryMath(EOpDiv, $1, $3, @2); } | multiplicative_expression PERCENT unary_expression { - ES3_ONLY("%", @2, "integer modulus operator"); + ES3_OR_NEWER("%", @2, "integer modulus operator"); $$ = context->addBinaryMath(EOpIMod, $1, $3, @2); } ; @@ -426,11 +448,11 @@ additive_expression shift_expression : additive_expression { $$ = $1; } | shift_expression LEFT_OP additive_expression { - ES3_ONLY("<<", @2, "bit-wise operator"); + ES3_OR_NEWER("<<", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2); } | shift_expression RIGHT_OP additive_expression { - ES3_ONLY(">>", @2, "bit-wise operator"); + ES3_OR_NEWER(">>", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2); } ; @@ -464,7 +486,7 @@ equality_expression and_expression : equality_expression { $$ = $1; } | and_expression AMPERSAND equality_expression { - ES3_ONLY("&", @2, "bit-wise operator"); + ES3_OR_NEWER("&", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2); } ; @@ -472,7 +494,7 @@ and_expression exclusive_or_expression : and_expression { $$ = $1; } | exclusive_or_expression CARET and_expression { - ES3_ONLY("^", @2, "bit-wise operator"); + ES3_OR_NEWER("^", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2); } ; @@ -480,7 +502,7 @@ exclusive_or_expression inclusive_or_expression : exclusive_or_expression { $$ = $1; } | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { - ES3_ONLY("|", @2, "bit-wise operator"); + ES3_OR_NEWER("|", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2); } ; @@ -516,41 +538,39 @@ conditional_expression assignment_expression : conditional_expression { $$ = $1; } | unary_expression assignment_operator assignment_expression { - if (context->lValueErrorCheck(@2, "assign", $1)) - context->recover(); - $$ = context->addAssign($2.op, $1, $3, @2); + $$ = context->addAssign($2, $1, $3, @2); } ; assignment_operator - : EQUAL { $$.op = EOpAssign; } - | MUL_ASSIGN { $$.op = EOpMulAssign; } - | DIV_ASSIGN { $$.op = EOpDivAssign; } + : EQUAL { $$ = EOpAssign; } + | MUL_ASSIGN { $$ = EOpMulAssign; } + | DIV_ASSIGN { $$ = EOpDivAssign; } | MOD_ASSIGN { - ES3_ONLY("%=", @$, "integer modulus operator"); - $$.op = EOpIModAssign; + ES3_OR_NEWER("%=", @$, "integer modulus operator"); + $$ = EOpIModAssign; } - | ADD_ASSIGN { $$.op = EOpAddAssign; } - | SUB_ASSIGN { $$.op = EOpSubAssign; } + | ADD_ASSIGN { $$ = EOpAddAssign; } + | SUB_ASSIGN { $$ = EOpSubAssign; } | LEFT_ASSIGN { - ES3_ONLY("<<=", @$, "bit-wise operator"); - $$.op = EOpBitShiftLeftAssign; + ES3_OR_NEWER("<<=", @$, "bit-wise operator"); + $$ = EOpBitShiftLeftAssign; } | RIGHT_ASSIGN { - ES3_ONLY(">>=", @$, "bit-wise operator"); - $$.op = EOpBitShiftRightAssign; + ES3_OR_NEWER(">>=", @$, "bit-wise operator"); + $$ = EOpBitShiftRightAssign; } | AND_ASSIGN { - ES3_ONLY("&=", @$, "bit-wise operator"); - $$.op = EOpBitwiseAndAssign; + ES3_OR_NEWER("&=", @$, "bit-wise operator"); + $$ = EOpBitwiseAndAssign; } | XOR_ASSIGN { - ES3_ONLY("^=", @$, "bit-wise operator"); - $$.op = EOpBitwiseXorAssign; + ES3_OR_NEWER("^=", @$, "bit-wise operator"); + $$ = EOpBitwiseXorAssign; } | OR_ASSIGN { - ES3_ONLY("|=", @$, "bit-wise operator"); - $$.op = EOpBitwiseOrAssign; + ES3_OR_NEWER("|=", @$, "bit-wise operator"); + $$ = EOpBitwiseOrAssign; } ; @@ -565,16 +585,14 @@ expression constant_expression : conditional_expression { - if (context->constErrorCheck($1)) - context->recover(); + context->checkIsConst($1); $$ = $1; } ; enter_struct : IDENTIFIER LEFT_BRACE { - if (context->enterStructDeclaration(@1, *$1.string)) - context->recover(); + context->enterStructDeclaration(@1, *$1.string); $$ = $1; } ; @@ -584,43 +602,38 @@ declaration $$ = context->addFunctionPrototypeDeclaration(*($1.function), @1); } | init_declarator_list SEMICOLON { - TIntermAggregate *aggNode = $1.intermAggregate; - if (aggNode && aggNode->getOp() == EOpNull) - aggNode->setOp(EOpDeclaration); - $$ = aggNode; + $$ = $1.intermDeclaration; } | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { - if (($2 == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) { - context->error(@1, "precision is not supported in fragment shader", "highp"); - context->recover(); - } - if (!context->symbolTable.setDefaultPrecision( $3, $2 )) { - context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type)); - context->recover(); - } - $$ = 0; + context->parseDefaultPrecisionQualifier($2, $3, @1); + $$ = nullptr; } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, NULL, @$, NULL, @$); } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, NULL, @$); } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, $7, @6); } | type_qualifier SEMICOLON { - context->parseGlobalLayoutQualifier($1); - $$ = 0; + context->parseGlobalLayoutQualifier(*$1); + $$ = nullptr; + } + | type_qualifier IDENTIFIER SEMICOLON // e.g. to qualify an existing variable as invariant + { + $$ = context->parseInvariantDeclaration(*$1, @2, $2.string, $2.symbol); } ; function_prototype : function_declarator RIGHT_PAREN { $$.function = context->parseFunctionDeclarator(@2, $1); + context->exitFunctionDeclaration(); } ; @@ -638,145 +651,69 @@ function_header_with_parameters : function_header parameter_declaration { // Add the parameter $$ = $1; - if ($2.param.type->getBasicType() != EbtVoid) - $1->addParameter($2.param.turnToConst()); - else - delete $2.param.type; + if ($2.type->getBasicType() != EbtVoid) + { + $1->addParameter($2.turnToConst()); + } } | function_header_with_parameters COMMA parameter_declaration { - // + $$ = $1; // Only first parameter of one-parameter functions can be void // The check for named parameters not being void is done in parameter_declarator - // - if ($3.param.type->getBasicType() == EbtVoid) { - // + if ($3.type->getBasicType() == EbtVoid) + { // This parameter > first is void - // - context->error(@2, "cannot be an argument type except for '(void)'", "void"); - context->recover(); - delete $3.param.type; - } else { - // Add the parameter - $$ = $1; - $1->addParameter($3.param.turnToConst()); + context->error(@2, "cannot be a parameter type except for '(void)'", "void"); + } + else + { + $1->addParameter($3.turnToConst()); } } ; function_header : fully_specified_type IDENTIFIER LEFT_PAREN { - 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->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; - const TType *type = new TType($1); - function = new TFunction($2.string, type); - $$ = function; - + $$ = context->parseFunctionHeader($1, $2.string, @2); + context->symbolTable.push(); + context->enterFunctionDeclaration(); } ; parameter_declarator // Type + name : type_specifier identifier { - if ($1.type == EbtVoid) { - context->error(@2, "illegal use of type 'void'", $2.string->c_str()); - context->recover(); - } - if (context->reservedErrorCheck(@2, *$2.string)) - context->recover(); - TParameter param = {$2.string, new TType($1)}; - $$.param = param; + $$ = context->parseParameterDeclarator($1, $2.string, @2); } - | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - // Check that we can make an array out of this type - if (context->arrayTypeErrorCheck(@3, $1)) - context->recover(); - - if (context->reservedErrorCheck(@2, *$2.string)) - context->recover(); - - int size; - if (context->arraySizeErrorCheck(@3, $4, size)) - context->recover(); - $1.setArraySize(size); - - TType* type = new TType($1); - TParameter param = { $2.string, type }; - $$.param = param; + | type_specifier identifier array_specifier { + $$ = context->parseParameterArrayDeclarator($2.string, @2, *($3), @3, &$1); } ; parameter_declaration - // - // The only parameter qualifier a parameter can have are - // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. - // - - // - // Type + name - // - : parameter_type_qualifier parameter_qualifier parameter_declarator { - $$ = $3; - if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) - context->recover(); - } - | parameter_qualifier parameter_declarator { - $$ = $2; - if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) - context->recover(); - if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) - context->recover(); - } - // - // Only type - // - | parameter_type_qualifier parameter_qualifier parameter_type_specifier { - $$ = $3; - if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) - context->recover(); - } - | parameter_qualifier parameter_type_specifier { + : type_qualifier parameter_declarator { $$ = $2; - if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) - context->recover(); - if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) - context->recover(); + context->checkIsParameterQualifierValid(@2, *$1, $2.type); } - ; - -parameter_qualifier - : /* empty */ { - $$ = EvqIn; - } - | IN_QUAL { - $$ = EvqIn; + | parameter_declarator { + $$ = $1; + $$.type->setQualifier(EvqIn); } - | OUT_QUAL { - $$ = EvqOut; + | type_qualifier parameter_type_specifier { + $$ = $2; + context->checkIsParameterQualifierValid(@2, *$1, $2.type); } - | INOUT_QUAL { - $$ = EvqInOut; + | parameter_type_specifier { + $$ = $1; + $$.type->setQualifier(EvqIn); } ; parameter_type_specifier : type_specifier { TParameter param = { 0, new TType($1) }; - $$.param = param; + $$ = param; } ; @@ -786,213 +723,164 @@ init_declarator_list } | init_declarator_list COMMA identifier { $$ = $1; - $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, @3, *$3.string); - } - | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - $$ = $1; - $$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); + context->parseDeclarator($$.type, @3, *$3.string, $$.intermDeclaration); } - | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("[]", @3, "implicitly sized array"); + | init_declarator_list COMMA identifier array_specifier { $$ = $1; - $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7); + context->parseArrayDeclarator($$.type, @3, *$3.string, @4, *($4), $$.intermDeclaration); } - | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("=", @7, "first-class arrays (array initializer)"); + | init_declarator_list COMMA identifier array_specifier EQUAL initializer { + ES3_OR_NEWER("=", @5, "first-class arrays (array initializer)"); $$ = $1; - $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5, @7, $8); + context->parseArrayInitDeclarator($$.type, @3, *$3.string, @4, *($4), @5, $6, $$.intermDeclaration); } | init_declarator_list COMMA identifier EQUAL initializer { $$ = $1; - $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); + context->parseInitDeclarator($$.type, @3, *$3.string, @4, $5, $$.intermDeclaration); } ; single_declaration : fully_specified_type { $$.type = $1; - $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, ""); + $$.intermDeclaration = context->parseSingleDeclaration($$.type, @1, ""); } | fully_specified_type identifier { $$.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); + $$.intermDeclaration = context->parseSingleDeclaration($$.type, @2, *$2.string); } - | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("[]", @3, "implicitly sized array"); + | fully_specified_type identifier array_specifier { $$.type = $1; - $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6); + $$.intermDeclaration = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, *($3)); } - | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("=", @6, "first-class arrays (array initializer)"); + | fully_specified_type identifier array_specifier EQUAL initializer { + ES3_OR_NEWER("[]", @3, "first-class arrays (array initializer)"); $$.type = $1; - $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7); + $$.intermDeclaration = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, *($3), @4, $5); } | fully_specified_type identifier EQUAL initializer { $$.type = $1; - $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); - } - | INVARIANT IDENTIFIER { - // $$.type is not used in invariant declarations. - $$.intermAggregate = context->parseInvariantDeclaration(@1, @2, $2.string, $2.symbol); + $$.intermDeclaration = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); } ; fully_specified_type : type_specifier { + context->addFullySpecifiedType(&$1); $$ = $1; - - if ($1.array) { - ES3_ONLY("[]", @1, "first-class-array"); - if (context->getShaderVersion() != 300) { - $1.clearArrayness(); - } - } } - | type_qualifier type_specifier { - $$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2); + | type_qualifier type_specifier { + $$ = context->addFullySpecifiedType(*$1, $2); } ; interpolation_qualifier : SMOOTH { - $$.qualifier = EvqSmooth; + $$ = EvqSmooth; } | FLAT { - $$.qualifier = EvqFlat; - } - ; - -parameter_type_qualifier - : CONST_QUAL { - $$ = EvqConst; + $$ = EvqFlat; } ; type_qualifier - : ATTRIBUTE { - VERTEX_ONLY("attribute", @1); - ES2_ONLY("attribute", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute")) - context->recover(); - $$.setBasic(EbtVoid, EvqAttribute, @1); - } - | VARYING { - ES2_ONLY("varying", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - $$.setBasic(EbtVoid, EvqVaryingOut, @1); - else - $$.setBasic(EbtVoid, EvqVaryingIn, @1); + : single_type_qualifier { + $$ = context->createTypeQualifierBuilder(@1); + $$->appendQualifier($1); } - | INVARIANT VARYING { - ES2_ONLY("varying", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - $$.setBasic(EbtVoid, EvqVaryingOut, @1); - else - $$.setBasic(EbtVoid, EvqVaryingIn, @1); - $$.invariant = true; - } - | storage_qualifier { - if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) - { - context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier)); - context->recover(); - } - $$.setBasic(EbtVoid, $1.qualifier, @1); + | type_qualifier single_type_qualifier { + $$ = $1; + $$->appendQualifier($2); } - | interpolation_qualifier storage_qualifier { - $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier); + ; + +invariant_qualifier + : INVARIANT { + // empty } - | interpolation_qualifier { - context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier)); - context->recover(); - - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtVoid, qual, @1); + ; + +single_type_qualifier + : storage_qualifier { + context->checkLocalVariableConstStorageQualifier(*$1); + $$ = $1; } | layout_qualifier { - $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.layoutQualifier = $1; + context->checkIsAtGlobalLevel(@1, "layout"); + $$ = new TLayoutQualifierWrapper($1, @1); } - | layout_qualifier storage_qualifier { - $$.setBasic(EbtVoid, $2.qualifier, @2); - $$.layoutQualifier = $1; + | precision_qualifier { + $$ = new TPrecisionQualifierWrapper($1, @1); } - | INVARIANT storage_qualifier { - context->es3InvariantErrorCheck($2.qualifier, @1); - $$.setBasic(EbtVoid, $2.qualifier, @2); - $$.invariant = true; + | interpolation_qualifier { + $$ = new TInterpolationQualifierWrapper($1, @1); } - | INVARIANT interpolation_qualifier storage_qualifier { - context->es3InvariantErrorCheck($3.qualifier, @1); - $$ = context->joinInterpolationQualifiers(@2, $2.qualifier, @3, $3.qualifier); - $$.invariant = true; + | invariant_qualifier { + context->checkIsAtGlobalLevel(@1, "invariant"); + $$ = new TInvariantQualifierWrapper(@1); } ; + storage_qualifier - : CONST_QUAL { - $$.qualifier = EvqConst; + : + ATTRIBUTE { + VERTEX_ONLY("attribute", @1); + ES2_ONLY("attribute", @1); + $$ = context->parseGlobalStorageQualifier(EvqAttribute, @1); + } + | VARYING { + ES2_ONLY("varying", @1); + $$ = context->parseVaryingQualifier(@1); + } + | CONST_QUAL { + $$ = new TStorageQualifierWrapper(EvqConst, @1); } | IN_QUAL { - ES3_ONLY("in", @1, "storage qualifier"); - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + $$ = context->parseInQualifier(@1); } | OUT_QUAL { - ES3_ONLY("out", @1, "storage qualifier"); - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; + $$ = context->parseOutQualifier(@1); } - | CENTROID IN_QUAL { - ES3_ONLY("centroid in", @1, "storage qualifier"); - 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->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; + | INOUT_QUAL { + $$ = context->parseInOutQualifier(@1); } - | CENTROID OUT_QUAL { - ES3_ONLY("centroid out", @1, "storage qualifier"); - 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->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + | CENTROID { + ES3_OR_NEWER("centroid", @1, "storage qualifier"); + $$ = new TStorageQualifierWrapper(EvqCentroid, @1); } | UNIFORM { - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform")) - context->recover(); - $$.qualifier = EvqUniform; + $$ = context->parseGlobalStorageQualifier(EvqUniform, @1); + } + | BUFFER { + ES3_1_ONLY("buffer", @1, "storage qualifier"); + $$ = context->parseGlobalStorageQualifier(EvqBuffer, @1); + } + | READONLY { + $$ = new TMemoryQualifierWrapper(EvqReadOnly, @1); + } + | WRITEONLY { + $$ = new TMemoryQualifierWrapper(EvqWriteOnly, @1); + } + | COHERENT { + $$ = new TMemoryQualifierWrapper(EvqCoherent, @1); + } + | RESTRICT { + $$ = new TMemoryQualifierWrapper(EvqRestrict, @1); + } + | VOLATILE { + $$ = new TMemoryQualifierWrapper(EvqVolatile, @1); + } + | SHARED { + COMPUTE_ONLY("shared", @1); + $$ = context->parseGlobalStorageQualifier(EvqShared, @1); } ; type_specifier : type_specifier_no_prec { $$ = $1; - - if ($$.precision == EbpUndefined) { - $$.precision = context->symbolTable.getDefaultPrecision($1.type); - if (context->precisionErrorCheck(@1, $$.precision, $1.type)) { - context->recover(); - } - } - } - | precision_qualifier type_specifier_no_prec { - $$ = $2; - $$.precision = $1; - - if (!SupportsPrecision($2.type)) { - context->error(@1, "illegal type for precision qualifier", getBasicString($2.type)); - context->recover(); - } + $$.precision = context->symbolTable.getDefaultPrecision($1.getBasicType()); } ; @@ -1010,7 +898,7 @@ precision_qualifier layout_qualifier : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { - ES3_ONLY("layout", @1, "qualifier"); + ES3_OR_NEWER_OR_MULTIVIEW("layout", @1, "qualifier"); $$ = $3; } ; @@ -1020,7 +908,7 @@ layout_qualifier_id_list $$ = $1; } | layout_qualifier_id_list COMMA layout_qualifier_id { - $$ = context->joinLayoutQualifiers($1, $3); + $$ = context->joinLayoutQualifiers($1, $3, @3); } ; @@ -1029,279 +917,303 @@ layout_qualifier_id $$ = context->parseLayoutQualifier(*$1.string, @1); } | IDENTIFIER EQUAL INTCONSTANT { - $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3); } | IDENTIFIER EQUAL UINTCONSTANT { - $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3); + } + | SHARED { + $$ = context->parseLayoutQualifier("shared", @1); } ; type_specifier_no_prec : type_specifier_nonarray { - $$ = $1; + $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + } + | type_specifier_nonarray array_specifier { + $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + $$.setArraySizes($2); + } + ; + +array_specifier + : LEFT_BRACKET RIGHT_BRACKET { + ES3_OR_NEWER("[]", @1, "implicitly sized array"); + $$ = new TVector(); + $$->push_back(0u); } - | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET { - ES3_ONLY("[]", @2, "implicitly sized array"); + | LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = new TVector(); + unsigned int size = context->checkIsValidArraySize(@1, $2); + // Make the type an array even if size check failed. + // This ensures useless error messages regarding a variable's non-arrayness won't follow. + $$->push_back(size); + } + | array_specifier LEFT_BRACKET RIGHT_BRACKET { + ES3_1_ONLY("[]", @2, "arrays of arrays"); $$ = $1; - $$.setArraySize(0); + $$->insert($$->begin(), 0u); } - | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + | array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET { + ES3_1_ONLY("[]", @2, "arrays of arrays"); $$ = $1; - - if (context->arrayTypeErrorCheck(@2, $1)) - context->recover(); - else { - int size; - if (context->arraySizeErrorCheck(@2, $3, size)) - context->recover(); - $$.setArraySize(size); - } + unsigned int size = context->checkIsValidArraySize(@2, $3); + // Make the type an array even if size check failed. + // This ensures useless error messages regarding a variable's non-arrayness won't follow. + $$->insert($$->begin(), size); } ; type_specifier_nonarray : VOID_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtVoid, qual, @1); + $$.initialize(EbtVoid, @1); } | FLOAT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); } | INT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); } | UINT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); } | BOOL_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); } | VEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(2); } | VEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(3); } | VEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(4); } | BVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(2); } | BVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(3); } | BVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(4); } | IVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(2); } | IVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(3); } | IVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(4); } | UVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(2); } | UVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(3); } | UVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(4); } | MATRIX2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 2); } | MATRIX3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 3); } | MATRIX4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 4); } | MATRIX2x3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 3); } | MATRIX3x2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 2); } | MATRIX2x4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 4); } | MATRIX4x2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 2); } | MATRIX3x4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 4); } | MATRIX4x3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 3); } + | YUVCSCSTANDARDEXT { + if (!context->checkCanUseExtension(@1, TExtension::EXT_YUV_target)) + { + context->error(@1, "unsupported type", "yuvCscStandardEXT"); + } + $$.initialize(EbtYuvCscStandardEXT, @1); + } | SAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2D, qual, @1); + $$.initialize(EbtSampler2D, @1); } | SAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler3D, qual, @1); + $$.initialize(EbtSampler3D, @1); } | SAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerCube, qual, @1); + $$.initialize(EbtSamplerCube, @1); } | SAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DArray, qual, @1); + $$.initialize(EbtSampler2DArray, @1); + } + | SAMPLER2DMS { + $$.initialize(EbtSampler2DMS, @1); } | ISAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler2D, qual, @1); + $$.initialize(EbtISampler2D, @1); } | ISAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler3D, qual, @1); + $$.initialize(EbtISampler3D, @1); } | ISAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISamplerCube, qual, @1); + $$.initialize(EbtISamplerCube, @1); } | ISAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler2DArray, qual, @1); + $$.initialize(EbtISampler2DArray, @1); + } + | ISAMPLER2DMS { + $$.initialize(EbtISampler2DMS, @1); } | USAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler2D, qual, @1); + $$.initialize(EbtUSampler2D, @1); } | USAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler3D, qual, @1); + $$.initialize(EbtUSampler3D, @1); } | USAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSamplerCube, qual, @1); + $$.initialize(EbtUSamplerCube, @1); } | USAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler2DArray, qual, @1); + $$.initialize(EbtUSampler2DArray, @1); + } + | USAMPLER2DMS { + $$.initialize(EbtUSampler2DMS, @1); } | SAMPLER2DSHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DShadow, qual, @1); + $$.initialize(EbtSampler2DShadow, @1); } | SAMPLERCUBESHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerCubeShadow, qual, @1); + $$.initialize(EbtSamplerCubeShadow, @1); } | SAMPLER2DARRAYSHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DArrayShadow, qual, @1); + $$.initialize(EbtSampler2DArrayShadow, @1); } | SAMPLER_EXTERNAL_OES { - if (!context->supportsExtension("GL_OES_EGL_image_external")) { + constexpr std::array extensions{ { TExtension::NV_EGL_stream_consumer_external, + TExtension::OES_EGL_image_external_essl3, + TExtension::OES_EGL_image_external } }; + if (!context->checkCanUseOneOfExtensions(@1, extensions)) + { context->error(@1, "unsupported type", "samplerExternalOES"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerExternalOES, qual, @1); + $$.initialize(EbtSamplerExternalOES, @1); + } + | SAMPLEREXTERNAL2DY2YEXT { + if (!context->checkCanUseExtension(@1, TExtension::EXT_YUV_target)) + { + context->error(@1, "unsupported type", "__samplerExternal2DY2YEXT"); + } + $$.initialize(EbtSamplerExternal2DY2YEXT, @1); } | SAMPLER2DRECT { - if (!context->supportsExtension("GL_ARB_texture_rectangle")) { + if (!context->checkCanUseExtension(@1, TExtension::ARB_texture_rectangle)) + { context->error(@1, "unsupported type", "sampler2DRect"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DRect, qual, @1); + $$.initialize(EbtSampler2DRect, @1); } | struct_specifier { $$ = $1; - $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | IMAGE2D { + $$.initialize(EbtImage2D, @1); + } + | IIMAGE2D { + $$.initialize(EbtIImage2D, @1); + } + | UIMAGE2D { + $$.initialize(EbtUImage2D, @1); + } + | IMAGE3D { + $$.initialize(EbtImage3D, @1); + } + | IIMAGE3D { + $$.initialize(EbtIImage3D, @1); + } + | UIMAGE3D { + $$.initialize(EbtUImage3D, @1); + } + | IMAGE2DARRAY { + $$.initialize(EbtImage2DArray, @1); + } + | IIMAGE2DARRAY { + $$.initialize(EbtIImage2DArray, @1); + } + | UIMAGE2DARRAY { + $$.initialize(EbtUImage2DArray, @1); + } + | IMAGECUBE { + $$.initialize(EbtImageCube, @1); + } + | IIMAGECUBE { + $$.initialize(EbtIImageCube, @1); + } + | UIMAGECUBE { + $$.initialize(EbtUImageCube, @1); + } + | ATOMICUINT { + $$.initialize(EbtAtomicCounter, @1); } | TYPE_NAME { - // - // This is for user defined type names. The lexical phase looked up the - // type. - // + // This is for user defined type names. The lexical phase looked up the type. TType& structure = static_cast($1.symbol)->getType(); - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtStruct, qual, @1); - $$.userDef = &structure; + $$.initializeStruct(structure.getStruct(), false, @1); } ; struct_specifier - : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + : STRUCT identifier LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE { $$ = context->addStructure(@1, @2, $2.string, $5); } - | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + | STRUCT LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE { $$ = context->addStructure(@1, @$, NewPoolTString(""), $4); } ; struct_declaration_list : struct_declaration { - $$ = $1; + $$ = context->addStructFieldList($1, @1); } | struct_declaration_list struct_declaration { - $$ = $1; - for (size_t i = 0; i < $2->size(); ++i) { - TField* field = (*$2)[i]; - for (size_t j = 0; j < $$->size(); ++j) { - if ((*$$)[j]->name() == field->name()) { - context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str()); - context->recover(); - } - } - $$->push_back(field); - } + $$ = context->combineStructFieldLists($1, $2, @2); } ; @@ -1311,9 +1223,7 @@ struct_declaration } | type_qualifier type_specifier struct_declarator_list SEMICOLON { // ES3 Only, but errors should be handled elsewhere - $2.qualifier = $1.qualifier; - $2.layoutQualifier = $1.layoutQualifier; - $$ = context->addStructDeclaratorList($2, $3); + $$ = context->addStructDeclaratorListWithQualifiers(*$1, &$2, $3); } ; @@ -1329,23 +1239,10 @@ struct_declarator_list struct_declarator : identifier { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); - - TType* type = new TType(EbtVoid, EbpUndefined); - $$ = new TField(type, $1.string, @1); + $$ = context->parseStructDeclarator($1.string, @1); } - | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); - - TType* type = new TType(EbtVoid, EbpUndefined); - int size; - if (context->arraySizeErrorCheck(@3, $3, size)) - context->recover(); - type->setArraySize(size); - - $$ = new TField(type, $1.string, @1); + | identifier array_specifier { + $$ = context->parseStructArrayDeclarator($1.string, @1, *($2), @2); } ; @@ -1358,8 +1255,8 @@ declaration_statement ; statement - : compound_statement { $$ = $1; } - | simple_statement { $$ = $1; } + : compound_statement_with_scope { $$ = $1; } + | simple_statement { $$ = $1; } ; // Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported. @@ -1374,13 +1271,13 @@ simple_statement | jump_statement { $$ = $1; } ; -compound_statement - : LEFT_BRACE RIGHT_BRACE { $$ = 0; } +compound_statement_with_scope + : LEFT_BRACE RIGHT_BRACE { + $$ = new TIntermBlock(); + $$->setLine(@$); + } | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE { - if ($3 != 0) { - $3->setOp(EOpSequence); - $3->setLine(@$); - } + $3->setLine(@$); $$ = $3; } ; @@ -1396,38 +1293,36 @@ statement_with_scope ; compound_statement_no_new_scope - // Statement that doesn't create a new scope, for selection_statement, iteration_statement + // Statement that doesn't create a new scope for iteration_statement, function definition (scope is created for parameters) : LEFT_BRACE RIGHT_BRACE { - $$ = 0; + $$ = new TIntermBlock(); + $$->setLine(@$); } | LEFT_BRACE statement_list RIGHT_BRACE { - if ($2) { - $2->setOp(EOpSequence); - $2->setLine(@$); - } + $2->setLine(@$); $$ = $2; } ; statement_list : statement { - $$ = context->intermediate.makeAggregate($1, @$); + $$ = new TIntermBlock(); + $$->appendStatement($1); } | statement_list statement { - $$ = context->intermediate.growAggregate($1, $2, @$); + $$ = $1; + $$->appendStatement($2); } ; expression_statement - : SEMICOLON { $$ = 0; } - | expression SEMICOLON { $$ = static_cast($1); } + : SEMICOLON { $$ = context->addEmptyStatement(@$); } + | expression SEMICOLON { $$ = $1; } ; selection_statement : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { - if (context->boolErrorCheck(@1, $3)) - context->recover(); - $$ = context->intermediate.addSelection($3, $5, @1); + $$ = context->addIfElse($3, $5, @1); } ; @@ -1438,12 +1333,14 @@ selection_rest_statement } | statement_with_scope { $$.node1 = $1; - $$.node2 = 0; + $$.node2 = nullptr; } ; +// Note that we've diverged from the spec grammar here a bit for the sake of simplicity. +// We're reusing compound_statement_with_scope instead of having separate rules for switch. switch_statement - : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement { + : SWITCH LEFT_PAREN expression RIGHT_PAREN { context->incrSwitchNestingLevel(); } compound_statement_with_scope { $$ = context->addSwitch($3, $6, @1); context->decrSwitchNestingLevel(); } @@ -1459,42 +1356,28 @@ case_label ; condition - // In 1996 c++ draft, conditions can include single declarations : expression { $$ = $1; - if (context->boolErrorCheck($1->getLine(), $1)) - context->recover(); + context->checkIsScalarBool($1->getLine(), $1); } | fully_specified_type identifier EQUAL initializer { - TIntermNode *intermNode; - if (context->boolErrorCheck(@2, $1)) - context->recover(); - - if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode)) - $$ = $4; - else { - context->recover(); - $$ = 0; - } + $$ = context->addConditionInitializer($1, *$2.string, $4, @2); } ; iteration_statement : 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->addLoop(ELoopWhile, 0, $4, 0, $6, @1); context->decrLoopNestingLevel(); } | 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->addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); context->decrLoopNestingLevel(); } | 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->addLoop(ELoopFor, $4, $5.node1, reinterpret_cast($5.node2), $7, @1); context->decrLoopNestingLevel(); } ; @@ -1513,7 +1396,7 @@ conditionopt $$ = $1; } | /* May be null */ { - $$ = 0; + $$ = nullptr; } ; @@ -1542,7 +1425,6 @@ jump_statement $$ = context->addBranch(EOpReturn, $2, @1); } | DISCARD SEMICOLON { - FRAG_ONLY("discard", @1); $$ = context->addBranch(EOpKill, @1); } ; @@ -1551,12 +1433,13 @@ jump_statement translation_unit : external_declaration { - $$ = $1; + $$ = new TIntermBlock(); + $$->setLine(@$); + $$->appendStatement($1); context->setTreeRoot($$); } | translation_unit external_declaration { - $$ = context->intermediate.growAggregate($1, $2, @$); - context->setTreeRoot($$); + $$->appendStatement($2); } ; @@ -1571,10 +1454,10 @@ external_declaration function_definition : function_prototype { - context->parseFunctionPrototype(@1, $1.function, &$1.intermAggregate); + context->parseFunctionDefinitionHeader(@1, &($1.function), &($1.intermFunctionPrototype)); } compound_statement_no_new_scope { - $$ = context->addFunctionDefinition(*($1.function), $1.intermAggregate, $3, @1); + $$ = context->addFunctionDefinition($1.intermFunctionPrototype, $3, @1); } ; diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp deleted file mode 100644 index 6dca547f08..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp +++ /dev/null @@ -1,626 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/Intermediate.h" -#include "compiler/translator/SymbolTable.h" - -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 -// also directly call Traverse() on children themselves to -// have finer grained control over the process than shown here. -// See the last function for how to get started. -// 2. Print out a text based description of the tree. -// - -// -// Use this class to carry along data from node to node in -// the traversal -// -class TOutputTraverser : public TIntermTraverser -{ - public: - TOutputTraverser(TInfoSinkBase &i) - : TIntermTraverser(true, false, false), - sink(i) - { - } - TInfoSinkBase& sink; - - protected: - 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; -}; - -// -// Helper functions for printing, not part of traversing. -// -void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth) -{ - int i; - - sink.location(node->getLine()); - - for (i = 0; i < depth; ++i) - sink << " "; -} - -} // namespace anonymous - -// -// The rest of the file are the traversal functions. The last one -// is the one that starts the traversal. -// -// Return true from interior nodes to have the external traversal -// continue on to children. If you process children yourself, -// return false. -// - -void TOutputTraverser::visitSymbol(TIntermSymbol *node) -{ - OutputTreeText(sink, node, mDepth); - - sink << "'" << node->getSymbol() << "' "; - sink << "(" << node->getCompleteString() << ")\n"; -} - -bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) -{ - TInfoSinkBase& out = sink; - - OutputTreeText(out, node, mDepth); - - switch (node->getOp()) - { - case EOpAssign: - out << "move second child to first child"; - break; - case EOpInitialize: - out << "initialize first child with second child"; - break; - case EOpAddAssign: - out << "add second child into first child"; - break; - case EOpSubAssign: - out << "subtract second child into first child"; - break; - case EOpMulAssign: - out << "multiply second child into first child"; - break; - case EOpVectorTimesMatrixAssign: - out << "matrix mult second child into first child"; - break; - case EOpVectorTimesScalarAssign: - out << "vector scale second child into first child"; - break; - case EOpMatrixTimesScalarAssign: - out << "matrix scale second child into first child"; - break; - case EOpMatrixTimesMatrixAssign: - out << "matrix mult second child into first child"; - break; - case EOpDivAssign: - out << "divide second child into first child"; - break; - case EOpIModAssign: - out << "modulo second child into first child"; - break; - case EOpBitShiftLeftAssign: - out << "bit-wise shift first child left by second child"; - break; - case EOpBitShiftRightAssign: - out << "bit-wise shift first child right by second child"; - break; - case EOpBitwiseAndAssign: - out << "bit-wise and second child into first child"; - break; - case EOpBitwiseXorAssign: - out << "bit-wise xor second child into first child"; - break; - case EOpBitwiseOrAssign: - out << "bit-wise or second child into first child"; - break; - - case EOpIndexDirect: - out << "direct index"; - break; - case EOpIndexIndirect: - out << "indirect index"; - break; - case EOpIndexDirectStruct: - out << "direct index for structure"; - break; - case EOpIndexDirectInterfaceBlock: - out << "direct index for interface block"; - break; - case EOpVectorSwizzle: - out << "vector swizzle"; - break; - - case EOpAdd: - out << "add"; - break; - case EOpSub: - out << "subtract"; - break; - case EOpMul: - out << "component-wise multiply"; - break; - case EOpDiv: - out << "divide"; - break; - case EOpIMod: - out << "modulo"; - break; - case EOpBitShiftLeft: - out << "bit-wise shift left"; - break; - case EOpBitShiftRight: - out << "bit-wise shift right"; - break; - case EOpBitwiseAnd: - out << "bit-wise and"; - break; - case EOpBitwiseXor: - out << "bit-wise xor"; - break; - case EOpBitwiseOr: - out << "bit-wise or"; - break; - - case EOpEqual: - out << "Compare Equal"; - break; - case EOpNotEqual: - out << "Compare Not Equal"; - break; - case EOpLessThan: - out << "Compare Less Than"; - break; - case EOpGreaterThan: - out << "Compare Greater Than"; - break; - case EOpLessThanEqual: - out << "Compare Less Than or Equal"; - break; - case EOpGreaterThanEqual: - out << "Compare Greater Than or Equal"; - break; - - case EOpVectorTimesScalar: - out << "vector-scale"; - break; - case EOpVectorTimesMatrix: - out << "vector-times-matrix"; - break; - case EOpMatrixTimesVector: - out << "matrix-times-vector"; - break; - case EOpMatrixTimesScalar: - out << "matrix-scale"; - break; - case EOpMatrixTimesMatrix: - out << "matrix-multiply"; - break; - - case EOpLogicalOr: - out << "logical-or"; - break; - case EOpLogicalXor: - out << "logical-xor"; - break; - case EOpLogicalAnd: - out << "logical-and"; - break; - default: - out << ""; - } - - out << " (" << node->getCompleteString() << ")"; - - out << "\n"; - - // Special handling for direct indexes. Because constant - // unions are not aware they are struct indexes, treat them - // here where we have that contextual knowledge. - if (node->getOp() == EOpIndexDirectStruct || - node->getOp() == EOpIndexDirectInterfaceBlock) - { - mDepth++; - node->getLeft()->traverse(this); - mDepth--; - - TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); - ASSERT(intermConstantUnion); - - OutputTreeText(out, intermConstantUnion, mDepth + 1); - - // The following code finds the field name from the constant union - const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer(); - const TStructure *structure = node->getLeft()->getType().getStruct(); - const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); - ASSERT(structure || interfaceBlock); - - const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); - - const TField *field = fields[constantUnion->getIConst()]; - - out << constantUnion->getIConst() << " (field '" << field->name() << "')"; - - return false; - } - - return true; -} - -bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) -{ - TInfoSinkBase& out = sink; - - OutputTreeText(out, node, mDepth); - - switch (node->getOp()) - { - case EOpNegative: out << "Negate value"; break; - case EOpPositive: out << "Positive sign"; break; - case EOpVectorLogicalNot: - case EOpLogicalNot: out << "Negate conditional"; break; - case EOpBitwiseNot: out << "bit-wise not"; break; - - case EOpPostIncrement: out << "Post-Increment"; break; - case EOpPostDecrement: out << "Post-Decrement"; break; - case EOpPreIncrement: out << "Pre-Increment"; break; - case EOpPreDecrement: out << "Pre-Decrement"; break; - - case EOpRadians: out << "radians"; break; - case EOpDegrees: out << "degrees"; break; - case EOpSin: out << "sine"; break; - case EOpCos: out << "cosine"; break; - case EOpTan: out << "tangent"; break; - case EOpAsin: out << "arc sine"; break; - case EOpAcos: out << "arc cosine"; break; - case EOpAtan: out << "arc tangent"; break; - - case EOpSinh: out << "hyperbolic sine"; break; - case EOpCosh: out << "hyperbolic cosine"; break; - case EOpTanh: out << "hyperbolic tangent"; break; - case EOpAsinh: out << "arc hyperbolic sine"; break; - case EOpAcosh: out << "arc hyperbolic cosine"; break; - case EOpAtanh: out << "arc hyperbolic tangent"; break; - - case EOpExp: out << "exp"; break; - case EOpLog: out << "log"; break; - case EOpExp2: out << "exp2"; break; - case EOpLog2: out << "log2"; break; - case EOpSqrt: out << "sqrt"; break; - case EOpInverseSqrt: out << "inverse sqrt"; break; - - case EOpAbs: out << "Absolute value"; break; - case EOpSign: out << "Sign"; break; - case EOpFloor: out << "Floor"; break; - case EOpTrunc: out << "Truncate"; break; - case EOpRound: out << "Round"; break; - case EOpRoundEven: out << "Round half even"; break; - case EOpCeil: out << "Ceiling"; break; - case EOpFract: out << "Fraction"; break; - case EOpIsNan: out << "Is not a number"; break; - case EOpIsInf: out << "Is infinity"; break; - - case EOpFloatBitsToInt: out << "float bits to int"; break; - case EOpFloatBitsToUint: out << "float bits to uint"; break; - case EOpIntBitsToFloat: out << "int bits to float"; break; - case EOpUintBitsToFloat: out << "uint bits to float"; break; - - case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break; - case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break; - case EOpPackHalf2x16: out << "pack half 2x16"; break; - - case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break; - case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break; - case EOpUnpackHalf2x16: out << "unpack half 2x16"; break; - - case EOpLength: out << "length"; break; - case EOpNormalize: out << "normalize"; break; - // case EOpDPdx: out << "dPdx"; break; - // case EOpDPdy: out << "dPdy"; break; - // case EOpFwidth: out << "fwidth"; break; - - case EOpDeterminant: out << "determinant"; break; - case EOpTranspose: out << "transpose"; break; - case EOpInverse: out << "inverse"; break; - - case EOpAny: out << "any"; break; - case EOpAll: out << "all"; break; - - default: - out.prefix(EPrefixError); - out << "Bad unary op"; - } - - out << " (" << node->getCompleteString() << ")"; - - out << "\n"; - - return true; -} - -bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) -{ - TInfoSinkBase &out = sink; - - if (node->getOp() == EOpNull) - { - out.prefix(EPrefixError); - out << "node is still EOpNull!"; - return true; - } - - OutputTreeText(out, node, mDepth); - - switch (node->getOp()) - { - case EOpSequence: out << "Sequence\n"; return true; - case EOpComma: out << "Comma\n"; return true; - case EOpFunction: OutputFunction(out, "Function Definition", node); break; - case EOpFunctionCall: OutputFunction(out, "Function Call", node); break; - case EOpParameters: out << "Function Parameters: "; break; - case EOpPrototype: OutputFunction(out, "Function Prototype", node); break; - - case EOpConstructFloat: out << "Construct float"; break; - case EOpConstructVec2: out << "Construct vec2"; break; - case EOpConstructVec3: out << "Construct vec3"; break; - case EOpConstructVec4: out << "Construct vec4"; break; - case EOpConstructBool: out << "Construct bool"; break; - case EOpConstructBVec2: out << "Construct bvec2"; break; - case EOpConstructBVec3: out << "Construct bvec3"; break; - case EOpConstructBVec4: out << "Construct bvec4"; break; - case EOpConstructInt: out << "Construct int"; break; - case EOpConstructIVec2: out << "Construct ivec2"; break; - case EOpConstructIVec3: out << "Construct ivec3"; break; - case EOpConstructIVec4: out << "Construct ivec4"; break; - case EOpConstructUInt: out << "Construct uint"; break; - case EOpConstructUVec2: out << "Construct uvec2"; break; - case EOpConstructUVec3: out << "Construct uvec3"; break; - case EOpConstructUVec4: out << "Construct uvec4"; break; - case EOpConstructMat2: out << "Construct mat2"; break; - case 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; - - case EOpLessThan: out << "Compare Less Than"; break; - case EOpGreaterThan: out << "Compare Greater Than"; break; - case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; - case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; - case EOpVectorEqual: out << "Equal"; break; - case EOpVectorNotEqual: out << "NotEqual"; break; - - case EOpMod: out << "mod"; break; - case EOpModf: out << "modf"; break; - case EOpPow: out << "pow"; break; - - case EOpAtan: out << "arc tangent"; break; - - case EOpMin: out << "min"; break; - case EOpMax: out << "max"; break; - case EOpClamp: out << "clamp"; break; - case EOpMix: out << "mix"; break; - case EOpStep: out << "step"; break; - case EOpSmoothStep: out << "smoothstep"; break; - - case EOpDistance: out << "distance"; break; - case EOpDot: out << "dot-product"; break; - case EOpCross: out << "cross-product"; break; - case EOpFaceForward: out << "face-forward"; break; - case EOpReflect: out << "reflect"; break; - case EOpRefract: out << "refract"; break; - case EOpMul: out << "component-wise multiply"; break; - - case EOpOuterProduct: out << "outer product"; break; - - case EOpDeclaration: out << "Declaration: "; break; - case EOpInvariantDeclaration: out << "Invariant Declaration: "; break; - - default: - out.prefix(EPrefixError); - out << "Bad aggregation op"; - } - - if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) - out << " (" << node->getCompleteString() << ")"; - - out << "\n"; - - return true; -} - -bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node) -{ - TInfoSinkBase &out = sink; - - OutputTreeText(out, node, mDepth); - - out << "Test condition and select"; - out << " (" << node->getCompleteString() << ")\n"; - - ++mDepth; - - OutputTreeText(sink, node, mDepth); - out << "Condition\n"; - node->getCondition()->traverse(this); - - OutputTreeText(sink, node, mDepth); - if (node->getTrueBlock()) - { - out << "true case\n"; - node->getTrueBlock()->traverse(this); - } - else - { - out << "true case is null\n"; - } - - if (node->getFalseBlock()) - { - OutputTreeText(sink, node, mDepth); - out << "false case\n"; - node->getFalseBlock()->traverse(this); - } - - --mDepth; - - return false; -} - -void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node) -{ - TInfoSinkBase &out = sink; - - size_t size = node->getType().getObjectSize(); - - for (size_t i = 0; i < size; i++) - { - OutputTreeText(out, node, mDepth); - switch (node->getUnionArrayPointer()[i].getType()) - { - case EbtBool: - if (node->getUnionArrayPointer()[i].getBConst()) - out << "true"; - else - out << "false"; - - out << " (" << "const bool" << ")"; - out << "\n"; - break; - case EbtFloat: - out << node->getUnionArrayPointer()[i].getFConst(); - out << " (const float)\n"; - break; - case EbtInt: - out << node->getUnionArrayPointer()[i].getIConst(); - out << " (const int)\n"; - break; - case EbtUInt: - out << node->getUnionArrayPointer()[i].getUConst(); - out << " (const uint)\n"; - break; - default: - out.message(EPrefixInternalError, node->getLine(), "Unknown constant"); - break; - } - } -} - -bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node) -{ - TInfoSinkBase &out = sink; - - OutputTreeText(out, node, mDepth); - - out << "Loop with condition "; - if (node->getType() == ELoopDoWhile) - out << "not "; - out << "tested first\n"; - - ++mDepth; - - OutputTreeText(sink, node, mDepth); - if (node->getCondition()) - { - out << "Loop Condition\n"; - node->getCondition()->traverse(this); - } - else - { - out << "No loop condition\n"; - } - - OutputTreeText(sink, node, mDepth); - if (node->getBody()) - { - out << "Loop Body\n"; - node->getBody()->traverse(this); - } - else - { - out << "No loop body\n"; - } - - if (node->getExpression()) - { - OutputTreeText(sink, node, mDepth); - out << "Loop Terminal Expression\n"; - node->getExpression()->traverse(this); - } - - --mDepth; - - return false; -} - -bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) -{ - TInfoSinkBase &out = sink; - - OutputTreeText(out, node, mDepth); - - switch (node->getFlowOp()) - { - case EOpKill: out << "Branch: Kill"; break; - case EOpBreak: out << "Branch: Break"; break; - case EOpContinue: out << "Branch: Continue"; break; - case EOpReturn: out << "Branch: Return"; break; - default: out << "Branch: Unknown Branch"; break; - } - - if (node->getExpression()) - { - out << " with expression\n"; - ++mDepth; - node->getExpression()->traverse(this); - --mDepth; - } - else - { - out << "\n"; - } - - return false; -} - -// -// This function is the one to call externally to start the traversal. -// Individual functions can be initialized to 0 to skip processing of that -// type of node. Its children will still be processed. -// -void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink) -{ - TOutputTraverser it(infoSink); - - ASSERT(root); - - root->traverse(&it); -} diff --git a/src/3rdparty/angle/src/compiler/translator/length_limits.h b/src/3rdparty/angle/src/compiler/translator/length_limits.h index 88634381fa..fcda639d71 100644 --- a/src/3rdparty/angle/src/compiler/translator/length_limits.h +++ b/src/3rdparty/angle/src/compiler/translator/length_limits.h @@ -16,6 +16,11 @@ // These constants are factored out from the rest of the headers to // make it easier to reference them from the compiler sources. +namespace sh +{ + size_t GetGlobalMaxTokenSize(ShShaderSpec spec); -#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_ +} // namespace sh + +#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/parseConst.cpp b/src/3rdparty/angle/src/compiler/translator/parseConst.cpp deleted file mode 100644 index 1897ed151c..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/parseConst.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// -// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/ParseContext.h" - -// -// Use this class to carry along data from node to node in -// the traversal -// -class TConstTraverser : public TIntermTraverser -{ - public: - TConstTraverser(ConstantUnion *cUnion, bool singleConstParam, - TOperator constructType, TInfoSink &sink, TType &t) - : error(false), - mIndex(0), - mUnionArray(cUnion), - mType(t), - mConstructorType(constructType), - mSingleConstantParam(singleConstParam), - mInfoSink(sink), - mSize(0), - mIsDiagonalMatrixInit(false), - mMatrixCols(0), - mMatrixRows(0) - { - } - - bool error; - - protected: - void visitSymbol(TIntermSymbol *); - void visitConstantUnion(TIntermConstantUnion *); - bool visitBinary(Visit visit, TIntermBinary *); - bool visitUnary(Visit visit, TIntermUnary *); - bool visitSelection(Visit visit, TIntermSelection *); - bool visitAggregate(Visit visit, TIntermAggregate *); - bool visitLoop(Visit visit, TIntermLoop *); - bool visitBranch(Visit visit, TIntermBranch *); - - size_t mIndex; - ConstantUnion *mUnionArray; - TType mType; - TOperator mConstructorType; - bool mSingleConstantParam; - TInfoSink &mInfoSink; - size_t mSize; // size of the constructor ( 4 for vec4) - bool mIsDiagonalMatrixInit; - int mMatrixCols; // columns of the matrix - int mMatrixRows; // rows of the matrix -}; - -// -// The rest of the file are the traversal functions. The last one -// is the one that starts the traversal. -// -// Return true from interior nodes to have the external traversal -// continue on to children. If you process children yourself, -// return false. -// -void TConstTraverser::visitSymbol(TIntermSymbol *node) -{ - mInfoSink.info.message(EPrefixInternalError, node->getLine(), - "Symbol Node found in constant constructor"); - return; -} - -bool TConstTraverser::visitBinary(Visit visit, TIntermBinary *node) -{ - TQualifier qualifier = node->getType().getQualifier(); - - if (qualifier != EvqConst) - { - TString buf; - buf.append("'constructor' : assigning non-constant to "); - buf.append(mType.getCompleteString()); - mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); - error = true; - return false; - } - - mInfoSink.info.message(EPrefixInternalError, node->getLine(), - "Binary Node found in constant constructor"); - return false; -} - -bool TConstTraverser::visitUnary(Visit visit, TIntermUnary *node) -{ - TString buf; - buf.append("'constructor' : assigning non-constant to "); - buf.append(mType.getCompleteString()); - mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); - error = true; - return false; -} - -bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate *node) -{ - if (!node->isConstructor() && node->getOp() != EOpComma) - { - TString buf; - buf.append("'constructor' : assigning non-constant to "); - buf.append(mType.getCompleteString()); - mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); - error = true; - return false; - } - - if (node->getSequence()->size() == 0) - { - error = true; - return false; - } - - bool flag = node->getSequence()->size() == 1 && - (*node->getSequence())[0]->getAsTyped()->getAsConstantUnion(); - if (flag) - { - mSingleConstantParam = true; - mConstructorType = node->getOp(); - mSize = node->getType().getObjectSize(); - - if (node->getType().isMatrix()) - { - mIsDiagonalMatrixInit = true; - mMatrixCols = node->getType().getCols(); - mMatrixRows = node->getType().getRows(); - } - } - - for (TIntermSequence::iterator p = node->getSequence()->begin(); - p != node->getSequence()->end(); p++) - { - if (node->getOp() == EOpComma) - mIndex = 0; - (*p)->traverse(this); - } - if (flag) - { - mSingleConstantParam = false; - mConstructorType = EOpNull; - mSize = 0; - mIsDiagonalMatrixInit = false; - mMatrixCols = 0; - mMatrixRows = 0; - } - return false; -} - -bool TConstTraverser::visitSelection(Visit visit, TIntermSelection *node) -{ - mInfoSink.info.message(EPrefixInternalError, node->getLine(), - "Selection Node found in constant constructor"); - error = true; - return false; -} - -void TConstTraverser::visitConstantUnion(TIntermConstantUnion *node) -{ - if (!node->getUnionArrayPointer()) - { - // The constant was not initialized, this should already have been logged - ASSERT(mInfoSink.info.size() != 0); - return; - } - - ConstantUnion *leftUnionArray = mUnionArray; - size_t instanceSize = mType.getObjectSize(); - TBasicType basicType = mType.getBasicType(); - - if (mIndex >= instanceSize) - return; - - if (!mSingleConstantParam) - { - size_t objectSize = node->getType().getObjectSize(); - ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); - for (size_t i=0; i < objectSize; i++) - { - if (mIndex >= instanceSize) - return; - leftUnionArray[mIndex].cast(basicType, rightUnionArray[i]); - mIndex++; - } - } - else - { - size_t totalSize = mIndex + mSize; - ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); - if (!mIsDiagonalMatrixInit) - { - int count = 0; - for (size_t i = mIndex; i < totalSize; i++) - { - if (i >= instanceSize) - return; - leftUnionArray[i].cast(basicType, rightUnionArray[count]); - mIndex++; - if (node->getType().getObjectSize() > 1) - count++; - } - } - else - { - // for matrix diagonal constructors from a single scalar - for (int i = 0, col = 0; col < mMatrixCols; col++) - { - for (int row = 0; row < mMatrixRows; row++, i++) - { - if (col == row) - { - leftUnionArray[i].cast(basicType, rightUnionArray[0]); - } - else - { - leftUnionArray[i].setFConst(0.0f); - } - mIndex++; - } - } - } - } -} - -bool TConstTraverser::visitLoop(Visit visit, TIntermLoop *node) -{ - mInfoSink.info.message(EPrefixInternalError, node->getLine(), - "Loop Node found in constant constructor"); - error = true; - return false; -} - -bool TConstTraverser::visitBranch(Visit visit, TIntermBranch *node) -{ - mInfoSink.info.message(EPrefixInternalError, node->getLine(), - "Branch Node found in constant constructor"); - error = true; - return false; -} - -// -// This function is the one to call externally to start the traversal. -// Individual functions can be initialized to 0 to skip processing of that -// type of node. It's children will still be processed. -// -bool TIntermediate::parseConstTree( - const TSourceLoc &line, TIntermNode *root, ConstantUnion *unionArray, - TOperator constructorType, TType t, bool singleConstantParam) -{ - if (root == 0) - return false; - - TConstTraverser it(unionArray, singleConstantParam, constructorType, - mInfoSink, t); - - root->traverse(&it); - if (it.error) - return true; - else - return false; -} diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp deleted file mode 100644 index 790974a2bf..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp +++ /dev/null @@ -1,130 +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. -// - -#include "compiler/translator/InfoSink.h" -#include "compiler/translator/ParseContext.h" -#include "compiler/translator/depgraph/DependencyGraphOutput.h" -#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" - -RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) - : mSink(sink) - , mNumErrors(0) -{ - // Sampling ops found only in fragment shaders. - mSamplingOps.insert("texture2D(s21;vf2;f1;"); - mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); - mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); - mSamplingOps.insert("textureCube(sC1;vf3;f1;"); - // Sampling ops found in both vertex and fragment shaders. - mSamplingOps.insert("texture2D(s21;vf2;"); - mSamplingOps.insert("texture2DProj(s21;vf3;"); - mSamplingOps.insert("texture2DProj(s21;vf4;"); - mSamplingOps.insert("textureCube(sC1;vf3;"); - // Sampling ops provided by OES_EGL_image_external. - mSamplingOps.insert("texture2D(1;vf2;"); - mSamplingOps.insert("texture2DProj(1;vf3;"); - mSamplingOps.insert("texture2DProj(1;vf4;"); - // Sampling ops provided by ARB_texture_rectangle. - mSamplingOps.insert("texture2DRect(1;vf2;"); - mSamplingOps.insert("texture2DRectProj(1;vf3;"); - mSamplingOps.insert("texture2DRectProj(1;vf4;"); - // Sampling ops provided by EXT_shader_texture_lod. - mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;"); - mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;"); - mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;"); - mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;"); - mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;"); - mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;"); - mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;"); - mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;"); -} - -// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. -// can vary based on the value of the input arguments. If so, we should restrict those as well. -void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) -{ - mNumErrors = 0; - - // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, - // so we generate errors for them. - validateUserDefinedFunctionCallUsage(graph); - - // 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 (auto samplerSymbol : graph.samplerSymbols()) - { - clearVisited(); - samplerSymbol->traverse(this); - } -} - -void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) -{ - for (const auto* functionCall : graph.userDefinedFunctionCalls()) - { - beginError(functionCall->getIntermFunctionCall()); - mSink << "A call to a user defined function is not permitted.\n"; - } -} - -void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) -{ - ++mNumErrors; - mSink.prefix(EPrefixError); - mSink.location(node->getLine()); -} - -bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const -{ - return !intermFunctionCall->isUserDefined() && - mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); -} - -void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) -{ - // Texture cache access time might leak sensitive information. - // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a - // sampling operation. - if (isSamplingOp(parameter->getIntermFunctionCall())) { - switch (parameter->getArgumentNumber()) { - case 1: - // Second argument (coord) - beginError(parameter->getIntermFunctionCall()); - mSink << "An expression dependent on a sampler is not permitted to be the" - << " coordinate argument of a sampling operation.\n"; - break; - case 2: - // Third argument (bias) - beginError(parameter->getIntermFunctionCall()); - mSink << "An expression dependent on a sampler is not permitted to be the" - << " bias argument of a sampling operation.\n"; - break; - default: - // First argument (sampler) - break; - } - } -} - -void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) -{ - beginError(selection->getIntermSelection()); - mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; -} - -void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) -{ - beginError(loop->getIntermLoop()); - mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; -} - -void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) -{ - beginError(logicalOp->getIntermLogicalOp()); - mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " - << logicalOp->getOpString() - << " operator.\n"; -} diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h deleted file mode 100644 index b8c7e82956..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h +++ /dev/null @@ -1,39 +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. -// - -#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ -#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ - -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/depgraph/DependencyGraph.h" - -class TInfoSinkBase; - -class RestrictFragmentShaderTiming : TDependencyGraphTraverser -{ - public: - RestrictFragmentShaderTiming(TInfoSinkBase &sink); - void enforceRestrictions(const TDependencyGraph &graph); - int numErrors() const { return mNumErrors; } - - void visitArgument(TGraphArgument *parameter) override; - void visitSelection(TGraphSelection *selection) override; - void visitLoop(TGraphLoop *loop) override; - void visitLogicalOp(TGraphLogicalOp *logicalOp) override; - - private: - void beginError(const TIntermNode *node); - void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph); - bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const; - - TInfoSinkBase &mSink; - int mNumErrors; - - typedef std::set StringSet; - StringSet mSamplingOps; -}; - -#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp deleted file mode 100644 index 7c1208a298..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp +++ /dev/null @@ -1,17 +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. -// - -#include "compiler/translator/timing/RestrictVertexShaderTiming.h" - -void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node) -{ - if (IsSampler(node->getBasicType())) { - ++mNumErrors; - mSink.message(EPrefixError, - node->getLine(), - "Samplers are not permitted in vertex shaders.\n"); - } -} diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h deleted file mode 100644 index 23a8217722..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h +++ /dev/null @@ -1,32 +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. -// - -#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ -#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ - -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/InfoSink.h" - -class TInfoSinkBase; - -class RestrictVertexShaderTiming : public TIntermTraverser { -public: - RestrictVertexShaderTiming(TInfoSinkBase& sink) - : TIntermTraverser(true, false, false) - , mSink(sink) - , mNumErrors(0) {} - - void enforceRestrictions(TIntermNode* root) { root->traverse(this); } - int numErrors() { return mNumErrors; } - - void visitSymbol(TIntermSymbol *) override; - -private: - TInfoSinkBase& mSink; - int mNumErrors; -}; - -#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp index 0131137206..9738370c47 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.cpp +++ b/src/3rdparty/angle/src/compiler/translator/util.cpp @@ -8,17 +8,9 @@ #include +#include "common/utilities.h" #include "compiler/preprocessor/numeric_lex.h" #include "compiler/translator/SymbolTable.h" -#include "common/utilities.h" - -bool strtof_clamp(const std::string &str, float *value) -{ - bool success = pp::numeric_lex_float(str, value); - if (!success) - *value = std::numeric_limits::max(); - return success; -} bool atoi_clamp(const char *str, unsigned int *value) { @@ -31,135 +23,392 @@ bool atoi_clamp(const char *str, unsigned int *value) namespace sh { -GLenum GLVariableType(const TType &type) +namespace { - if (type.getBasicType() == EbtFloat) + +bool IsInterpolationIn(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + return true; + default: + return false; + } +} + +} // anonymous namespace + +float NumericLexFloat32OutOfRangeToInfinity(const std::string &str) +{ + // Parses a decimal string using scientific notation into a floating point number. + // Out-of-range values are converted to infinity. Values that are too small to be + // represented are converted to zero. + + // The mantissa in decimal scientific notation. The magnitude of the mantissa integer does not + // matter. + unsigned int decimalMantissa = 0; + size_t i = 0; + bool decimalPointSeen = false; + bool nonZeroSeenInMantissa = false; + + // The exponent offset reflects the position of the decimal point. + int exponentOffset = -1; + while (i < str.length()) { - if (type.isScalar()) + const char c = str[i]; + if (c == 'e' || c == 'E') { - return GL_FLOAT; + break; + } + if (c == '.') + { + decimalPointSeen = true; + ++i; + continue; + } + + unsigned int digit = static_cast(c - '0'); + ASSERT(digit < 10u); + if (digit != 0u) + { + nonZeroSeenInMantissa = true; } - else if (type.isVector()) + if (nonZeroSeenInMantissa) + { + // Add bits to the mantissa until space runs out in 32-bit int. This should be + // enough precision to make the resulting binary mantissa accurate to 1 ULP. + if (decimalMantissa <= (std::numeric_limits::max() - 9u) / 10u) + { + decimalMantissa = decimalMantissa * 10u + digit; + } + if (!decimalPointSeen) + { + ++exponentOffset; + } + } + else if (decimalPointSeen) + { + --exponentOffset; + } + ++i; + } + if (decimalMantissa == 0) + { + return 0.0f; + } + int exponent = 0; + if (i < str.length()) + { + ASSERT(str[i] == 'e' || str[i] == 'E'); + ++i; + bool exponentOutOfRange = false; + bool negativeExponent = false; + if (str[i] == '-') + { + negativeExponent = true; + ++i; + } + else if (str[i] == '+') + { + ++i; + } + while (i < str.length()) + { + const char c = str[i]; + unsigned int digit = static_cast(c - '0'); + ASSERT(digit < 10u); + if (exponent <= (std::numeric_limits::max() - 9) / 10) + { + exponent = exponent * 10 + digit; + } + else + { + exponentOutOfRange = true; + } + ++i; + } + if (negativeExponent) + { + exponent = -exponent; + } + if (exponentOutOfRange) + { + if (negativeExponent) + { + return 0.0f; + } + else + { + return std::numeric_limits::infinity(); + } + } + } + // Do the calculation in 64-bit to avoid overflow. + long long exponentLong = + static_cast(exponent) + static_cast(exponentOffset); + if (exponentLong > std::numeric_limits::max_exponent10) + { + return std::numeric_limits::infinity(); + } + else if (exponentLong < std::numeric_limits::min_exponent10) + { + return 0.0f; + } + // The exponent is in range, so we need to actually evaluate the float. + exponent = static_cast(exponentLong); + double value = decimalMantissa; + + // Calculate the exponent offset to normalize the mantissa. + int normalizationExponentOffset = 0; + while (decimalMantissa >= 10u) + { + --normalizationExponentOffset; + decimalMantissa /= 10u; + } + // Apply the exponent. + value *= std::pow(10.0, static_cast(exponent + normalizationExponentOffset)); + if (value > static_cast(std::numeric_limits::max())) + { + return std::numeric_limits::infinity(); + } + if (value < static_cast(std::numeric_limits::min())) + { + return 0.0f; + } + return static_cast(value); +} + +bool strtof_clamp(const std::string &str, float *value) +{ + // Try the standard float parsing path first. + bool success = pp::numeric_lex_float(str, value); + + // If the standard path doesn't succeed, take the path that can handle the following corner + // cases: + // 1. The decimal mantissa is very small but the exponent is very large, putting the resulting + // number inside the float range. + // 2. The decimal mantissa is very large but the exponent is very small, putting the resulting + // number inside the float range. + // 3. The value is out-of-range and should be evaluated as infinity. + // 4. The value is too small and should be evaluated as zero. + // See ESSL 3.00.6 section 4.1.4 for the relevant specification. + if (!success) + *value = NumericLexFloat32OutOfRangeToInfinity(str); + return !gl::isInf(*value); +} + +GLenum GLVariableType(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + if (type.isVector()) { switch (type.getNominalSize()) { - case 2: return GL_FLOAT_VEC2; - case 3: return GL_FLOAT_VEC3; - case 4: return GL_FLOAT_VEC4; - default: UNREACHABLE(); + case 2: + return GL_FLOAT_VEC2; + case 3: + return GL_FLOAT_VEC3; + case 4: + return GL_FLOAT_VEC4; + default: + UNREACHABLE(); } } else if (type.isMatrix()) { switch (type.getCols()) { - case 2: - switch (type.getRows()) - { - case 2: return GL_FLOAT_MAT2; - case 3: return GL_FLOAT_MAT2x3; - case 4: return GL_FLOAT_MAT2x4; - default: UNREACHABLE(); - } - - case 3: - switch (type.getRows()) - { - case 2: return GL_FLOAT_MAT3x2; - case 3: return GL_FLOAT_MAT3; - case 4: return GL_FLOAT_MAT3x4; - default: UNREACHABLE(); - } - - case 4: - switch (type.getRows()) - { - case 2: return GL_FLOAT_MAT4x2; - case 3: return GL_FLOAT_MAT4x3; - case 4: return GL_FLOAT_MAT4; - default: UNREACHABLE(); - } - - default: UNREACHABLE(); + case 2: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT2; + case 3: + return GL_FLOAT_MAT2x3; + case 4: + return GL_FLOAT_MAT2x4; + default: + UNREACHABLE(); + } + + case 3: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT3x2; + case 3: + return GL_FLOAT_MAT3; + case 4: + return GL_FLOAT_MAT3x4; + default: + UNREACHABLE(); + } + + case 4: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT4x2; + case 3: + return GL_FLOAT_MAT4x3; + case 4: + return GL_FLOAT_MAT4; + default: + UNREACHABLE(); + } + + default: + UNREACHABLE(); } } - else UNREACHABLE(); + else + { + return GL_FLOAT; + } } else if (type.getBasicType() == EbtInt) { - if (type.isScalar()) - { - return GL_INT; - } - else if (type.isVector()) + if (type.isVector()) { switch (type.getNominalSize()) { - case 2: return GL_INT_VEC2; - case 3: return GL_INT_VEC3; - case 4: return GL_INT_VEC4; - default: UNREACHABLE(); + case 2: + return GL_INT_VEC2; + case 3: + return GL_INT_VEC3; + case 4: + return GL_INT_VEC4; + default: + UNREACHABLE(); } } - else UNREACHABLE(); + else + { + ASSERT(!type.isMatrix()); + return GL_INT; + } } else if (type.getBasicType() == EbtUInt) { - if (type.isScalar()) - { - return GL_UNSIGNED_INT; - } - else if (type.isVector()) + if (type.isVector()) { switch (type.getNominalSize()) { - case 2: return GL_UNSIGNED_INT_VEC2; - case 3: return GL_UNSIGNED_INT_VEC3; - case 4: return GL_UNSIGNED_INT_VEC4; - default: UNREACHABLE(); + case 2: + return GL_UNSIGNED_INT_VEC2; + case 3: + return GL_UNSIGNED_INT_VEC3; + case 4: + return GL_UNSIGNED_INT_VEC4; + default: + UNREACHABLE(); } } - else UNREACHABLE(); + else + { + ASSERT(!type.isMatrix()); + return GL_UNSIGNED_INT; + } } else if (type.getBasicType() == EbtBool) { - if (type.isScalar()) - { - return GL_BOOL; - } - else if (type.isVector()) + if (type.isVector()) { switch (type.getNominalSize()) { - case 2: return GL_BOOL_VEC2; - case 3: return GL_BOOL_VEC3; - case 4: return GL_BOOL_VEC4; - default: UNREACHABLE(); + case 2: + return GL_BOOL_VEC2; + case 3: + return GL_BOOL_VEC3; + case 4: + return GL_BOOL_VEC4; + default: + UNREACHABLE(); } } - else UNREACHABLE(); + else + { + ASSERT(!type.isMatrix()); + return GL_BOOL; + } } switch (type.getBasicType()) { - case EbtSampler2D: return GL_SAMPLER_2D; - case EbtSampler3D: return GL_SAMPLER_3D; - case EbtSamplerCube: return GL_SAMPLER_CUBE; - case EbtSamplerExternalOES: return GL_SAMPLER_EXTERNAL_OES; - case EbtSampler2DRect: return GL_SAMPLER_2D_RECT_ARB; - case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY; - case EbtISampler2D: return GL_INT_SAMPLER_2D; - case EbtISampler3D: return GL_INT_SAMPLER_3D; - case EbtISamplerCube: return GL_INT_SAMPLER_CUBE; - case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY; - case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D; - case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D; - case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE; - case EbtUSampler2DArray: return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; - case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW; - case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW; - case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW; - default: UNREACHABLE(); + case EbtSampler2D: + return GL_SAMPLER_2D; + case EbtSampler3D: + return GL_SAMPLER_3D; + case EbtSamplerCube: + return GL_SAMPLER_CUBE; + case EbtSamplerExternalOES: + return GL_SAMPLER_EXTERNAL_OES; + case EbtSamplerExternal2DY2YEXT: + return GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT; + case EbtSampler2DRect: + return GL_SAMPLER_2D_RECT_ANGLE; + case EbtSampler2DArray: + return GL_SAMPLER_2D_ARRAY; + case EbtSampler2DMS: + return GL_SAMPLER_2D_MULTISAMPLE; + case EbtISampler2D: + return GL_INT_SAMPLER_2D; + case EbtISampler3D: + return GL_INT_SAMPLER_3D; + case EbtISamplerCube: + return GL_INT_SAMPLER_CUBE; + case EbtISampler2DArray: + return GL_INT_SAMPLER_2D_ARRAY; + case EbtISampler2DMS: + return GL_INT_SAMPLER_2D_MULTISAMPLE; + case EbtUSampler2D: + return GL_UNSIGNED_INT_SAMPLER_2D; + case EbtUSampler3D: + return GL_UNSIGNED_INT_SAMPLER_3D; + case EbtUSamplerCube: + return GL_UNSIGNED_INT_SAMPLER_CUBE; + case EbtUSampler2DArray: + return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; + case EbtUSampler2DMS: + return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; + case EbtSampler2DShadow: + return GL_SAMPLER_2D_SHADOW; + case EbtSamplerCubeShadow: + return GL_SAMPLER_CUBE_SHADOW; + case EbtSampler2DArrayShadow: + return GL_SAMPLER_2D_ARRAY_SHADOW; + case EbtImage2D: + return GL_IMAGE_2D; + case EbtIImage2D: + return GL_INT_IMAGE_2D; + case EbtUImage2D: + return GL_UNSIGNED_INT_IMAGE_2D; + case EbtImage2DArray: + return GL_IMAGE_2D_ARRAY; + case EbtIImage2DArray: + return GL_INT_IMAGE_2D_ARRAY; + case EbtUImage2DArray: + return GL_UNSIGNED_INT_IMAGE_2D_ARRAY; + case EbtImage3D: + return GL_IMAGE_3D; + case EbtIImage3D: + return GL_INT_IMAGE_3D; + case EbtUImage3D: + return GL_UNSIGNED_INT_IMAGE_3D; + case EbtImageCube: + return GL_IMAGE_CUBE; + case EbtIImageCube: + return GL_INT_IMAGE_CUBE; + case EbtUImageCube: + return GL_UNSIGNED_INT_IMAGE_CUBE; + case EbtAtomicCounter: + return GL_UNSIGNED_INT_ATOMIC_COUNTER; + default: + UNREACHABLE(); } return GL_NONE; @@ -171,32 +420,32 @@ GLenum GLVariablePrecision(const TType &type) { switch (type.getPrecision()) { - case EbpHigh: - return GL_HIGH_FLOAT; - case EbpMedium: - return GL_MEDIUM_FLOAT; - case EbpLow: - return GL_LOW_FLOAT; - case EbpUndefined: - // Should be defined as the default precision by the parser - default: - UNREACHABLE(); + case EbpHigh: + return GL_HIGH_FLOAT; + case EbpMedium: + return GL_MEDIUM_FLOAT; + case EbpLow: + return GL_LOW_FLOAT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: + UNREACHABLE(); } } else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt) { switch (type.getPrecision()) { - case EbpHigh: - return GL_HIGH_INT; - case EbpMedium: - return GL_MEDIUM_INT; - case EbpLow: - return GL_LOW_INT; - case EbpUndefined: - // Should be defined as the default precision by the parser - default: - UNREACHABLE(); + case EbpHigh: + return GL_HIGH_INT; + case EbpMedium: + return GL_MEDIUM_INT; + case EbpLow: + return GL_LOW_INT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: + UNREACHABLE(); } } @@ -206,26 +455,46 @@ GLenum GLVariablePrecision(const TType &type) TString ArrayString(const TType &type) { + TStringStream arrayString; if (!type.isArray()) + return arrayString.str(); + + const TVector &arraySizes = *type.getArraySizes(); + for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend(); + ++arraySizeIter) { - return ""; + arrayString << "["; + if (*arraySizeIter > 0) + { + arrayString << (*arraySizeIter); + } + arrayString << "]"; } + return arrayString.str(); +} - return "[" + str(type.getArraySize()) + "]"; +TString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap) +{ + if (type.getBasicType() == EbtStruct) + return HashName(TName(type.getStruct()->name()), hashFunction, nameMap); + else + return type.getBuiltInTypeNameString(); } bool IsVaryingOut(TQualifier qualifier) { switch (qualifier) { - case EvqVaryingOut: - case EvqSmoothOut: - case EvqFlatOut: - case EvqCentroidOut: - case EvqVertexOut: - return true; - - default: break; + case EvqVaryingOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqVertexOut: + case EvqGeometryOut: + return true; + + default: + break; } return false; @@ -235,14 +504,16 @@ bool IsVaryingIn(TQualifier qualifier) { switch (qualifier) { - case EvqVaryingIn: - case EvqSmoothIn: - case EvqFlatIn: - case EvqCentroidIn: - case EvqFragmentIn: - return true; - - default: break; + case EvqVaryingIn: + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + case EvqFragmentIn: + case EvqGeometryIn: + return true; + + default: + break; } return false; @@ -253,108 +524,191 @@ bool IsVarying(TQualifier qualifier) return IsVaryingIn(qualifier) || IsVaryingOut(qualifier); } +bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier) +{ + return (qualifier == EvqGeometryIn) || + ((shaderType == GL_GEOMETRY_SHADER_OES) && IsInterpolationIn(qualifier)); +} + InterpolationType GetInterpolationType(TQualifier qualifier) { switch (qualifier) { - case EvqFlatIn: - case EvqFlatOut: - return INTERPOLATION_FLAT; - - case EvqSmoothIn: - case EvqSmoothOut: - case EvqVertexOut: - case EvqFragmentIn: - case EvqVaryingIn: - case EvqVaryingOut: - return INTERPOLATION_SMOOTH; - - case EvqCentroidIn: - case EvqCentroidOut: - return INTERPOLATION_CENTROID; - - default: UNREACHABLE(); - return INTERPOLATION_SMOOTH; + case EvqFlatIn: + case EvqFlatOut: + return INTERPOLATION_FLAT; + + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqVaryingIn: + case EvqVaryingOut: + case EvqGeometryIn: + case EvqGeometryOut: + return INTERPOLATION_SMOOTH; + + case EvqCentroidIn: + case EvqCentroidOut: + return INTERPOLATION_CENTROID; + + default: + UNREACHABLE(); + return INTERPOLATION_SMOOTH; + } +} + +TType GetShaderVariableBasicType(const sh::ShaderVariable &var) +{ + switch (var.type) + { + case GL_BOOL: + return TType(EbtBool); + case GL_BOOL_VEC2: + return TType(EbtBool, 2); + case GL_BOOL_VEC3: + return TType(EbtBool, 3); + case GL_BOOL_VEC4: + return TType(EbtBool, 4); + case GL_FLOAT: + return TType(EbtFloat); + case GL_FLOAT_VEC2: + return TType(EbtFloat, 2); + case GL_FLOAT_VEC3: + return TType(EbtFloat, 3); + case GL_FLOAT_VEC4: + return TType(EbtFloat, 4); + case GL_FLOAT_MAT2: + return TType(EbtFloat, 2, 2); + case GL_FLOAT_MAT3: + return TType(EbtFloat, 3, 3); + case GL_FLOAT_MAT4: + return TType(EbtFloat, 4, 4); + case GL_FLOAT_MAT2x3: + return TType(EbtFloat, 2, 3); + case GL_FLOAT_MAT2x4: + return TType(EbtFloat, 2, 4); + case GL_FLOAT_MAT3x2: + return TType(EbtFloat, 3, 2); + case GL_FLOAT_MAT3x4: + return TType(EbtFloat, 3, 4); + case GL_FLOAT_MAT4x2: + return TType(EbtFloat, 4, 2); + case GL_FLOAT_MAT4x3: + return TType(EbtFloat, 4, 3); + case GL_INT: + return TType(EbtInt); + case GL_INT_VEC2: + return TType(EbtInt, 2); + case GL_INT_VEC3: + return TType(EbtInt, 3); + case GL_INT_VEC4: + return TType(EbtInt, 4); + case GL_UNSIGNED_INT: + return TType(EbtUInt); + case GL_UNSIGNED_INT_VEC2: + return TType(EbtUInt, 2); + case GL_UNSIGNED_INT_VEC3: + return TType(EbtUInt, 3); + case GL_UNSIGNED_INT_VEC4: + return TType(EbtUInt, 4); + default: + UNREACHABLE(); + return TType(); } } -GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable) - : mSymbolTable(symbolTable) +// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier +bool CanBeInvariantESSL1(TQualifier qualifier) { + return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) || + IsBuiltinOutputVariable(qualifier) || + (IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing); } -template void GetVariableTraverser::setTypeSpecificInfo( - const TType &type, const TString& name, InterfaceBlockField *variable); -template void GetVariableTraverser::setTypeSpecificInfo( - const TType &type, const TString& name, ShaderVariable *variable); -template void GetVariableTraverser::setTypeSpecificInfo( - const TType &type, const TString& name, Uniform *variable); +// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier +// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier) +{ + return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut || + IsBuiltinOutputVariable(qualifier); +} -template<> -void GetVariableTraverser::setTypeSpecificInfo( - const TType &type, const TString& name, Varying *variable) +bool IsBuiltinOutputVariable(TQualifier qualifier) { - ASSERT(variable); - switch (type.getQualifier()) + switch (qualifier) { - case EvqVaryingIn: - case EvqVaryingOut: - case EvqVertexOut: - case EvqSmoothOut: - case EvqFlatOut: - case EvqCentroidOut: - if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant()) - { - variable->isInvariant = true; - } - break; - default: - break; + case EvqPosition: + case EvqPointSize: + case EvqFragDepth: + case EvqFragDepthEXT: + case EvqFragColor: + case EvqSecondaryFragColorEXT: + case EvqFragData: + case EvqSecondaryFragDataEXT: + return true; + default: + break; } - - variable->interpolation = GetInterpolationType(type.getQualifier()); + return false; } -template -void GetVariableTraverser::traverse(const TType &type, - const TString &name, - std::vector *output) +bool IsBuiltinFragmentInputVariable(TQualifier qualifier) { - const TStructure *structure = type.getStruct(); + switch (qualifier) + { + case EvqFragCoord: + case EvqPointCoord: + case EvqFrontFacing: + return true; + default: + break; + } + return false; +} - VarT variable; - variable.name = name.c_str(); - variable.arraySize = static_cast(type.getArraySize()); +bool IsOutputESSL(ShShaderOutput output) +{ + return output == SH_ESSL_OUTPUT; +} - if (!structure) +bool IsOutputGLSL(ShShaderOutput output) +{ + switch (output) { - variable.type = GLVariableType(type); - variable.precision = GLVariablePrecision(type); + 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: + return true; + default: + break; } - else + return false; +} +bool IsOutputHLSL(ShShaderOutput output) +{ + switch (output) { - // Note: this enum value is not exposed outside ANGLE - variable.type = GL_STRUCT_ANGLEX; - variable.structName = structure->name().c_str(); - - const TFieldList &fields = structure->fields(); - - for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) - { - TField *field = fields[fieldIndex]; - traverse(*field->type(), field->name(), &variable.fields); - } + case SH_HLSL_3_0_OUTPUT: + case SH_HLSL_4_1_OUTPUT: + case SH_HLSL_4_0_FL9_3_OUTPUT: + return true; + default: + break; } - setTypeSpecificInfo(type, name, &variable); - visitVariable(&variable); - - ASSERT(output); - output->push_back(variable); + return false; } - -template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); -template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); -template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); -template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); - +bool IsOutputVulkan(ShShaderOutput output) +{ + return output == SH_GLSL_VULKAN_OUTPUT; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h index ea7a35a352..6d6dc95b3b 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.h +++ b/src/3rdparty/angle/src/compiler/translator/util.h @@ -12,54 +12,52 @@ #include "angle_gl.h" #include +#include "compiler/translator/HashNames.h" +#include "compiler/translator/Operator.h" #include "compiler/translator/Types.h" -// 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. -bool strtof_clamp(const std::string &str, float *value); - // If overflow happens, clamp the value to UINT_MIN or UINT_MAX. // Return false if overflow happens. bool atoi_clamp(const char *str, unsigned int *value); -class TSymbolTable; - namespace sh { +class TSymbolTable; + +float NumericLexFloat32OutOfRangeToInfinity(const std::string &str); + +// strtof_clamp is like strtof but +// 1. it forces C locale, i.e. forcing '.' as decimal point. +// 2. it sets the value to infinity if overflow happens. +// 3. str should be guaranteed to be in the valid format for a floating point number as defined +// by the grammar in the ESSL 3.00.6 spec section 4.1.4. +// Return false if overflow happens. +bool strtof_clamp(const std::string &str, float *value); GLenum GLVariableType(const TType &type); GLenum GLVariablePrecision(const TType &type); bool IsVaryingIn(TQualifier qualifier); bool IsVaryingOut(TQualifier qualifier); bool IsVarying(TQualifier qualifier); +bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier); -TString ArrayString(const TType &type); -class GetVariableTraverser : angle::NonCopyable -{ - public: - GetVariableTraverser(const TSymbolTable &symbolTable); - virtual ~GetVariableTraverser() {} - - template - void traverse(const TType &type, const TString &name, std::vector *output); - - protected: - // May be overloaded - virtual void visitVariable(ShaderVariable *newVar) {} +// Returns array brackets including size with outermost array size first, as specified in GLSL ES +// 3.10 section 4.1.9. +TString ArrayString(const TType &type); - private: - // Helper function called by traverse() to fill specific fields - // for attributes/varyings/uniforms. - template - void setTypeSpecificInfo( - const TType &type, const TString &name, VarT *variable) {} +TString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap); - const TSymbolTable &mSymbolTable; -}; +TType GetShaderVariableBasicType(const sh::ShaderVariable &var); -} +bool IsBuiltinOutputVariable(TQualifier qualifier); +bool IsBuiltinFragmentInputVariable(TQualifier qualifier); +bool CanBeInvariantESSL1(TQualifier qualifier); +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier); +bool IsOutputESSL(ShShaderOutput output); +bool IsOutputGLSL(ShShaderOutput output); +bool IsOutputHLSL(ShShaderOutput output); +bool IsOutputVulkan(ShShaderOutput output); +} // namespace sh -#endif // COMPILER_TRANSLATOR_UTIL_H_ +#endif // COMPILER_TRANSLATOR_UTIL_H_ diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp new file mode 100644 index 0000000000..f8d744342d --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.cpp @@ -0,0 +1,171 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo.cpp: implementation of the system-agnostic parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo.h" + +#include +#include + +#include "common/debug.h" +#include "common/string_utils.h" + +namespace angle +{ + +GPUDeviceInfo::GPUDeviceInfo() = default; + +GPUDeviceInfo::~GPUDeviceInfo() = default; + +GPUDeviceInfo::GPUDeviceInfo(const GPUDeviceInfo &other) = default; + +SystemInfo::SystemInfo() = default; + +SystemInfo::~SystemInfo() = default; + +SystemInfo::SystemInfo(const SystemInfo &other) = default; + +bool IsAMD(VendorID vendorId) +{ + return vendorId == kVendorID_AMD; +} + +bool IsIntel(VendorID vendorId) +{ + return vendorId == kVendorID_Intel; +} + +bool IsNvidia(VendorID vendorId) +{ + return vendorId == kVendorID_Nvidia; +} + +bool IsQualcomm(VendorID vendorId) +{ + return vendorId == kVendorID_Qualcomm; +} + +bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version) +{ + const size_t begin = content.find_first_of("0123456789"); + if (begin == std::string::npos) + { + return false; + } + + const size_t end = content.find_first_not_of("0123456789.", begin); + if (end == std::string::npos) + { + *version = content.substr(begin); + } + else + { + *version = content.substr(begin, end - begin); + } + return true; +} + +bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version) +{ + std::istringstream stream(content); + + std::string line; + while (std::getline(stream, line)) + { + static const char kReleaseVersion[] = "ReleaseVersion="; + if (line.compare(0, std::strlen(kReleaseVersion), kReleaseVersion) != 0) + { + continue; + } + + if (ParseAMDBrahmaDriverVersion(line, version)) + { + return true; + } + } + return false; +} + +bool ParseMacMachineModel(const std::string &identifier, + std::string *type, + int32_t *major, + int32_t *minor) +{ + size_t numberLoc = identifier.find_first_of("0123456789"); + if (numberLoc == std::string::npos) + { + return false; + } + + size_t commaLoc = identifier.find(',', numberLoc); + if (commaLoc == std::string::npos || commaLoc >= identifier.size()) + { + return false; + } + + const char *numberPtr = &identifier[numberLoc]; + const char *commaPtr = &identifier[commaLoc + 1]; + char *endPtr = nullptr; + + int32_t majorTmp = std::strtol(numberPtr, &endPtr, 10); + if (endPtr == numberPtr) + { + return false; + } + + int32_t minorTmp = std::strtol(commaPtr, &endPtr, 10); + if (endPtr == commaPtr) + { + return false; + } + + *major = majorTmp; + *minor = minorTmp; + *type = identifier.substr(0, numberLoc); + + return true; +} + +bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId) +{ + unsigned int vendor = 0; + unsigned int device = 0; + + bool success = id.length() >= 21 && HexStringToUInt(id.substr(8, 4), &vendor) && + HexStringToUInt(id.substr(17, 4), &device); + + *vendorId = vendor; + *deviceId = device; + return success; +} + +void FindPrimaryGPU(SystemInfo *info) +{ + ASSERT(!info->gpus.empty()); + + // On dual-GPU systems we assume the non-Intel GPU is the primary one. + int primary = 0; + bool hasIntel = false; + for (size_t i = 0; i < info->gpus.size(); ++i) + { + if (IsIntel(info->gpus[i].vendorId)) + { + hasIntel = true; + } + if (IsIntel(info->gpus[primary].vendorId)) + { + primary = static_cast(i); + } + } + + // Assume that a combination of AMD or Nvidia with Intel means Optimus or AMD Switchable + info->primaryGPUIndex = primary; + info->isOptimus = hasIntel && IsNvidia(info->gpus[primary].vendorId); + info->isAMDSwitchable = hasIntel && IsAMD(info->gpus[primary].vendorId); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h new file mode 100644 index 0000000000..ada43f0a15 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo.h: gathers information available without starting a GPU driver. + +#ifndef GPU_INFO_UTIL_SYSTEM_INFO_H_ +#define GPU_INFO_UTIL_SYSTEM_INFO_H_ + +#include +#include +#include + +namespace angle +{ + +using VendorID = uint32_t; +using DeviceID = uint32_t; + +constexpr VendorID kVendorID_AMD = 0x1002; +constexpr VendorID kVendorID_Intel = 0x8086; +constexpr VendorID kVendorID_Nvidia = 0x10DE; +constexpr VendorID kVendorID_Qualcomm = 0x5143; + +struct GPUDeviceInfo +{ + GPUDeviceInfo(); + ~GPUDeviceInfo(); + + GPUDeviceInfo(const GPUDeviceInfo &other); + + VendorID vendorId = 0; + DeviceID deviceId = 0; + + std::string driverVendor; + std::string driverVersion; + std::string driverDate; +}; + +struct SystemInfo +{ + SystemInfo(); + ~SystemInfo(); + + SystemInfo(const SystemInfo &other); + + std::vector gpus; + int primaryGPUIndex = -1; + int activeGPUIndex = -1; + + bool isOptimus = false; + bool isAMDSwitchable = false; + + // Only available on macOS + std::string machineModelName; + std::string machineModelVersion; + + // Only available on Windows, set even on failure. + std::string primaryDisplayDeviceId; +}; + +bool GetSystemInfo(SystemInfo *info); + +bool IsAMD(VendorID vendorId); +bool IsIntel(VendorID vendorId); +bool IsNvidia(VendorID vendorId); +bool IsQualcomm(VendorID vendorId); + +} // namespace angle + +#endif // GPU_INFO_UTIL_SYSTEM_INFO_H_ diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h new file mode 100644 index 0000000000..d2f6124662 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_internal.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_internal.h: Functions used by the SystemInfo_* files and unittests + +#ifndef GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ +#define GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ + +#include "gpu_info_util/SystemInfo.h" + +namespace angle +{ + +// Defined in SystemInfo_libpci when GPU_INFO_USE_LIBPCI is defined. +bool GetPCIDevicesWithLibPCI(std::vector *devices); +// Defined in SystemInfo_x11 when GPU_INFO_USE_X11 is defined. +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version); + +// Target specific helper functions that can be compiled on all targets +// Live in SystemInfo.cpp +bool ParseAMDBrahmaDriverVersion(const std::string &content, std::string *version); +bool ParseAMDCatalystDriverVersion(const std::string &content, std::string *version); +bool ParseMacMachineModel(const std::string &identifier, + std::string *type, + int32_t *major, + int32_t *minor); +bool CMDeviceIDToDeviceAndVendorID(const std::string &id, uint32_t *vendorId, uint32_t *deviceId); + +// In the case there are multiple GPUs, this finds the primary one and sets Optimus or AMD +// Switchable +void FindPrimaryGPU(SystemInfo *info); + +} // namespace angle + +#endif // GPU_INFO_UTIL_SYSTEM_INFO_INTERNAL_H_ diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp new file mode 100644 index 0000000000..07c72872ad --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_libpci.cpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_libpci.cpp: implementation of the libPCI-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +#if !defined(GPU_INFO_USE_LIBPCI) +#error SystemInfo_libpci.cpp compiled without GPU_INFO_USE_LIBPCI +#endif + +namespace angle +{ + +namespace +{ + +struct LibPCI : private angle::NonCopyable +{ + LibPCI() + { + if (access("/sys/bus/pci/", F_OK) != 0 && access("/sys/bs/pci_express/", F_OK) != 0) + { + return; + } + + mHandle = dlopen("libpci.so.3", RTLD_LAZY); + + if (mHandle == nullptr) + { + mHandle = dlopen("libpci.so", RTLD_LAZY); + } + + if (mHandle == nullptr) + { + return; + } + + mValid = + (Alloc = reinterpret_cast(dlsym(mHandle, "pci_alloc"))) != nullptr && + (Init = reinterpret_cast(dlsym(mHandle, "pci_init"))) != nullptr && + (Cleanup = reinterpret_cast(dlsym(mHandle, "pci_cleanup"))) != + nullptr && + (ScanBus = reinterpret_cast(dlsym(mHandle, "pci_scan_bus"))) != + nullptr && + (FillInfo = reinterpret_cast(dlsym(mHandle, "pci_fill_info"))) != + nullptr && + (LookupName = reinterpret_cast( + dlsym(mHandle, "pci_lookup_name"))) != nullptr; + } + + bool IsValid() const { return mValid; } + + ~LibPCI() + { + if (mHandle != nullptr) + { + dlclose(mHandle); + } + } + + decltype(&::pci_alloc) Alloc = nullptr; + decltype(&::pci_init) Init = nullptr; + decltype(&::pci_cleanup) Cleanup = nullptr; + decltype(&::pci_scan_bus) ScanBus = nullptr; + decltype(&::pci_fill_info) FillInfo = nullptr; + decltype(&::pci_lookup_name) LookupName = nullptr; + + private: + void *mHandle = nullptr; + bool mValid = false; +}; + +} // anonymous namespace + +// Adds an entry per PCI GPU found and fills the device and vendor ID. +bool GetPCIDevicesWithLibPCI(std::vector *devices) +{ + LibPCI pci; + if (!pci.IsValid()) + { + return false; + } + + pci_access *access = pci.Alloc(); + ASSERT(access != nullptr); + pci.Init(access); + pci.ScanBus(access); + + for (pci_dev *device = access->devices; device != nullptr; device = device->next) + { + pci.FillInfo(device, PCI_FILL_IDENT | PCI_FILL_CLASS); + + // Skip non-GPU devices + switch (device->device_class) + { + case PCI_CLASS_DISPLAY_VGA: + case PCI_CLASS_DISPLAY_XGA: + case PCI_CLASS_DISPLAY_3D: + break; + default: + continue; + } + + // Skip unknown devices + if (device->vendor_id == 0 || device->device_id == 0) + { + continue; + } + + GPUDeviceInfo info; + info.vendorId = device->vendor_id; + info.deviceId = device->device_id; + + devices->push_back(info); + } + + pci.Cleanup(access); + + return true; +} +} diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp new file mode 100644 index 0000000000..98f000b069 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_linux.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_linux.cpp: implementation of the Linux-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace angle +{ + +namespace +{ + +bool ReadWholeFile(const char *filename, std::string *content) +{ + std::ifstream file(filename); + + if (!file) + { + return false; + } + + *content = std::string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + return true; +} + +// Scan /sys/module/amdgpu/version. +bool GetAMDBrahmaDriverVersion(std::string *version) +{ + *version = ""; + std::string content; + + return ReadWholeFile("/sys/module/amdgpu/version", &content) && + ParseAMDBrahmaDriverVersion(content, version); +} + +// Scan /etc/ati/amdpcsdb.default for "ReleaseVersion". +bool GetAMDCatalystDriverVersion(std::string *version) +{ + *version = ""; + std::string content; + + return ReadWholeFile("/etc/ati/amdpcsdb.default", &content) && + ParseAMDCatalystDriverVersion(content, version); +} + +} // anonymous namespace + +#if !defined(GPU_INFO_USE_X11) +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version) +{ + return false; +} +#endif + +#if !defined(GPU_INFO_USE_LIBPCI) +bool GetPCIDevicesWithLibPCI(std::vector *devices) +{ + return false; +} +#endif + +bool GetSystemInfo(SystemInfo *info) +{ + if (!GetPCIDevicesWithLibPCI(&(info->gpus))) + { + return false; + } + + if (info->gpus.size() == 0) + { + return false; + } + + FindPrimaryGPU(info); + + for (size_t i = 0; i < info->gpus.size(); ++i) + { + GPUDeviceInfo *gpu = &info->gpus[i]; + + // New GPUs might be added inside this loop, don't query for their driver version again + if (!gpu->driverVendor.empty()) + { + continue; + } + + if (IsAMD(gpu->vendorId)) + { + std::string version; + if (GetAMDBrahmaDriverVersion(&version)) + { + gpu->driverVendor = "AMD (Brahma)"; + gpu->driverVersion = std::move(version); + } + else if (GetAMDCatalystDriverVersion(&version)) + { + gpu->driverVendor = "AMD (Catalyst)"; + gpu->driverVersion = std::move(version); + } + } + + if (IsNvidia(gpu->vendorId)) + { + std::string version; + if (GetNvidiaDriverVersionWithXNVCtrl(&version)) + { + gpu->driverVendor = "Nvidia"; + gpu->driverVersion = std::move(version); + } + } + + // In dual-GPU cases the PCI scan sometimes only gives us the Intel GPU. + // If we are able to query for the Nvidia driver version, it means there + // was hidden Nvidia GPU, so we add it to the list and make it primary. + if (IsIntel(gpu->vendorId) && info->gpus.size() == 1) + { + std::string version; + if (GetNvidiaDriverVersionWithXNVCtrl(&version)) + { + GPUDeviceInfo nvidiaInfo; + nvidiaInfo.vendorId = kVendorID_Nvidia; + nvidiaInfo.deviceId = 0; + gpu->driverVendor = "Nvidia"; + gpu->driverVersion = std::move(version); + + info->gpus.emplace_back(std::move(nvidiaInfo)); + info->isOptimus = true; + } + } + } + + return true; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm new file mode 100644 index 0000000000..7a7a62d170 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_mac.mm @@ -0,0 +1,170 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_mac.cpp: implementation of the Mac-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#import +#import + +namespace angle +{ + +namespace +{ + +std::string GetMachineModel() +{ + io_service_t platformExpert = IOServiceGetMatchingService( + kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + + if (platformExpert == IO_OBJECT_NULL) + { + return ""; + } + + CFDataRef modelData = static_cast( + IORegistryEntryCreateCFProperty(platformExpert, CFSTR("model"), kCFAllocatorDefault, 0)); + if (modelData == nullptr) + { + IOObjectRelease(platformExpert); + return ""; + } + + std::string result = reinterpret_cast(CFDataGetBytePtr(modelData)); + + IOObjectRelease(platformExpert); + CFRelease(modelData); + + return result; +} + +// Extracts one integer property from a registry entry. +bool GetEntryProperty(io_registry_entry_t entry, CFStringRef name, uint32_t *value) +{ + *value = 0; + + CFDataRef data = static_cast( + IORegistryEntrySearchCFProperty(entry, kIOServicePlane, name, kCFAllocatorDefault, + kIORegistryIterateRecursively | kIORegistryIterateParents)); + + if (data == nullptr) + { + return false; + } + + const uint32_t *valuePtr = reinterpret_cast(CFDataGetBytePtr(data)); + + if (valuePtr == nullptr) + { + CFRelease(data); + return false; + } + + *value = *valuePtr; + CFRelease(data); + return true; +} + +// CGDisplayIOServicePort is deprecated as of macOS 10.9, but has no replacement, see +// https://crbug.com/650837 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +// Find the info of the current GPU. +bool GetActiveGPU(VendorID *vendorId, DeviceID *deviceId) +{ + io_registry_entry_t port = CGDisplayIOServicePort(kCGDirectMainDisplay); + + return GetEntryProperty(port, CFSTR("vendor-id"), vendorId) && + GetEntryProperty(port, CFSTR("device-id"), deviceId); +} + +#pragma clang diagnostic pop + +// Gathers the vendor and device IDs for the PCI GPUs +bool GetPCIDevices(std::vector *devices) +{ + // matchDictionary will be consumed by IOServiceGetMatchingServices, no need to release it. + CFMutableDictionaryRef matchDictionary = IOServiceMatching("IOPCIDevice"); + + io_iterator_t entryIterator; + if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchDictionary, &entryIterator) != + kIOReturnSuccess) + { + return false; + } + + io_registry_entry_t entry = IO_OBJECT_NULL; + + while ((entry = IOIteratorNext(entryIterator)) != IO_OBJECT_NULL) + { + constexpr uint32_t kClassCodeDisplayVGA = 0x30000; + uint32_t classCode; + GPUDeviceInfo info; + + if (GetEntryProperty(entry, CFSTR("class-code"), &classCode) && + classCode == kClassCodeDisplayVGA && + GetEntryProperty(entry, CFSTR("vendor-id"), &info.vendorId) && + GetEntryProperty(entry, CFSTR("device-id"), &info.deviceId)) + { + devices->push_back(info); + } + + IOObjectRelease(entry); + } + IOObjectRelease(entryIterator); + + return true; +} + +} // anonymous namespace + +bool GetSystemInfo(SystemInfo *info) +{ + { + int32_t major = 0; + int32_t minor = 0; + ParseMacMachineModel(GetMachineModel(), &info->machineModelName, &major, &minor); + info->machineModelVersion = std::to_string(major) + "." + std::to_string(minor); + } + + if (!GetPCIDevices(&(info->gpus))) + { + return false; + } + + if (info->gpus.empty()) + { + return false; + } + + // Find the active GPU + { + VendorID activeVendor; + DeviceID activeDevice; + if (!GetActiveGPU(&activeVendor, &activeDevice)) + { + return false; + } + + for (size_t i = 0; i < info->gpus.size(); ++i) + { + if (info->gpus[i].vendorId == activeVendor && info->gpus[i].deviceId == activeDevice) + { + info->activeGPUIndex = i; + break; + } + } + } + + FindPrimaryGPU(info); + + return true; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp new file mode 100644 index 0000000000..041fdad34d --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_win.cpp @@ -0,0 +1,251 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_win.cpp: implementation of the Windows-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include "common/debug.h" +#include "common/string_utils.h" + +// Windows.h needs to be included first +#include + +#if defined(GPU_INFO_USE_SETUPAPI) +// Remove parts of commctrl.h that have compile errors +#define NOTOOLBAR +#define NOTOOLTIPS +#include +#include +#elif defined(GPU_INFO_USE_DXGI) +#include +#include +#else +#error "SystemInfo_win needs at least GPU_INFO_USE_SETUPAPI or GPU_INFO_USE_DXGI defined" +#endif + +#include +#include + +namespace angle +{ + +namespace +{ + +// Returns the CM device ID of the primary GPU. +std::string GetPrimaryDisplayDeviceId() +{ + DISPLAY_DEVICEA displayDevice; + displayDevice.cb = sizeof(DISPLAY_DEVICEA); + + for (int i = 0; EnumDisplayDevicesA(nullptr, i, &displayDevice, 0); ++i) + { + if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + return displayDevice.DeviceID; + } + } + + return ""; +} + +#if defined(GPU_INFO_USE_SETUPAPI) + +std::string GetRegistryStringValue(HKEY key, const char *valueName) +{ + std::array value; + DWORD valueSize = sizeof(value); + if (RegQueryValueExA(key, valueName, nullptr, nullptr, reinterpret_cast(value.data()), + &valueSize) == ERROR_SUCCESS) + { + return value.data(); + } + return ""; +} + +// Gathers information about the devices from the registry. The reason why we aren't using +// a dedicated API such as DXGI is that we need information like the driver vendor and date. +// DXGI doesn't provide a way to know the device registry key from an IDXGIAdapter. +bool GetDevicesFromRegistry(std::vector *devices) +{ + // Display adapter class GUID from + // https://msdn.microsoft.com/en-us/library/windows/hardware/ff553426%28v=vs.85%29.aspx + GUID displayClass = { + 0x4d36e968, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}; + + HDEVINFO deviceInfo = SetupDiGetClassDevsW(&displayClass, nullptr, nullptr, DIGCF_PRESENT); + + if (deviceInfo == INVALID_HANDLE_VALUE) + { + return false; + } + + // This iterates over the devices of the "Display adapter" class + DWORD deviceIndex = 0; + SP_DEVINFO_DATA deviceData; + deviceData.cbSize = sizeof(deviceData); + while (SetupDiEnumDeviceInfo(deviceInfo, deviceIndex++, &deviceData)) + { + // The device and vendor IDs can be gathered directly, but information about the driver + // requires some registry digging + char fullDeviceID[MAX_DEVICE_ID_LEN]; + if (CM_Get_Device_IDA(deviceData.DevInst, fullDeviceID, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) + { + continue; + } + + GPUDeviceInfo device; + + if (!CMDeviceIDToDeviceAndVendorID(fullDeviceID, &device.vendorId, &device.deviceId)) + { + continue; + } + + // The driver key will end with something like {}/<4 digit number>. + std::array value; + if (!SetupDiGetDeviceRegistryPropertyW(deviceInfo, &deviceData, SPDRP_DRIVER, nullptr, + reinterpret_cast(value.data()), sizeof(value), + nullptr)) + { + continue; + } + + std::wstring driverKey = L"System\\CurrentControlSet\\Control\\Class\\"; + driverKey += value.data(); + + HKEY key; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, driverKey.c_str(), 0, KEY_QUERY_VALUE, &key) != + ERROR_SUCCESS) + { + continue; + } + + device.driverVersion = GetRegistryStringValue(key, "DriverVersion"); + device.driverDate = GetRegistryStringValue(key, "DriverDate"); + device.driverVendor = GetRegistryStringValue(key, "ProviderName"); + + RegCloseKey(key); + + devices->push_back(device); + } + + SetupDiDestroyDeviceInfoList(deviceInfo); + + return true; +} + +#elif defined(GPU_INFO_USE_DXGI) + +bool GetDevicesFromDXGI(std::vector *devices) +{ + IDXGIFactory *factory; + if (!SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&factory)))) + { + return false; + } + + UINT i = 0; + IDXGIAdapter *adapter = nullptr; + while (factory->EnumAdapters(i++, &adapter) != DXGI_ERROR_NOT_FOUND) + { + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + LARGE_INTEGER umdVersion; + if (adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &umdVersion) == + DXGI_ERROR_UNSUPPORTED) + { + adapter->Release(); + continue; + } + + // The UMD driver version here is the same as in the registry except for the last number. + uint64_t intVersion = umdVersion.QuadPart; + std::ostringstream o; + + const uint64_t kMask = 0xFF; + o << ((intVersion >> 48) & kMask) << "."; + o << ((intVersion >> 32) & kMask) << "."; + o << ((intVersion >> 16) & kMask) << "."; + o << (intVersion & kMask); + + GPUDeviceInfo device; + device.vendorId = desc.VendorId; + device.deviceId = desc.DeviceId; + device.driverVersion = o.str(); + + devices->push_back(device); + + adapter->Release(); + } + + factory->Release(); + + return true; +} + +#else +#error +#endif + +} // anonymous namespace + +bool GetSystemInfo(SystemInfo *info) +{ + // Get the CM device ID first so that it is returned even in error cases. + info->primaryDisplayDeviceId = GetPrimaryDisplayDeviceId(); + +#if defined(GPU_INFO_USE_SETUPAPI) + if (!GetDevicesFromRegistry(&info->gpus)) + { + return false; + } +#elif defined(GPU_INFO_USE_DXGI) + if (!GetDevicesFromDXGI(&info->gpus)) + { + return false; + } +#else +#error +#endif + + if (info->gpus.size() == 0) + { + return false; + } + + FindPrimaryGPU(info); + + // Override the primary GPU index with what we gathered from EnumDisplayDevices + uint32_t primaryVendorId = 0; + uint32_t primaryDeviceId = 0; + + if (!CMDeviceIDToDeviceAndVendorID(info->primaryDisplayDeviceId, &primaryVendorId, + &primaryDeviceId)) + { + return false; + } + + bool foundPrimary = false; + for (size_t i = 0; i < info->gpus.size(); ++i) + { + if (info->gpus[i].vendorId == primaryVendorId && info->gpus[i].deviceId == primaryDeviceId) + { + info->primaryGPUIndex = static_cast(i); + foundPrimary = true; + } + } + ASSERT(foundPrimary); + + // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled. + HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll"); + info->isOptimus = nvd3d9wrap != nullptr; + + return true; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp new file mode 100644 index 0000000000..3513309f36 --- /dev/null +++ b/src/3rdparty/angle/src/gpu_info_util/SystemInfo_x11.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2013-2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SystemInfo_x11.cpp: implementation of the X11-specific parts of SystemInfo.h + +#include "gpu_info_util/SystemInfo_internal.h" + +#include + +#include "common/debug.h" +#include "third_party/libXNVCtrl/NVCtrl.h" +#include "third_party/libXNVCtrl/NVCtrlLib.h" + +#if !defined(GPU_INFO_USE_X11) +#error SystemInfo_x11.cpp compiled without GPU_INFO_USE_X11 +#endif + +namespace angle +{ + +bool GetNvidiaDriverVersionWithXNVCtrl(std::string *version) +{ + *version = ""; + + int eventBase = 0; + int errorBase = 0; + + Display *display = XOpenDisplay(nullptr); + + if (XNVCTRLQueryExtension(display, &eventBase, &errorBase)) + { + int screenCount = ScreenCount(display); + for (int screen = 0; screen < screenCount; ++screen) + { + char *buffer = nullptr; + if (XNVCTRLIsNvScreen(display, screen) && + XNVCTRLQueryStringAttribute(display, screen, 0, + NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &buffer)) + { + ASSERT(buffer != nullptr); + *version = buffer; + XFree(buffer); + return true; + } + } + } + + return false; +} +} diff --git a/src/3rdparty/angle/src/id/commit.h b/src/3rdparty/angle/src/id/commit.h deleted file mode 100644 index 0546412964..0000000000 --- a/src/3rdparty/angle/src/id/commit.h +++ /dev/null @@ -1,3 +0,0 @@ -#define ANGLE_COMMIT_HASH "8613f4946861" -#define ANGLE_COMMIT_HASH_SIZE 12 -#define ANGLE_COMMIT_DATE "2016-02-11 19:53:41 +0000" diff --git a/src/3rdparty/angle/src/image_util/copyimage.cpp b/src/3rdparty/angle/src/image_util/copyimage.cpp new file mode 100644 index 0000000000..cc07908158 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/copyimage.cpp @@ -0,0 +1,22 @@ +// +// 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. +// + +// copyimage.cpp: Defines image copying functions + +#include "image_util/copyimage.h" + +namespace angle +{ + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest) +{ + uint32_t argb = *reinterpret_cast(source); + *reinterpret_cast(dest) = (argb & 0xFF00FF00) | // Keep alpha and green + (argb & 0x00FF0000) >> 16 | // Move red to blue + (argb & 0x000000FF) << 16; // Move blue to red +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/copyimage.h b/src/3rdparty/angle/src/image_util/copyimage.h new file mode 100644 index 0000000000..bc8c1390eb --- /dev/null +++ b/src/3rdparty/angle/src/image_util/copyimage.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.h: Defines image copying functions + +#ifndef IMAGEUTIL_COPYIMAGE_H_ +#define IMAGEUTIL_COPYIMAGE_H_ + +#include "common/Color.h" + +#include "image_util/imageformats.h" + +#include + +namespace angle +{ + +template +void ReadColor(const uint8_t *source, uint8_t *dest); + +template +void WriteColor(const uint8_t *source, uint8_t *dest); + +template +void CopyPixel(const uint8_t *source, uint8_t *dest); + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest); + +} // namespace angle + +#include "copyimage.inl" + +#endif // IMAGEUTIL_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/image_util/copyimage.inl b/src/3rdparty/angle/src/image_util/copyimage.inl new file mode 100644 index 0000000000..dbada81291 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/copyimage.inl @@ -0,0 +1,34 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// copyimage.inl: Defines image copying functions + +namespace angle +{ + +template +inline void ReadColor(const uint8_t *source, uint8_t *dest) +{ + sourceType::readColor(reinterpret_cast*>(dest), + reinterpret_cast(source)); +} + +template +inline void WriteColor(const uint8_t *source, uint8_t *dest) +{ + destType::writeColor(reinterpret_cast(dest), + reinterpret_cast*>(source)); +} + +template +inline void CopyPixel(const uint8_t *source, uint8_t *dest) +{ + colorDataType temp; + ReadColor(source, &temp); + WriteColor(&temp, dest); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/generatemip.h b/src/3rdparty/angle/src/image_util/generatemip.h new file mode 100644 index 0000000000..a89db823b0 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/generatemip.h @@ -0,0 +1,34 @@ +// +// 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. +// + +// generatemip.h: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#ifndef IMAGEUTIL_GENERATEMIP_H_ +#define IMAGEUTIL_GENERATEMIP_H_ + +#include +#include + +namespace angle +{ + +template +inline void GenerateMip(size_t sourceWidth, + size_t sourceHeight, + size_t sourceDepth, + const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourceDepthPitch, + uint8_t *destData, + size_t destRowPitch, + size_t destDepthPitch); + +} // namespace angle + +#include "generatemip.inl" + +#endif // IMAGEUTIL_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/image_util/generatemip.inl b/src/3rdparty/angle/src/image_util/generatemip.inl new file mode 100644 index 0000000000..ddf510c749 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/generatemip.inl @@ -0,0 +1,268 @@ +// +// 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. +// + +// generatemip.inl: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#include "common/mathutil.h" + +#include "image_util/imageformats.h" + +namespace angle +{ + +namespace priv +{ + +template +static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth == 1); + + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + const T *src0 = GetPixel(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, 0, z, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, 0, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src4 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src5 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src6 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src7 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(&tmp2, src4, src5); + T::average(&tmp3, src6, src7); + + T::average(&tmp4, &tmp0, &tmp1); + T::average(&tmp5, &tmp2, &tmp3); + + T::average(dst, &tmp4, &tmp5); + } + } + } +} + + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +template +static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) +{ + uint8_t index = ((sourceWidth > 1) ? 1 : 0) | + ((sourceHeight > 1) ? 2 : 0) | + ((sourceDepth > 1) ? 4 : 0); + + switch (index) + { + case 0: return nullptr; + case 1: return GenerateMip_X; // W x 1 x 1 + case 2: return GenerateMip_Y; // 1 x H x 1 + case 3: return GenerateMip_XY; // W x H x 1 + case 4: return GenerateMip_Z; // 1 x 1 x D + case 5: return GenerateMip_XZ; // W x 1 x D + case 6: return GenerateMip_YZ; // 1 x H x D + case 7: return GenerateMip_XYZ; // W x H x D + } + + UNREACHABLE(); + return nullptr; +} + +} // namespace priv + +template +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + size_t mipWidth = std::max(1, sourceWidth >> 1); + size_t mipHeight = std::max(1, sourceHeight >> 1); + size_t mipDepth = std::max(1, sourceDepth >> 1); + + priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction(sourceWidth, sourceHeight, sourceDepth); + ASSERT(generationFunction != nullptr); + + generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, + mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/imageformats.cpp b/src/3rdparty/angle/src/image_util/imageformats.cpp new file mode 100644 index 0000000000..a4c86945b6 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/imageformats.cpp @@ -0,0 +1,1722 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// imageformats.cpp: Defines image format types with functions for mip generation +// and copying. + +#include "image_util/imageformats.h" + +#include "common/mathutil.h" + +namespace angle +{ + +void L8::readColor(gl::ColorF *dst, const L8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; +} + +void L8::writeColor(L8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized(src->red); +} + +void L8::average(L8 *dst, const L8 *src1, const L8 *src2) +{ + dst->L = gl::average(src1->L, src2->L); +} + +void R8::readColor(gl::ColorUI *dst, const R8 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R8::readColor(gl::ColorF *dst, const R8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8::writeColor(R8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); +} + +void R8::writeColor(R8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R8::average(R8 *dst, const R8 *src1, const R8 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void A8::readColor(gl::ColorF *dst, const A8 *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8::writeColor(A8 *dst, const gl::ColorF *src) +{ + dst->A = gl::floatToNormalized(src->alpha); +} + +void A8::average(A8 *dst, const A8 *src1, const A8 *src2) +{ + dst->A = gl::average(src1->A, src2->A); +} + +void L8A8::readColor(gl::ColorF *dst, const L8A8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void L8A8::writeColor(L8A8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized(src->red); + dst->A = gl::floatToNormalized(src->alpha); +} + +void L8A8::average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void A8L8::readColor(gl::ColorF *dst, const A8L8 *src) +{ + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8L8::writeColor(A8L8 *dst, const gl::ColorF *src) +{ + dst->L = gl::floatToNormalized(src->red); + dst->A = gl::floatToNormalized(src->alpha); +} + +void A8L8::average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void R8G8::readColor(gl::ColorUI *dst, const R8G8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R8G8::readColor(gl::ColorF *dst, const R8G8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8G8::writeColor(R8G8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R8G8::writeColor(R8G8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R8G8::average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) +{ + *(uint16_t *)dst = (((*(uint16_t *)src1 ^ *(uint16_t *)src2) & 0xFEFE) >> 1) + + (*(uint16_t *)src1 & *(uint16_t *)src2); +} + +void R8G8B8::readColor(gl::ColorUI *dst, const R8G8B8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; +} + +void R8G8B8::readColor(gl::ColorF *dst, const R8G8B8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R8G8B8::writeColor(R8G8B8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R8G8B8::writeColor(R8G8B8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R8G8B8::average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *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); +} + +void B8G8R8::readColor(gl::ColorUI *dst, const B8G8R8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; +} + +void B8G8R8::readColor(gl::ColorF *dst, const B8G8R8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void B8G8R8::writeColor(B8G8R8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void B8G8R8::writeColor(B8G8R8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void B8G8R8::average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *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); +} + +void R5G6B5::readColor(gl::ColorF *dst, const R5G6B5 *src) +{ + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); + dst->alpha = 1.0f; +} + +void R5G6B5::writeColor(R5G6B5 *dst, const gl::ColorF *src) +{ + dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, uint16_t>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(src->blue)); +} + +void R5G6B5::average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) +{ + dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), + gl::getShiftedData<5, 11>(src2->RGB))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), + gl::getShiftedData<6, 5>(src2->RGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), + gl::getShiftedData<5, 0>(src2->RGB))); +} + +void B5G6R5::readColor(gl::ColorF *dst, const B5G6R5 *src) +{ + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->BGR)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->BGR)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGR)); + dst->alpha = 1.0f; +} + +void B5G6R5::writeColor(B5G6R5 *dst, const gl::ColorF *src) +{ + dst->BGR = gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | + gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)); +} + +void B5G6R5::average(B5G6R5 *dst, const B5G6R5 *src1, const B5G6R5 *src2) +{ + dst->BGR = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->BGR), + gl::getShiftedData<5, 11>(src2->BGR))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->BGR), + gl::getShiftedData<6, 5>(src2->BGR))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGR), + gl::getShiftedData<5, 0>(src2->BGR))); +} + +void A8R8G8B8::readColor(gl::ColorUI *dst, const A8R8G8B8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void A8R8G8B8::readColor(gl::ColorF *dst, const A8R8G8B8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void A8R8G8B8::writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void A8R8G8B8::writeColor(A8R8G8B8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void A8R8G8B8::average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void R8G8B8A8::readColor(gl::ColorUI *dst, const R8G8B8A8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R8G8B8A8::readColor(gl::ColorF *dst, const R8G8B8A8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8::writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R8G8B8A8::writeColor(R8G8B8A8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R8G8B8A8::average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void R8G8B8A8SRGB::readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8SRGB::writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R8G8B8A8SRGB::average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2) +{ + dst->R = + gl::linearToSRGB(static_cast((static_cast(gl::sRGBToLinear(src1->R)) + + static_cast(gl::sRGBToLinear(src2->R))) >> + 1)); + dst->G = + gl::linearToSRGB(static_cast((static_cast(gl::sRGBToLinear(src1->G)) + + static_cast(gl::sRGBToLinear(src2->G))) >> + 1)); + dst->B = + gl::linearToSRGB(static_cast((static_cast(gl::sRGBToLinear(src1->B)) + + static_cast(gl::sRGBToLinear(src2->B))) >> + 1)); + dst->A = static_cast( + (static_cast(src1->A) + static_cast(src2->A)) >> 1); +} + +void B8G8R8A8::readColor(gl::ColorUI *dst, const B8G8R8A8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void B8G8R8A8::readColor(gl::ColorF *dst, const B8G8R8A8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void B8G8R8A8::writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void B8G8R8A8::writeColor(B8G8R8A8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void B8G8R8A8::average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); +} + +void B8G8R8X8::readColor(gl::ColorUI *dst, const B8G8R8X8 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void B8G8R8X8::readColor(gl::ColorF *dst, const B8G8R8X8 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void B8G8R8X8::writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->X = 255; +} + +void B8G8R8X8::writeColor(B8G8R8X8 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->X = 255; +} + +void B8G8R8X8::average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) +{ + *(uint32_t *)dst = (((*(uint32_t *)src1 ^ *(uint32_t *)src2) & 0xFEFEFEFE) >> 1) + + (*(uint32_t *)src1 & *(uint32_t *)src2); + dst->X = 255; +} + +void A1R5G5B5::readColor(gl::ColorF *dst, const A1R5G5B5 *src) +{ + 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)); +} + +void A1R5G5B5::writeColor(A1R5G5B5 *dst, const gl::ColorF *src) +{ + dst->ARGB = gl::shiftData<1, 15>(gl::floatToNormalized<1, uint16_t>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, uint16_t>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(src->blue)); +} + +void A1R5G5B5::average(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2) +{ + 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))); +} + +void R5G5B5A1::readColor(gl::ColorF *dst, const R5G5B5A1 *src) +{ + 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)); +} + +void R5G5B5A1::writeColor(R5G5B5A1 *dst, const gl::ColorF *src) +{ + dst->RGBA = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(src->red)) | + gl::shiftData<5, 6>(gl::floatToNormalized<5, uint16_t>(src->green)) | + gl::shiftData<5, 1>(gl::floatToNormalized<5, uint16_t>(src->blue)) | + gl::shiftData<1, 0>(gl::floatToNormalized<1, uint16_t>(src->alpha)); +} + +void R5G5B5A1::average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) +{ + 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))); +} + +void R4G4B4A4::readColor(gl::ColorF *dst, const R4G4B4A4 *src) +{ + 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)); +} + +void R4G4B4A4::writeColor(R4G4B4A4 *dst, const gl::ColorF *src) +{ + dst->RGBA = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(src->red)) | + gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(src->green)) | + gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(src->blue)) | + gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(src->alpha)); +} + +void R4G4B4A4::average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) +{ + 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))); +} + +void A4R4G4B4::readColor(gl::ColorF *dst, const A4R4G4B4 *src) +{ + 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)); +} + +void A4R4G4B4::writeColor(A4R4G4B4 *dst, const gl::ColorF *src) +{ + dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(src->alpha)) | + gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(src->red)) | + gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(src->green)) | + gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(src->blue)); +} + +void A4R4G4B4::average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) +{ + 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))); +} + +void R16::readColor(gl::ColorUI *dst, const R16 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R16::readColor(gl::ColorF *dst, const R16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16::writeColor(R16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); +} + +void R16::writeColor(R16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R16::average(R16 *dst, const R16 *src1, const R16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R16G16::readColor(gl::ColorUI *dst, const R16G16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R16G16::readColor(gl::ColorF *dst, const R16G16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16::writeColor(R16G16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R16G16::writeColor(R16G16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R16G16::average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R16G16B16::readColor(gl::ColorUI *dst, const R16G16B16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R16G16B16::readColor(gl::ColorF *dst, const R16G16B16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16::writeColor(R16G16B16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R16G16B16::writeColor(R16G16B16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R16G16B16::average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *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); +} + +void R16G16B16A16::readColor(gl::ColorUI *dst, const R16G16B16A16 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R16G16B16A16::readColor(gl::ColorF *dst, const R16G16B16A16 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R16G16B16A16::writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R16G16B16A16::writeColor(R16G16B16A16 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R16G16B16A16::average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *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); +} + +void R32::readColor(gl::ColorUI *dst, const R32 *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R32::readColor(gl::ColorF *dst, const R32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32::writeColor(R32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); +} + +void R32::writeColor(R32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R32::average(R32 *dst, const R32 *src1, const R32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R32G32::readColor(gl::ColorUI *dst, const R32G32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R32G32::readColor(gl::ColorF *dst, const R32G32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32::writeColor(R32G32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R32G32::writeColor(R32G32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R32G32::average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32::readColor(gl::ColorUI *dst, const R32G32B32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R32G32B32::readColor(gl::ColorF *dst, const R32G32B32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R32G32B32::writeColor(R32G32B32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R32G32B32::writeColor(R32G32B32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R32G32B32::average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *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); +} + +void R32G32B32A32::readColor(gl::ColorUI *dst, const R32G32B32A32 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32::readColor(gl::ColorF *dst, const R32G32B32A32 *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R32G32B32A32::writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R32G32B32A32::writeColor(R32G32B32A32 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R32G32B32A32::average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *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); +} + +void R8S::readColor(gl::ColorI *dst, const R8S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R8S::readColor(gl::ColorF *dst, const R8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8S::writeColor(R8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); +} + +void R8S::writeColor(R8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R8S::average(R8S *dst, const R8S *src1, const R8S *src2) +{ + dst->R = static_cast(gl::average(src1->R, src2->R)); +} + +void R8G8S::readColor(gl::ColorI *dst, const R8G8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R8G8S::readColor(gl::ColorF *dst, const R8G8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R8G8S::writeColor(R8G8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R8G8S::writeColor(R8G8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R8G8S::average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) +{ + dst->R = static_cast(gl::average(src1->R, src2->R)); + dst->G = static_cast(gl::average(src1->G, src2->G)); +} + +void R8G8B8S::readColor(gl::ColorI *dst, const R8G8B8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R8G8B8S::readColor(gl::ColorF *dst, const R8G8B8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R8G8B8S::writeColor(R8G8B8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R8G8B8S::writeColor(R8G8B8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R8G8B8S::average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) +{ + 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)); +} + +void R8G8B8A8S::readColor(gl::ColorI *dst, const R8G8B8A8S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R8G8B8A8S::readColor(gl::ColorF *dst, const R8G8B8A8S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R8G8B8A8S::writeColor(R8G8B8A8S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R8G8B8A8S::writeColor(R8G8B8A8S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R8G8B8A8S::average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) +{ + 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)); +} + +void R16S::readColor(gl::ColorI *dst, const R16S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R16S::readColor(gl::ColorF *dst, const R16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16S::writeColor(R16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); +} + +void R16S::writeColor(R16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R16S::average(R16S *dst, const R16S *src1, const R16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R16G16S::readColor(gl::ColorI *dst, const R16G16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R16G16S::readColor(gl::ColorF *dst, const R16G16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16S::writeColor(R16G16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R16G16S::writeColor(R16G16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R16G16S::average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R16G16B16S::readColor(gl::ColorI *dst, const R16G16B16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R16G16B16S::readColor(gl::ColorF *dst, const R16G16B16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16S::writeColor(R16G16B16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R16G16B16S::writeColor(R16G16B16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R16G16B16S::average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *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); +} + +void R16G16B16A16S::readColor(gl::ColorI *dst, const R16G16B16A16S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R16G16B16A16S::readColor(gl::ColorF *dst, const R16G16B16A16S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R16G16B16A16S::writeColor(R16G16B16A16S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R16G16B16A16S::writeColor(R16G16B16A16S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R16G16B16A16S::average(R16G16B16A16S *dst, + const R16G16B16A16S *src1, + const R16G16B16A16S *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); +} + +void R32S::readColor(gl::ColorI *dst, const R32S *src) +{ + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; +} + +void R32S::readColor(gl::ColorF *dst, const R32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32S::writeColor(R32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); +} + +void R32S::writeColor(R32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); +} + +void R32S::average(R32S *dst, const R32S *src1, const R32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void R32G32S::readColor(gl::ColorI *dst, const R32G32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; +} + +void R32G32S::readColor(gl::ColorF *dst, const R32G32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32S::writeColor(R32G32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); +} + +void R32G32S::writeColor(R32G32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); +} + +void R32G32S::average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32S::readColor(gl::ColorI *dst, const R32G32B32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; +} + +void R32G32B32S::readColor(gl::ColorF *dst, const R32G32B32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; +} + +void R32G32B32S::writeColor(R32G32B32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); +} + +void R32G32B32S::writeColor(R32G32B32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); +} + +void R32G32B32S::average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *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); +} + +void R32G32B32A32S::readColor(gl::ColorI *dst, const R32G32B32A32S *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32S::readColor(gl::ColorF *dst, const R32G32B32A32S *src) +{ + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); +} + +void R32G32B32A32S::writeColor(R32G32B32A32S *dst, const gl::ColorI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R32G32B32A32S::writeColor(R32G32B32A32S *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); +} + +void R32G32B32A32S::average(R32G32B32A32S *dst, + const R32G32B32A32S *src1, + const R32G32B32A32S *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); +} + +void A16B16G16R16F::readColor(gl::ColorF *dst, const A16B16G16R16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); +} + +void A16B16G16R16F::writeColor(A16B16G16R16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void A16B16G16R16F::average(A16B16G16R16F *dst, + const A16B16G16R16F *src1, + const A16B16G16R16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16G16B16A16F::readColor(gl::ColorF *dst, const R16G16B16A16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); +} + +void R16G16B16A16F::writeColor(R16G16B16A16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void R16G16B16A16F::average(R16G16B16A16F *dst, + const R16G16B16A16F *src1, + const R16G16B16A16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16F::readColor(gl::ColorF *dst, const R16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16F::writeColor(R16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); +} + +void R16F::average(R16F *dst, const R16F *src1, const R16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); +} + +void A16F::readColor(gl::ColorF *dst, const A16F *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::float16ToFloat32(src->A); +} + +void A16F::writeColor(A16F *dst, const gl::ColorF *src) +{ + dst->A = gl::float32ToFloat16(src->alpha); +} + +void A16F::average(A16F *dst, const A16F *src1, const A16F *src2) +{ + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void L16F::readColor(gl::ColorF *dst, const L16F *src) +{ + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; +} + +void L16F::writeColor(L16F *dst, const gl::ColorF *src) +{ + dst->L = gl::float32ToFloat16(src->red); +} + +void L16F::average(L16F *dst, const L16F *src1, const L16F *src2) +{ + dst->L = gl::averageHalfFloat(src1->L, src2->L); +} + +void L16A16F::readColor(gl::ColorF *dst, const L16A16F *src) +{ + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::float16ToFloat32(src->A); +} + +void L16A16F::writeColor(L16A16F *dst, const gl::ColorF *src) +{ + dst->L = gl::float32ToFloat16(src->red); + dst->A = gl::float32ToFloat16(src->alpha); +} + +void L16A16F::average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) +{ + dst->L = gl::averageHalfFloat(src1->L, src2->L); + dst->A = gl::averageHalfFloat(src1->A, src2->A); +} + +void R16G16F::readColor(gl::ColorF *dst, const R16G16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R16G16F::writeColor(R16G16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); +} + +void R16G16F::average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); +} + +void R16G16B16F::readColor(gl::ColorF *dst, const R16G16B16F *src) +{ + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = 1.0f; +} + +void R16G16B16F::writeColor(R16G16B16F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); +} + +void R16G16B16F::average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) +{ + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); +} + +void A32B32G32R32F::readColor(gl::ColorF *dst, const A32B32G32R32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void A32B32G32R32F::writeColor(A32B32G32R32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; +} + +void A32B32G32R32F::average(A32B32G32R32F *dst, + const A32B32G32R32F *src1, + const A32B32G32R32F *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); +} + +void R32G32B32A32F::readColor(gl::ColorF *dst, const R32G32B32A32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R32G32B32A32F::writeColor(R32G32B32A32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; +} + +void R32G32B32A32F::average(R32G32B32A32F *dst, + const R32G32B32A32F *src1, + const R32G32B32A32F *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); +} + +void R32F::readColor(gl::ColorF *dst, const R32F *src) +{ + dst->red = src->R; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32F::writeColor(R32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; +} + +void R32F::average(R32F *dst, const R32F *src1, const R32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); +} + +void A32F::readColor(gl::ColorF *dst, const A32F *src) +{ + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = src->A; +} + +void A32F::writeColor(A32F *dst, const gl::ColorF *src) +{ + dst->A = src->alpha; +} + +void A32F::average(A32F *dst, const A32F *src1, const A32F *src2) +{ + dst->A = gl::average(src1->A, src2->A); +} + +void L32F::readColor(gl::ColorF *dst, const L32F *src) +{ + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = 1.0f; +} + +void L32F::writeColor(L32F *dst, const gl::ColorF *src) +{ + dst->L = src->red; +} + +void L32F::average(L32F *dst, const L32F *src1, const L32F *src2) +{ + dst->L = gl::average(src1->L, src2->L); +} + +void L32A32F::readColor(gl::ColorF *dst, const L32A32F *src) +{ + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = src->A; +} + +void L32A32F::writeColor(L32A32F *dst, const gl::ColorF *src) +{ + dst->L = src->red; + dst->A = src->alpha; +} + +void L32A32F::average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) +{ + dst->L = gl::average(src1->L, src2->L); + dst->A = gl::average(src1->A, src2->A); +} + +void R32G32F::readColor(gl::ColorF *dst, const R32G32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = 0.0f; + dst->alpha = 1.0f; +} + +void R32G32F::writeColor(R32G32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; +} + +void R32G32F::average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) +{ + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); +} + +void R32G32B32F::readColor(gl::ColorF *dst, const R32G32B32F *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1.0f; +} + +void R32G32B32F::writeColor(R32G32B32F *dst, const gl::ColorF *src) +{ + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; +} + +void R32G32B32F::average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *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); +} + +void R10G10B10A2::readColor(gl::ColorUI *dst, const R10G10B10A2 *src) +{ + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; +} + +void R10G10B10A2::readColor(gl::ColorF *dst, const R10G10B10A2 *src) +{ + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat<2>(src->A); +} + +void R10G10B10A2::writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) +{ + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); +} + +void R10G10B10A2::writeColor(R10G10B10A2 *dst, const gl::ColorF *src) +{ + dst->R = gl::floatToNormalized<10, uint32_t>(src->red); + dst->G = gl::floatToNormalized<10, uint32_t>(src->green); + dst->B = gl::floatToNormalized<10, uint32_t>(src->blue); + dst->A = gl::floatToNormalized<2, uint32_t>(src->alpha); +} + +void R10G10B10A2::average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *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); +} + +void R9G9B9E5::readColor(gl::ColorF *dst, const R9G9B9E5 *src) +{ + gl::convert999E5toRGBFloats(gl::bitCast(*src), &dst->red, &dst->green, &dst->blue); + dst->alpha = 1.0f; +} + +void R9G9B9E5::writeColor(R9G9B9E5 *dst, const gl::ColorF *src) +{ + *reinterpret_cast(dst) = + gl::convertRGBFloatsTo999E5(src->red, src->green, src->blue); +} + +void R9G9B9E5::average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) +{ + float r1, g1, b1; + gl::convert999E5toRGBFloats(*reinterpret_cast(src1), &r1, &g1, &b1); + + float r2, g2, b2; + gl::convert999E5toRGBFloats(*reinterpret_cast(src2), &r2, &g2, &b2); + + *reinterpret_cast(dst) = + gl::convertRGBFloatsTo999E5(gl::average(r1, r2), gl::average(g1, g2), gl::average(b1, b2)); +} + +void R11G11B10F::readColor(gl::ColorF *dst, const R11G11B10F *src) +{ + dst->red = gl::float11ToFloat32(src->R); + dst->green = gl::float11ToFloat32(src->G); + dst->blue = gl::float10ToFloat32(src->B); + dst->alpha = 1.0f; +} + +void R11G11B10F::writeColor(R11G11B10F *dst, const gl::ColorF *src) +{ + dst->R = gl::float32ToFloat11(src->red); + dst->G = gl::float32ToFloat11(src->green); + dst->B = gl::float32ToFloat10(src->blue); +} + +void R11G11B10F::average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) +{ + dst->R = gl::averageFloat11(src1->R, src2->R); + dst->G = gl::averageFloat11(src1->G, src2->G); + dst->B = gl::averageFloat10(src1->B, src2->B); +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/imageformats.h b/src/3rdparty/angle/src/image_util/imageformats.h new file mode 100644 index 0000000000..65644cd8d9 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/imageformats.h @@ -0,0 +1,700 @@ +// +// 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. +// + +// imageformats.h: Defines image format types with functions for mip generation +// and copying. + +#ifndef IMAGEUTIL_IMAGEFORMATS_H_ +#define IMAGEUTIL_IMAGEFORMATS_H_ + +#include "common/Color.h" + +#include + +namespace angle +{ + +// Several structures share functionality for reading, writing or mipmapping but the layout +// must match the texture format which the structure represents. If collapsing or typedefing +// structs in this header, make sure the functionality and memory layout is exactly the same. + +struct L8 +{ + uint8_t L; + + static void readColor(gl::ColorF *dst, const L8 *src); + static void writeColor(L8 *dst, const gl::ColorF *src); + static void average(L8 *dst, const L8 *src1, const L8 *src2); +}; + +struct R8 +{ + uint8_t R; + + static void readColor(gl::ColorF *dst, const R8 *src); + static void readColor(gl::ColorUI *dst, const R8 *src); + static void writeColor(R8 *dst, const gl::ColorF *src); + static void writeColor(R8 *dst, const gl::ColorUI *src); + static void average(R8 *dst, const R8 *src1, const R8 *src2); +}; + +struct A8 +{ + uint8_t A; + + static void readColor(gl::ColorF *dst, const A8 *src); + static void writeColor(A8 *dst, const gl::ColorF *src); + static void average(A8 *dst, const A8 *src1, const A8 *src2); +}; + +struct L8A8 +{ + uint8_t L; + uint8_t A; + + static void readColor(gl::ColorF *dst, const L8A8 *src); + static void writeColor(L8A8 *dst, const gl::ColorF *src); + static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2); +}; + +struct A8L8 +{ + uint8_t A; + uint8_t L; + + static void readColor(gl::ColorF *dst, const A8L8 *src); + static void writeColor(A8L8 *dst, const gl::ColorF *src); + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2); +}; + +struct R8G8 +{ + uint8_t R; + uint8_t G; + + static void readColor(gl::ColorF *dst, const R8G8 *src); + static void readColor(gl::ColorUI *dst, const R8G8 *src); + static void writeColor(R8G8 *dst, const gl::ColorF *src); + static void writeColor(R8G8 *dst, const gl::ColorUI *src); + static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2); +}; + +struct R8G8B8 +{ + uint8_t R; + uint8_t G; + uint8_t B; + + static void readColor(gl::ColorF *dst, const R8G8B8 *src); + static void readColor(gl::ColorUI *dst, const R8G8B8 *src); + static void writeColor(R8G8B8 *dst, const gl::ColorF *src); + static void writeColor(R8G8B8 *dst, const gl::ColorUI *src); + static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2); +}; + +struct B8G8R8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + + static void readColor(gl::ColorF *dst, const B8G8R8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8 *src); + static void writeColor(B8G8R8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8 *dst, const gl::ColorUI *src); + static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2); +}; + +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" + uint16_t RGB; + + static void readColor(gl::ColorF *dst, const R5G6B5 *src); + static void writeColor(R5G6B5 *dst, const gl::ColorF *src); + static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2); +}; + +struct B5G6R5 +{ + uint16_t BGR; + + static void readColor(gl::ColorF *dst, const B5G6R5 *src); + static void writeColor(B5G6R5 *dst, const gl::ColorF *src); + static void average(B5G6R5 *dst, const B5G6R5 *src1, const B5G6R5 *src2); +}; + +struct A8R8G8B8 +{ + uint8_t A; + uint8_t R; + uint8_t G; + uint8_t B; + + static void readColor(gl::ColorF *dst, const A8R8G8B8 *src); + static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src); + static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src); + static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src); + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2); +}; + +struct R8G8B8A8 +{ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8 *src); + static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src); + static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src); + static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src); + static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2); +}; + +struct R8G8B8A8SRGB +{ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src); + static void writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src); + static void average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2); +}; + +struct B8G8R8A8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + uint8_t A; + + static void readColor(gl::ColorF *dst, const B8G8R8A8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src); + static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src); + static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2); +}; + +struct B8G8R8X8 +{ + uint8_t B; + uint8_t G; + uint8_t R; + uint8_t X; + + static void readColor(gl::ColorF *dst, const B8G8R8X8 *src); + static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src); + static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src); + static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src); + static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2); +}; + +struct A1R5G5B5 +{ + uint16_t ARGB; + + static void readColor(gl::ColorF *dst, const A1R5G5B5 *src); + static void writeColor(A1R5G5B5 *dst, const gl::ColorF *src); + static void average(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2); +}; + +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" + uint16_t RGBA; + + static void readColor(gl::ColorF *dst, const R5G5B5A1 *src); + static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src); + static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2); +}; + +struct R4G4B4A4 +{ + // 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" + uint16_t RGBA; + + static void readColor(gl::ColorF *dst, const R4G4B4A4 *src); + static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src); + static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2); +}; + +struct A4R4G4B4 +{ + uint16_t ARGB; + + static void readColor(gl::ColorF *dst, const A4R4G4B4 *src); + static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src); + static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2); +}; + +struct R16 +{ + uint16_t R; + + static void readColor(gl::ColorF *dst, const R16 *src); + static void readColor(gl::ColorUI *dst, const R16 *src); + static void writeColor(R16 *dst, const gl::ColorF *src); + static void writeColor(R16 *dst, const gl::ColorUI *src); + static void average(R16 *dst, const R16 *src1, const R16 *src2); +}; + +struct R16G16 +{ + uint16_t R; + uint16_t G; + + static void readColor(gl::ColorF *dst, const R16G16 *src); + static void readColor(gl::ColorUI *dst, const R16G16 *src); + static void writeColor(R16G16 *dst, const gl::ColorF *src); + static void writeColor(R16G16 *dst, const gl::ColorUI *src); + static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2); +}; + +struct R16G16B16 +{ + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16 *src); + static void readColor(gl::ColorUI *dst, const R16G16B16 *src); + static void writeColor(R16G16B16 *dst, const gl::ColorF *src); + static void writeColor(R16G16B16 *dst, const gl::ColorUI *src); + static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2); +}; + +struct R16G16B16A16 +{ + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16 *src); + static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src); + static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src); + static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src); + static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2); +}; + +struct R32 +{ + uint32_t R; + + static void readColor(gl::ColorF *dst, const R32 *src); + static void readColor(gl::ColorUI *dst, const R32 *src); + static void writeColor(R32 *dst, const gl::ColorF *src); + static void writeColor(R32 *dst, const gl::ColorUI *src); + static void average(R32 *dst, const R32 *src1, const R32 *src2); +}; + +struct R32G32 +{ + uint32_t R; + uint32_t G; + + static void readColor(gl::ColorF *dst, const R32G32 *src); + static void readColor(gl::ColorUI *dst, const R32G32 *src); + static void writeColor(R32G32 *dst, const gl::ColorF *src); + static void writeColor(R32G32 *dst, const gl::ColorUI *src); + static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2); +}; + +struct R32G32B32 +{ + uint32_t R; + uint32_t G; + uint32_t B; + + static void readColor(gl::ColorF *dst, const R32G32B32 *src); + static void readColor(gl::ColorUI *dst, const R32G32B32 *src); + static void writeColor(R32G32B32 *dst, const gl::ColorF *src); + static void writeColor(R32G32B32 *dst, const gl::ColorUI *src); + static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2); +}; + +struct R32G32B32A32 +{ + uint32_t R; + uint32_t G; + uint32_t B; + uint32_t A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32 *src); + static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src); + static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src); + static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src); + static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2); +}; + +struct R8S +{ + int8_t R; + + static void readColor(gl::ColorF *dst, const R8S *src); + static void readColor(gl::ColorI *dst, const R8S *src); + static void writeColor(R8S *dst, const gl::ColorF *src); + static void writeColor(R8S *dst, const gl::ColorI *src); + static void average(R8S *dst, const R8S *src1, const R8S *src2); +}; + +struct R8G8S +{ + int8_t R; + int8_t G; + + static void readColor(gl::ColorF *dst, const R8G8S *src); + static void readColor(gl::ColorI *dst, const R8G8S *src); + static void writeColor(R8G8S *dst, const gl::ColorF *src); + static void writeColor(R8G8S *dst, const gl::ColorI *src); + static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2); +}; + +struct R8G8B8S +{ + int8_t R; + int8_t G; + int8_t B; + + static void readColor(gl::ColorF *dst, const R8G8B8S *src); + static void readColor(gl::ColorI *dst, const R8G8B8S *src); + static void writeColor(R8G8B8S *dst, const gl::ColorF *src); + static void writeColor(R8G8B8S *dst, const gl::ColorI *src); + static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2); +}; + +struct R8G8B8A8S +{ + int8_t R; + int8_t G; + int8_t B; + int8_t A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8S *src); + static void readColor(gl::ColorI *dst, const R8G8B8A8S *src); + static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src); + static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src); + static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2); +}; + +struct R16S +{ + int16_t R; + + static void readColor(gl::ColorF *dst, const R16S *src); + static void readColor(gl::ColorI *dst, const R16S *src); + static void writeColor(R16S *dst, const gl::ColorF *src); + static void writeColor(R16S *dst, const gl::ColorI *src); + static void average(R16S *dst, const R16S *src1, const R16S *src2); +}; + +struct R16G16S +{ + int16_t R; + int16_t G; + + static void readColor(gl::ColorF *dst, const R16G16S *src); + static void readColor(gl::ColorI *dst, const R16G16S *src); + static void writeColor(R16G16S *dst, const gl::ColorF *src); + static void writeColor(R16G16S *dst, const gl::ColorI *src); + static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2); +}; + +struct R16G16B16S +{ + int16_t R; + int16_t G; + int16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16S *src); + static void readColor(gl::ColorI *dst, const R16G16B16S *src); + static void writeColor(R16G16B16S *dst, const gl::ColorF *src); + static void writeColor(R16G16B16S *dst, const gl::ColorI *src); + static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2); +}; + +struct R16G16B16A16S +{ + int16_t R; + int16_t G; + int16_t B; + int16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16S *src); + static void readColor(gl::ColorI *dst, const R16G16B16A16S *src); + static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src); + static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src); + static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2); +}; + +struct R32S +{ + int32_t R; + + static void readColor(gl::ColorF *dst, const R32S *src); + static void readColor(gl::ColorI *dst, const R32S *src); + static void writeColor(R32S *dst, const gl::ColorF *src); + static void writeColor(R32S *dst, const gl::ColorI *src); + static void average(R32S *dst, const R32S *src1, const R32S *src2); +}; + +struct R32G32S +{ + int32_t R; + int32_t G; + + static void readColor(gl::ColorF *dst, const R32G32S *src); + static void readColor(gl::ColorI *dst, const R32G32S *src); + static void writeColor(R32G32S *dst, const gl::ColorF *src); + static void writeColor(R32G32S *dst, const gl::ColorI *src); + static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2); +}; + +struct R32G32B32S +{ + int32_t R; + int32_t G; + int32_t B; + + static void readColor(gl::ColorF *dst, const R32G32B32S *src); + static void readColor(gl::ColorI *dst, const R32G32B32S *src); + static void writeColor(R32G32B32S *dst, const gl::ColorF *src); + static void writeColor(R32G32B32S *dst, const gl::ColorI *src); + static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2); +}; + +struct R32G32B32A32S +{ + int32_t R; + int32_t G; + int32_t B; + int32_t A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32S *src); + static void readColor(gl::ColorI *dst, const R32G32B32A32S *src); + static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src); + static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src); + static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2); +}; + +struct A16B16G16R16F +{ + uint16_t A; + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const A16B16G16R16F *src); + static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src); + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2); +}; + +struct R16G16B16A16F +{ + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16F *src); + static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src); + static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2); +}; + +struct R16F +{ + uint16_t R; + + static void readColor(gl::ColorF *dst, const R16F *src); + static void writeColor(R16F *dst, const gl::ColorF *src); + static void average(R16F *dst, const R16F *src1, const R16F *src2); +}; + +struct A16F +{ + uint16_t A; + + static void readColor(gl::ColorF *dst, const A16F *src); + static void writeColor(A16F *dst, const gl::ColorF *src); + static void average(A16F *dst, const A16F *src1, const A16F *src2); +}; + +struct L16F +{ + uint16_t L; + + static void readColor(gl::ColorF *dst, const L16F *src); + static void writeColor(L16F *dst, const gl::ColorF *src); + static void average(L16F *dst, const L16F *src1, const L16F *src2); +}; + +struct L16A16F +{ + uint16_t L; + uint16_t A; + + static void readColor(gl::ColorF *dst, const L16A16F *src); + static void writeColor(L16A16F *dst, const gl::ColorF *src); + static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2); +}; + +struct R16G16F +{ + uint16_t R; + uint16_t G; + + static void readColor(gl::ColorF *dst, const R16G16F *src); + static void writeColor(R16G16F *dst, const gl::ColorF *src); + static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2); +}; + +struct R16G16B16F +{ + uint16_t R; + uint16_t G; + uint16_t B; + + static void readColor(gl::ColorF *dst, const R16G16B16F *src); + static void writeColor(R16G16B16F *dst, const gl::ColorF *src); + static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2); +}; + +struct A32B32G32R32F +{ + float A; + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const A32B32G32R32F *src); + static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src); + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2); +}; + +struct R32G32B32A32F +{ + float R; + float G; + float B; + float A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32F *src); + static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src); + static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2); +}; + +struct R32F +{ + float R; + + static void readColor(gl::ColorF *dst, const R32F *src); + static void writeColor(R32F *dst, const gl::ColorF *src); + static void average(R32F *dst, const R32F *src1, const R32F *src2); +}; + +struct A32F +{ + float A; + + static void readColor(gl::ColorF *dst, const A32F *src); + static void writeColor(A32F *dst, const gl::ColorF *src); + static void average(A32F *dst, const A32F *src1, const A32F *src2); +}; + +struct L32F +{ + float L; + + static void readColor(gl::ColorF *dst, const L32F *src); + static void writeColor(L32F *dst, const gl::ColorF *src); + static void average(L32F *dst, const L32F *src1, const L32F *src2); +}; + +struct L32A32F +{ + float L; + float A; + + static void readColor(gl::ColorF *dst, const L32A32F *src); + static void writeColor(L32A32F *dst, const gl::ColorF *src); + static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2); +}; + +struct R32G32F +{ + float R; + float G; + + static void readColor(gl::ColorF *dst, const R32G32F *src); + static void writeColor(R32G32F *dst, const gl::ColorF *src); + static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2); +}; + +struct R32G32B32F +{ + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const R32G32B32F *src); + static void writeColor(R32G32B32F *dst, const gl::ColorF *src); + static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2); +}; + +struct R10G10B10A2 +{ + uint32_t R : 10; + uint32_t G : 10; + uint32_t B : 10; + uint32_t A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2 *src); + static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src); + static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src); + static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src); + static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2); +}; +static_assert(sizeof(R10G10B10A2) == 4, "R10G10B10A2 struct not 32-bits."); + +struct R9G9B9E5 +{ + uint32_t R : 9; + uint32_t G : 9; + uint32_t B : 9; + uint32_t E : 5; + + static void readColor(gl::ColorF *dst, const R9G9B9E5 *src); + static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src); + static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2); +}; +static_assert(sizeof(R9G9B9E5) == 4, "R9G9B9E5 struct not 32-bits."); + +struct R11G11B10F +{ + uint32_t R : 11; + uint32_t G : 11; + uint32_t B : 10; + + static void readColor(gl::ColorF *dst, const R11G11B10F *src); + static void writeColor(R11G11B10F *dst, const gl::ColorF *src); + static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2); +}; +static_assert(sizeof(R11G11B10F) == 4, "R11G11B10F struct not 32-bits."); + +} // namespace angle + +#endif // IMAGEUTIL_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/image_util/loadimage.cpp b/src/3rdparty/angle/src/image_util/loadimage.cpp new file mode 100644 index 0000000000..56ad3b32e3 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/loadimage.cpp @@ -0,0 +1,1323 @@ +// +// 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. +// + +// angle_loadimage.cpp: Defines image loading functions. + +#include "image_util/loadimage.h" + +#include "common/mathutil.h" +#include "common/platform.h" +#include "image_util/imageformats.h" + +namespace angle +{ + +void LoadA8ToRGBA8(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) +{ +#if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, + outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = + _mm_loadl_epi64(reinterpret_cast(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } + } + + return; + } +#endif + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } + } +} + +void LoadA8ToBGRA8(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) +{ + // Same as loading to RGBA + LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadA32FToRGBA32F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0.0f; + dest[4 * x + 1] = 0.0f; + dest[4 * x + 2] = 0.0f; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadA16FToRGBA16F(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadL8ToRGBA8(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t sourceVal = source[x]; + dest[4 * x + 0] = sourceVal; + dest[4 * x + 1] = sourceVal; + dest[4 * x + 2] = sourceVal; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadL8ToBGRA8(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) +{ + // Same as loading to RGBA + LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadL32FToRGBA32F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } + } +} + +void LoadL16FToRGBA16F(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = gl::Float16One; + } + } + } +} + +void LoadLA8ToRGBA8(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA8ToBGRA8(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) +{ + // Same as loading to RGBA + LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, + outputRowPitch, outputDepthPitch); +} + +void LoadLA32FToRGBA32F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadLA16FToRGBA16F(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2 * x + 0]; + dest[4 * x + 1] = source[2 * x + 0]; + dest[4 * x + 2] = source[2 * x + 0]; + dest[4 * x + 3] = source[2 * x + 1]; + } + } + } +} + +void LoadRGB8ToBGR565(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t r8 = source[x * 3 + 0]; + uint8_t g8 = source[x * 3 + 1]; + uint8_t b8 = source[x * 3 + 2]; + auto r5 = static_cast(r8 >> 3); + auto g6 = static_cast(g8 >> 2); + auto b5 = static_cast(b8 >> 3); + dest[x] = (r5 << 11) | (g6 << 5) | b5; + } + } + } +} + +void LoadRGB565ToBGR565(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + // The GL type RGB is packed with with red in the MSB, while the D3D11 type BGR + // is packed with red in the LSB + auto rgb = source[x]; + uint16_t r5 = gl::getShiftedData<5, 11>(rgb); + uint16_t g6 = gl::getShiftedData<6, 5>(rgb); + uint16_t b5 = gl::getShiftedData<5, 0>(rgb); + dest[x] = (r5 << 11) | (g6 << 5) | b5; + } + } + } +} + +void LoadRGB8ToBGRX8(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRG8ToBGRX8(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = source[x * 2 + 1]; + dest[4 * x + 2] = source[x * 2 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR8ToBGRX8(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 uint8_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = 0x00; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToBGRA8(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + 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; + } + } + } +} + +void LoadR5G6B5ToRGBA8(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + 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; + } + } + } +} + +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) +{ +#if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, + outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = + _mm_loadu_si128(reinterpret_cast(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16( + _mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), + _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i *>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } + + return; + } +#endif + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +} + +void LoadRGBA8ToBGRA4(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r4 = static_cast((rgba8 & 0x000000FF) >> 4); + auto g4 = static_cast((rgba8 & 0x0000FF00) >> 12); + auto b4 = static_cast((rgba8 & 0x00FF0000) >> 20); + auto a4 = static_cast((rgba8 & 0xFF000000) >> 28); + dest[x] = (a4 << 12) | (r4 << 8) | (g4 << 4) | b4; + } + } + } +} + +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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::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) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + 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)); + } + } + } +} + +void LoadRGBA4ToRGBA8(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + 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)); + } + } + } +} + +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) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + 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 LoadRGBA8ToBGR5A1(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba8 = source[x]; + auto r5 = static_cast((rgba8 & 0x000000FF) >> 3); + auto g5 = static_cast((rgba8 & 0x0000FF00) >> 11); + auto b5 = static_cast((rgba8 & 0x00FF0000) >> 19); + auto a1 = static_cast((rgba8 & 0xFF000000) >> 31); + dest[x] = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5; + } + } + } +} + +void LoadRGB10A2ToBGR5A1(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 R10G10B10A2 *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + R10G10B10A2 rgb10a2 = source[x]; + + uint16_t r5 = static_cast(rgb10a2.R >> 5u); + uint16_t g5 = static_cast(rgb10a2.G >> 5u); + uint16_t b5 = static_cast(rgb10a2.B >> 5u); + uint16_t a1 = static_cast(rgb10a2.A >> 1u); + + dest[x] = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5; + } + } + } +} + +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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = ANGLE_ROTR16(source[x], 1); + } + } + } +} + +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) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + 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); + } + } + } +} + +void LoadRGB5A1ToRGBA8(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + 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) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + 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); + } + } + } +} + +void LoadRGB10A2ToRGBA8(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + 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); + } + } + } +} + +void LoadRGB16FToRGB9E5(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), + gl::float16ToFloat32(source[x * 3 + 1]), + gl::float16ToFloat32(source[x * 3 + 2])); + } + } + } +} + +void LoadRGB32FToRGB9E5(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], + source[x * 3 + 2]); + } + } + } +} + +void LoadRGB16FToRG11B10F(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 = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | + (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | + (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); + } + } + } +} + +void LoadRGB32FToRG11B10F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | + (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | + (gl::float32ToFloat10(source[x * 3 + 2]) << 22); + } + } + } +} + +void LoadG8R24ToR24G8(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = source[x] >> 8; + uint8_t s = source[x] & 0xFF; + dest[x] = d | (s << 24); + } + } + } +} + +void LoadD32FToD32F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::clamp01(source[x]); + } + } + } +} + +void LoadD32FS8X24ToD32FS8X24(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 float *sourceDepth = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + const uint32_t *sourceStencil = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch) + 1; + float *destDepth = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + uint32_t *destStencil = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch) + + 1; + for (size_t x = 0; x < width; x++) + { + destDepth[x * 2] = gl::clamp01(sourceDepth[x * 2]); + destStencil[x * 2] = sourceStencil[x * 2] & 0xFF000000; + } + } + } +} + +void LoadRGB32FToRGBA16F(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 float *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + dest[x * 4 + 3] = gl::Float16One; + } + } + } +} + +void LoadR32ToR16(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 16; + } + } + } +} + +void LoadR32ToR24G8(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 uint32_t *source = + priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = + priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 8; + } + } + } +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/loadimage.h b/src/3rdparty/angle/src/image_util/loadimage.h new file mode 100644 index 0000000000..3e8aac79c2 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/loadimage.h @@ -0,0 +1,658 @@ +// +// 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.h: Defines image loading functions + +#ifndef IMAGEUTIL_LOADIMAGE_H_ +#define IMAGEUTIL_LOADIMAGE_H_ + +#include +#include + +namespace angle +{ + +void LoadA8ToRGBA8(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 LoadA8ToBGRA8(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 LoadA32FToRGBA32F(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 LoadA16FToRGBA16F(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 LoadL8ToRGBA8(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 LoadL8ToBGRA8(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 LoadL32FToRGBA32F(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 LoadL16FToRGBA16F(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 LoadLA8ToRGBA8(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 LoadLA8ToBGRA8(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 LoadLA32FToRGBA32F(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 LoadLA16FToRGBA16F(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 LoadRGB8ToBGR565(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 LoadRGB565ToBGR565(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 LoadRGB8ToBGRX8(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 LoadRG8ToBGRX8(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 LoadR8ToBGRX8(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 LoadR5G6B5ToBGRA8(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 LoadR5G6B5ToRGBA8(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 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 LoadRGBA8ToBGRA4(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); + +void LoadRGBA4ToRGBA8(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 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 LoadRGBA8ToBGR5A1(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 LoadRGB10A2ToBGR5A1(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); + +void LoadRGB5A1ToRGBA8(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 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); + +void LoadRGB10A2ToRGBA8(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 LoadRGB16FToRGB9E5(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 LoadRGB32FToRGB9E5(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 LoadRGB16FToRG11B10F(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 LoadRGB32FToRG11B10F(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 LoadG8R24ToR24G8(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 LoadD32FToD32F(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 LoadD32FS8X24ToD32FS8X24(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); + +template +inline void LoadToNative(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); + +template +inline void LoadToNative3To4(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); + +template +inline void Load32FTo16F(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 LoadRGB32FToRGBA16F(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); + +template +inline void LoadCompressedToNative(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 LoadR32ToR16(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); + +template +inline void Initialize4ComponentData(size_t width, + size_t height, + size_t depth, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +void LoadR32ToR24G8(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 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 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); + +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 LoadETC2SRGB8ToBC1(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 LoadETC2RGB8A1ToBC1(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 LoadETC2SRGB8A1ToBC1(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); + +} // namespace angle + +#include "loadimage.inl" + +#endif // IMAGEUTIL_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/image_util/loadimage.inl b/src/3rdparty/angle/src/image_util/loadimage.inl new file mode 100644 index 0000000000..b8d590ca1b --- /dev/null +++ b/src/3rdparty/angle/src/image_util/loadimage.inl @@ -0,0 +1,163 @@ +// +// Copyright (c) 2014-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 "common/mathutil.h" + +#include + +namespace angle +{ + +namespace priv +{ + +template +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +template +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +} // namespace priv + +template +inline void LoadToNative(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) +{ + const size_t rowSize = width * sizeof(type) * componentCount; + const size_t layerSize = rowSize * height; + const size_t imageSize = layerSize * depth; + + if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) + { + ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); + memcpy(output, input, imageSize); + } + else if (rowSize == inputRowPitch && rowSize == outputRowPitch) + { + for (size_t z = 0; z < depth; z++) + { + const type *source = priv::OffsetDataPointer(input, 0, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer(output, 0, z, outputRowPitch, outputDepthPitch); + + memcpy(dest, source, layerSize); + } + } + else + { + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, width * sizeof(type) * componentCount); + } + } + } +} + +template +inline void LoadToNative3To4(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) +{ + const type fourthValue = gl::bitCast(fourthComponentBits); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = source[x * 3 + 0]; + dest[x * 4 + 1] = source[x * 3 + 1]; + dest[x * 4 + 2] = source[x * 3 + 2]; + dest[x * 4 + 3] = fourthValue; + } + } + } +} + +template +inline void Load32FTo16F(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) +{ + const size_t elementWidth = componentCount * width; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < elementWidth; x++) + { + dest[x] = gl::float32ToFloat16(source[x]); + } + } + } +} + +template +inline void LoadCompressedToNative(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) +{ + const size_t columns = (width + (blockWidth - 1)) / blockWidth; + const size_t rows = (height + (blockHeight - 1)) / blockHeight; + + for (size_t z = 0; z < depth; ++z) + { + for (size_t y = 0; y < rows; ++y) + { + const uint8_t *source = priv::OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, columns * blockSize); + } + } +} + +template +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + type writeValues[4] = + { + gl::bitCast(firstBits), + gl::bitCast(secondBits), + gl::bitCast(thirdBits), + gl::bitCast(fourthBits), + }; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + type *destRow = priv::OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + type* destPixel = destRow + x * 4; + + // This could potentially be optimized by generating an entire row of initialization + // data and copying row by row instead of pixel by pixel. + memcpy(destPixel, writeValues, sizeof(type) * 4); + } + } + } +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/image_util/loadimage_etc.cpp b/src/3rdparty/angle/src/image_util/loadimage_etc.cpp new file mode 100644 index 0000000000..67f73837c0 --- /dev/null +++ b/src/3rdparty/angle/src/image_util/loadimage_etc.cpp @@ -0,0 +1,1729 @@ +// +// 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 "image_util/loadimage.h" + +#include "common/mathutil.h" + +#include "image_util/imageformats.h" + +namespace angle +{ +namespace +{ + +using IntensityModifier = const int[4]; + +// Table 3.17.2 sorted according to table 3.17.3 +// clang-format off +static IntensityModifier intensityModifierDefault[] = +{ + { 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 IntensityModifier intensityModifierNonOpaque[] = +{ + { 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 + +static const int kNumPixelsInBlock = 16; + +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 IntensityModifier *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 orderingTrickBit = + ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0); + const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit]; + + 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 int *pixelIndices, + const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + const R8G8B8A8 &minColor, + const R8G8B8A8 &maxColor, + bool nonOpaquePunchThroughAlpha) 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]; + } + + ASSERT(numColors <= kNumPixelsInBlock); + + int encodedColors[kNumPixelsInBlock]; + if (nonOpaquePunchThroughAlpha) + { + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + // In non-opaque mode, 3 is for tranparent pixels. + + if (0 == subblockColors[i].A) + { + encodedColors[i] = 3; + } + else + { + const R8G8B8A8 &pixel = subblockColors[i]; + const int dot = pixel.R * direction[0] + pixel.G * direction[1] + + pixel.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: + encodedColors[i] = 0; + break; + case 1: + encodedColors[i] = 2; + break; + case 2: + default: + encodedColors[i] = 1; + break; + } + } + } + } + } + else + { + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + // In opaque mode, the code is from 0 to 3. + + const R8G8B8A8 &pixel = subblockColors[i]; + const int dot = + pixel.R * direction[0] + pixel.G * direction[1] + pixel.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: + encodedColors[i] = 1; + break; + case 1: + encodedColors[i] = 3; + break; + case 2: + encodedColors[i] = 2; + break; + case 3: + default: + encodedColors[i] = 0; + break; + } + } + } + } + + uint32_t bits = 0; + for (int i = kNumPixelsInBlock - 1; i >= 0; i--) + { + bits <<= 2; + bits |= encodedColors[pixelIndices[i]]; + } + + return bits; + } + + void packBC1(void *bc1, + const int *pixelIndices, + const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + int minColorIndex, + int maxColorIndex, + bool nonOpaquePunchThroughAlpha) const + { + const R8G8B8A8 &minColor = subblockColors[minColorIndex]; + const R8G8B8A8 &maxColor = subblockColors[maxColorIndex]; + + 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(pixelIndices, pixelIndexCounts, subblockColors, numColors, minColor, + maxColor, nonOpaquePunchThroughAlpha); + } + else + { + // Same colors, BC1 index 0 is the color in both opaque and transparent mode + bits = 0; + // BC1 index 3 is transparent + if (nonOpaquePunchThroughAlpha) + { + for (int i = 0; i < kNumPixelsInBlock; i++) + { + if (0 == subblockColors[pixelIndices[i]].A) + { + bits |= (3 << (i * 2)); + } + } + } + } + + if (max16 < min16) + { + std::swap(max16, min16); + + uint32_t xorMask = 0; + if (nonOpaquePunchThroughAlpha) + { + // 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); + } + else + { + // 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; + } + 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 (nonOpaquePunchThroughAlpha) + { + dest->color0 = min16; + dest->color1 = max16; + } + else + { + dest->color0 = max16; + dest->color1 = min16; + } + 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 extractPixelIndices(int *pixelIndices, + int *pixelIndicesCounts, + size_t x, + size_t y, + size_t w, + size_t h, + bool flipbit, + size_t subblockIdx) 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; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = dxBegin; i < dxEnd; i++) + { + const size_t pixelIndex = subblockIdx * 4 + getIndex(i, j); + row[i] = static_cast(pixelIndex); + pixelIndicesCounts[pixelIndex]++; + } + } + } + + void selectEndPointPCA(const int *pixelIndexCounts, + const R8G8B8A8 *subblockColors, + size_t numColors, + int *minColorIndex, + int *maxColorIndex) const + { + // determine color distribution + int mu[3], min[3], max[3]; + for (int ch = 0; ch < 3; ch++) + { + int muv = 0; + int minv = 255; + int maxv = 0; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + // Non-transparent pixels + muv += (&pixel.R)[ch] * count; + minv = std::min(minv, (&pixel.R)[ch]); + maxv = std::max(maxv, (&pixel.R)[ch]); + } + } + } + + mu[ch] = (muv + kNumPixelsInBlock / 2) / kNumPixelsInBlock; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + int cov[6] = {0, 0, 0, 0, 0, 0}; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + int r = pixel.R - mu[0]; + int g = pixel.G - mu[1]; + int b = pixel.B - mu[2]; + + cov[0] += r * r * count; + cov[1] += r * g * count; + cov[2] += r * b * count; + cov[3] += g * g * count; + cov[4] += g * b * count; + cov[5] += b * b * count; + } + } + } + + // Power iteration algorithm to get the eigenvalues and eigenvector + + // Starts with diagonal vector + float vfr = static_cast(max[0] - min[0]); + float vfg = static_cast(max[1] - min[1]); + float vfb = static_cast(max[2] - min[2]); + float eigenvalue; + + static const size_t kPowerIterations = 4; + for (size_t i = 0; i < kPowerIterations; i++) + { + float r = vfr * cov[0] + vfg * cov[1] + vfb * cov[2]; + float g = vfr * cov[1] + vfg * cov[3] + vfb * cov[4]; + float b = vfr * cov[2] + vfg * cov[4] + vfb * cov[5]; + + vfr = r; + vfg = g; + vfb = b; + + eigenvalue = sqrt(r * r + g * g + b * b); + if (eigenvalue > 0) + { + float invNorm = 1.0f / eigenvalue; + vfr *= invNorm; + vfg *= invNorm; + vfb *= invNorm; + } + } + + int vr, vg, vb; + + static const float kDefaultLuminanceThreshold = 4.0f * 255; + static const float kQuantizeRange = 512.0f; + if (eigenvalue < kDefaultLuminanceThreshold) // too small, default to luminance + { + // Luminance weights defined by ITU-R Recommendation BT.601, scaled by 1000 + vr = 299; + vg = 587; + vb = 114; + } + else + { + // From the eigenvalue and eigenvector, choose the axis to project + // colors on. When projecting colors we want to do integer computations + // for speed, so we normalize the eigenvector to the [0, 512] range. + float magn = std::max(std::max(std::abs(vfr), std::abs(vfg)), std::abs(vfb)); + magn = kQuantizeRange / magn; + vr = static_cast(vfr * magn); + vg = static_cast(vfg * magn); + vb = static_cast(vfb * magn); + } + + // Pick colors at extreme points + int minD = INT_MAX; + int maxD = 0; + size_t minIndex = 0; + size_t maxIndex = 0; + for (size_t i = 0; i < numColors; i++) + { + const int count = pixelIndexCounts[i]; + if (count > 0) + { + const auto &pixel = subblockColors[i]; + if (pixel.A > 0) + { + int dot = pixel.R * vr + pixel.G * vg + pixel.B * vb; + if (dot < minD) + { + minD = dot; + minIndex = i; + } + if (dot > maxD) + { + maxD = dot; + maxIndex = i; + } + } + } + } + + *minColorIndex = static_cast(minIndex); + *maxColorIndex = static_cast(maxIndex); + } + + 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 + // select axis by principal component analysis (PCA) 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. + + // The goal of this algorithm is make it faster than decode ETC to RGBs + // and then encode to BC. To achieve this, we only extract subblock + // colors, pixel indices, and counts of each pixel indices from ETC. + // With those information, we can only encode used subblock colors + // to BC1, and copy the bits to the right pixels. + // Fully decode and encode need to process 16 RGBA pixels. With this + // algorithm, it's 8 pixels at maximum for a individual or + // differential block. Saves us bandwidth and computations. + + static const size_t kNumColors = 8; + + const IntensityModifier *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[kNumColors]; + for (size_t modifierIdx = 0; modifierIdx < 4; modifierIdx++) + { + if (nonOpaquePunchThroughAlpha && (modifierIdx == 2)) + { + // In ETC opaque punch through formats, individual and + // differential blocks take index 2 as transparent pixel. + // Thus we don't need to compute its color, just assign it + // as black. + subblockColors[modifierIdx] = createRGBA(0, 0, 0, 0); + subblockColors[4 + modifierIdx] = createRGBA(0, 0, 0, 0); + } + else + { + const int i1 = intensityModifier[u.idht.mode.idm.cw1][modifierIdx]; + subblockColors[modifierIdx] = createRGBA(r1 + i1, g1 + i1, b1 + i1); + + const int i2 = intensityModifier[u.idht.mode.idm.cw2][modifierIdx]; + subblockColors[4 + modifierIdx] = createRGBA(r2 + i2, g2 + i2, b2 + i2); + } + } + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + // Extract pixel indices from a ETC block. + for (size_t blockIdx = 0; blockIdx < 2; blockIdx++) + { + extractPixelIndices(pixelIndices, pixelIndexCounts, x, y, w, h, u.idht.mode.idm.flipbit, + blockIdx); + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, subblockColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, subblockColors, kNumColors, minColorIndex, + maxColorIndex, 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 + { + static const size_t kNumColors = 4; + + // 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]; + + // In ETC opaque punch through formats, index == 2 means transparent pixel. + // Thus we don't need to compute its color, just assign it as black. + const R8G8B8A8 paintColors[kNumColors] = { + createRGBA(r1, g1, b1), createRGBA(r2 + d, g2 + d, b2 + d), + nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) : createRGBA(r2, g2, b2), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + for (size_t j = 0; j < 4; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = 0; i < 4; i++) + { + const size_t pixelIndex = getIndex(i, j); + row[i] = static_cast(pixelIndex); + pixelIndexCounts[pixelIndex]++; + } + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex, + maxColorIndex, nonOpaquePunchThroughAlpha); + } + + 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 + { + static const size_t kNumColors = 4; + + // 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 orderingTrickBit = + ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0); + const int d = distance[(block.Hda << 2) | (block.Hdb << 1) | orderingTrickBit]; + + // In ETC opaque punch through formats, index == 2 means transparent pixel. + // Thus we don't need to compute its color, just assign it as black. + const R8G8B8A8 paintColors[kNumColors] = { + createRGBA(r1 + d, g1 + d, b1 + d), createRGBA(r1 - d, g1 - d, b1 - d), + nonOpaquePunchThroughAlpha ? createRGBA(0, 0, 0, 0) + : createRGBA(r2 + d, g2 + d, b2 + d), + createRGBA(r2 - d, g2 - d, b2 - d), + }; + + int pixelIndices[kNumPixelsInBlock]; + int pixelIndexCounts[kNumColors] = {0}; + for (size_t j = 0; j < 4; j++) + { + int *row = &pixelIndices[j * 4]; + for (size_t i = 0; i < 4; i++) + { + const size_t pixelIndex = getIndex(i, j); + row[i] = static_cast(pixelIndex); + pixelIndexCounts[pixelIndex]++; + } + } + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, paintColors, kNumColors, &minColorIndex, + &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, paintColors, kNumColors, minColorIndex, + maxColorIndex, nonOpaquePunchThroughAlpha); + } + + void transcodePlanarBlockToBC1(uint8_t *dest, + size_t x, + size_t y, + size_t w, + size_t h, + const uint8_t alphaValues[4][4]) const + { + static const size_t kNumColors = kNumPixelsInBlock; + + R8G8B8A8 rgbaBlock[kNumColors]; + decodePlanarBlock(reinterpret_cast(rgbaBlock), x, y, w, h, sizeof(R8G8B8A8) * 4, + alphaValues); + + // Planar block doesn't have a color table, fill indices as full + int pixelIndices[kNumPixelsInBlock] = {0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15}; + int pixelIndexCounts[kNumColors] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + int minColorIndex, maxColorIndex; + selectEndPointPCA(pixelIndexCounts, rgbaBlock, kNumColors, &minColorIndex, &maxColorIndex); + + packBC1(dest, pixelIndices, pixelIndexCounts, rgbaBlock, kNumColors, minColorIndex, + maxColorIndex, false); + } + + // 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 = + priv::OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::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 = + priv::OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::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 = + priv::OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::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 = + priv::OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = priv::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 = + priv::OffsetDataPointer(input, y / 4, z, inputRowPitch, inputDepthPitch); + uint8_t *destRow = + priv::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 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) +{ + LoadETC2RGB8ToBC1(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 LoadETC2SRGB8ToBC1(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 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 LoadETC2RGB8A1ToBC1(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, 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 LoadETC2SRGB8A1ToBC1(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, 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 angle diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp index 651a012037..e10d3add7c 100644 --- a/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp @@ -6,6 +6,8 @@ #include "libANGLE/AttributeMap.h" +#include "common/debug.h" + namespace egl { @@ -13,33 +15,61 @@ AttributeMap::AttributeMap() { } -AttributeMap::AttributeMap(const EGLint *attributes) -{ - if (attributes) - { - for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) - { - insert(curAttrib[0], curAttrib[1]); - } - } -} +AttributeMap::AttributeMap(const AttributeMap &other) = default; -void AttributeMap::insert(EGLint key, EGLint value) +AttributeMap::~AttributeMap() = default; + +void AttributeMap::insert(EGLAttrib key, EGLAttrib value) { mAttributes[key] = value; } -bool AttributeMap::contains(EGLint key) const +bool AttributeMap::contains(EGLAttrib key) const { return (mAttributes.find(key) != mAttributes.end()); } -EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const +EGLAttrib AttributeMap::get(EGLAttrib key) const +{ + auto iter = mAttributes.find(key); + ASSERT(iter != mAttributes.end()); + return iter->second; +} + +EGLAttrib AttributeMap::get(EGLAttrib key, EGLAttrib defaultValue) const { - std::map::const_iterator iter = mAttributes.find(key); + auto iter = mAttributes.find(key); return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; } +EGLint AttributeMap::getAsInt(EGLAttrib key) const +{ + return static_cast(get(key)); +} + +EGLint AttributeMap::getAsInt(EGLAttrib key, EGLint defaultValue) const +{ + return static_cast(get(key, static_cast(defaultValue))); +} + +bool AttributeMap::isEmpty() const +{ + return mAttributes.empty(); +} + +std::vector AttributeMap::toIntVector() const +{ + std::vector ret; + for (const auto &pair : mAttributes) + { + ret.push_back(static_cast(pair.first)); + ret.push_back(static_cast(pair.second)); + } + ret.push_back(EGL_NONE); + + return ret; +} + AttributeMap::const_iterator AttributeMap::begin() const { return mAttributes.begin(); @@ -50,4 +80,31 @@ AttributeMap::const_iterator AttributeMap::end() const return mAttributes.end(); } +// static +AttributeMap AttributeMap::CreateFromIntArray(const EGLint *attributes) +{ + AttributeMap map; + if (attributes) + { + for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + map.insert(static_cast(curAttrib[0]), static_cast(curAttrib[1])); + } + } + return map; +} + +// static +AttributeMap AttributeMap::CreateFromAttribArray(const EGLAttrib *attributes) +{ + AttributeMap map; + if (attributes) + { + for (const EGLAttrib *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + map.insert(curAttrib[0], curAttrib[1]); + } + } + return map; +} } diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.h b/src/3rdparty/angle/src/libANGLE/AttributeMap.h index 56f1684415..eddc1b72d0 100644 --- a/src/3rdparty/angle/src/libANGLE/AttributeMap.h +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.h @@ -11,6 +11,7 @@ #include #include +#include namespace egl { @@ -19,19 +20,28 @@ class AttributeMap final { public: AttributeMap(); - explicit AttributeMap(const EGLint *attributes); + AttributeMap(const AttributeMap &other); + ~AttributeMap(); - void insert(EGLint key, EGLint value); - bool contains(EGLint key) const; - EGLint get(EGLint key, EGLint defaultValue) const; + void insert(EGLAttrib key, EGLAttrib value); + bool contains(EGLAttrib key) const; + EGLAttrib get(EGLAttrib key) const; + EGLAttrib get(EGLAttrib key, EGLAttrib defaultValue) const; + EGLint getAsInt(EGLAttrib key) const; + EGLint getAsInt(EGLAttrib key, EGLint defaultValue) const; + bool isEmpty() const; + std::vector toIntVector() const; - typedef std::map::const_iterator const_iterator; + typedef std::map::const_iterator const_iterator; const_iterator begin() const; const_iterator end() const; + static AttributeMap CreateFromIntArray(const EGLint *attributes); + static AttributeMap CreateFromAttribArray(const EGLAttrib *attributes); + private: - std::map mAttributes; + std::map mAttributes; }; } diff --git a/src/3rdparty/angle/src/libANGLE/BinaryStream.h b/src/3rdparty/angle/src/libANGLE/BinaryStream.h index 3e6ccc7446..3e4c0934cf 100644 --- a/src/3rdparty/angle/src/libANGLE/BinaryStream.h +++ b/src/3rdparty/angle/src/libANGLE/BinaryStream.h @@ -9,25 +9,13 @@ #ifndef LIBANGLE_BINARYSTREAM_H_ #define LIBANGLE_BINARYSTREAM_H_ -#include "common/angleutils.h" -#include "common/mathutil.h" - #include #include #include #include -template -void StaticAssertIsFundamental() -{ - // c++11 STL is not available on OSX or Android -#if !defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_PLATFORM_ANDROID) - static_assert(std::is_fundamental::value, "T must be a fundamental type."); -#else - union { T dummy; } dummy; - static_cast(dummy); -#endif -} +#include "common/angleutils.h" +#include "common/mathutil.h" namespace gl { @@ -58,6 +46,16 @@ class BinaryInputStream : angle::NonCopyable *outValue = readInt(); } + template + void readIntVector(std::vector *param) + { + unsigned int size = readInt(); + for (unsigned int index = 0; index < size; ++index) + { + param->push_back(readInt()); + } + } + bool readBool() { int value = 0; @@ -92,25 +90,31 @@ class BinaryInputStream : angle::NonCopyable return; } - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += length; + + if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } v->assign(reinterpret_cast(mData) + mOffset, length); - mOffset += length; + mOffset = checkedOffset.ValueOrDie(); } void skip(size_t length) { - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += length; + + if (!checkedOffset.IsValid() || mOffset + length > mLength) { mError = true; return; } - mOffset += length; + mOffset = checkedOffset.ValueOrDie(); } size_t offset() const @@ -142,24 +146,27 @@ class BinaryInputStream : angle::NonCopyable template void read(T *v, size_t num) { - StaticAssertIsFundamental(); + static_assert(std::is_fundamental::value, "T must be a fundamental type."); - if (!rx::IsUnsignedMultiplicationSafe(num, sizeof(T))) + angle::CheckedNumeric checkedLength(num); + checkedLength *= sizeof(T); + if (!checkedLength.IsValid()) { mError = true; return; } - size_t length = num * sizeof(T); + angle::CheckedNumeric checkedOffset(mOffset); + checkedOffset += checkedLength; - if (!rx::IsUnsignedAdditionSafe(mOffset, length) || mOffset + length > mLength) + if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength) { mError = true; return; } - memcpy(v, mData + mOffset, length); - mOffset += length; + memcpy(v, mData + mOffset, checkedLength.ValueOrDie()); + mOffset = checkedOffset.ValueOrDie(); } template @@ -173,19 +180,42 @@ class BinaryInputStream : angle::NonCopyable class BinaryOutputStream : angle::NonCopyable { public: - BinaryOutputStream() - { - } + BinaryOutputStream(); + ~BinaryOutputStream(); // writeInt also handles bool types template void writeInt(IntT param) { - ASSERT(rx::IsIntegerCastSafe(param)); + ASSERT(angle::IsValueInRangeForNumericType(param)); int intValue = static_cast(param); write(&intValue, 1); } + // Specialized writeInt for values that can also be exactly -1. + template + void writeIntOrNegOne(UintT param) + { + if (param == static_cast(-1)) + { + writeInt(-1); + } + else + { + writeInt(param); + } + } + + template + void writeIntVector(std::vector param) + { + writeInt(param.size()); + for (IntT element : param) + { + writeIntOrNegOne(element); + } + } + void writeString(const std::string &v) { writeInt(v.length()); @@ -204,7 +234,7 @@ class BinaryOutputStream : angle::NonCopyable const void* data() const { - return mData.size() ? &mData[0] : NULL; + return mData.size() ? &mData[0] : nullptr; } private: @@ -213,12 +243,19 @@ class BinaryOutputStream : angle::NonCopyable template void write(const T *v, size_t num) { - StaticAssertIsFundamental(); + static_assert(std::is_fundamental::value, "T must be a fundamental type."); const char *asBytes = reinterpret_cast(v); mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); } }; + +inline BinaryOutputStream::BinaryOutputStream() +{ } +inline BinaryOutputStream::~BinaryOutputStream() = default; + +} // namespace gl + #endif // LIBANGLE_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.cpp b/src/3rdparty/angle/src/libANGLE/Buffer.cpp index 589735c5a8..a1ebfc1acb 100644 --- a/src/3rdparty/angle/src/libANGLE/Buffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Buffer.cpp @@ -9,123 +9,148 @@ // [OpenGL ES 2.0.24] section 2.9 page 21. #include "libANGLE/Buffer.h" + +#include "libANGLE/Context.h" #include "libANGLE/renderer/BufferImpl.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { -Buffer::Buffer(rx::BufferImpl *impl, GLuint id) - : RefCountObject(id), - mBuffer(impl), - mLabel(), - mUsage(GL_STATIC_DRAW), +BufferState::BufferState() + : mLabel(), + mUsage(BufferUsage::StaticDraw), mSize(0), mAccessFlags(0), mAccess(GL_WRITE_ONLY_OES), mMapped(GL_FALSE), - mMapPointer(NULL), + mMapPointer(nullptr), mMapOffset(0), mMapLength(0) { } +BufferState::~BufferState() +{ +} + +Buffer::Buffer(rx::GLImplFactory *factory, GLuint id) + : RefCountObject(id), mImpl(factory->createBuffer(mState)) +{ +} + Buffer::~Buffer() { - SafeDelete(mBuffer); + SafeDelete(mImpl); +} + +Error Buffer::onDestroy(const Context *context) +{ + // In tests, mImpl might be null. + if (mImpl) + mImpl->destroy(context); + return NoError(); } void Buffer::setLabel(const std::string &label) { - mLabel = label; + mState.mLabel = label; } const std::string &Buffer::getLabel() const { - return mLabel; + return mState.mLabel; } -Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +Error Buffer::bufferData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + BufferUsage usage) { - gl::Error error = mBuffer->setData(data, size, usage); - if (error.isError()) + const void *dataForImpl = data; + + // If we are using robust resource init, make sure the buffer starts cleared. + // Note: the Context is checked for nullptr because of some testing code. + // TODO(jmadill): Investigate lazier clearing. + if (context && context->getGLState().isRobustResourceInitEnabled() && !data && size > 0) { - return error; + angle::MemoryBuffer *scratchBuffer = nullptr; + ANGLE_TRY(context->getZeroFilledBuffer(static_cast(size), &scratchBuffer)); + dataForImpl = scratchBuffer->data(); } + ANGLE_TRY(mImpl->setData(context, target, dataForImpl, size, usage)); + mIndexRangeCache.clear(); - mUsage = usage; - mSize = size; + mState.mUsage = usage; + mState.mSize = size; - return error; + return NoError(); } -Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +Error Buffer::bufferSubData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + GLintptr offset) { - gl::Error error = mBuffer->setSubData(data, size, offset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset)); mIndexRangeCache.invalidateRange(static_cast(offset), static_cast(size)); - return error; + return NoError(); } -Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +Error Buffer::copyBufferSubData(const Context *context, + Buffer *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) { - gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size)); mIndexRangeCache.invalidateRange(static_cast(destOffset), static_cast(size)); - return error; + return NoError(); } -Error Buffer::map(GLenum access) +Error Buffer::map(const Context *context, GLenum access) { - ASSERT(!mMapped); + ASSERT(!mState.mMapped); - Error error = mBuffer->map(access, &mMapPointer); - if (error.isError()) - { - mMapPointer = NULL; - return error; - } + mState.mMapPointer = nullptr; + ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer)); ASSERT(access == GL_WRITE_ONLY_OES); - mMapped = GL_TRUE; - mMapOffset = 0; - mMapLength = mSize; - mAccess = access; - mAccessFlags = GL_MAP_WRITE_BIT; + mState.mMapped = GL_TRUE; + mState.mMapOffset = 0; + mState.mMapLength = mState.mSize; + mState.mAccess = access; + mState.mAccessFlags = GL_MAP_WRITE_BIT; mIndexRangeCache.clear(); - return error; + return NoError(); } -Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) +Error Buffer::mapRange(const Context *context, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { - ASSERT(!mMapped); - ASSERT(offset + length <= mSize); + ASSERT(!mState.mMapped); + ASSERT(offset + length <= mState.mSize); - Error error = mBuffer->mapRange(offset, length, access, &mMapPointer); - if (error.isError()) - { - mMapPointer = NULL; - return error; - } + mState.mMapPointer = nullptr; + ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer)); - mMapped = GL_TRUE; - mMapOffset = static_cast(offset); - mMapLength = static_cast(length); - mAccess = GL_WRITE_ONLY_OES; - mAccessFlags = access; + mState.mMapped = GL_TRUE; + mState.mMapOffset = static_cast(offset); + mState.mMapLength = static_cast(length); + mState.mAccess = GL_WRITE_ONLY_OES; + mState.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 @@ -137,28 +162,24 @@ Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) mIndexRangeCache.invalidateRange(static_cast(offset), static_cast(length)); } - return error; + return NoError(); } -Error Buffer::unmap(GLboolean *result) +Error Buffer::unmap(const Context *context, GLboolean *result) { - ASSERT(mMapped); + ASSERT(mState.mMapped); - Error error = mBuffer->unmap(result); - if (error.isError()) - { - *result = GL_FALSE; - return error; - } + *result = GL_FALSE; + ANGLE_TRY(mImpl->unmap(context, result)); - mMapped = GL_FALSE; - mMapPointer = NULL; - mMapOffset = 0; - mMapLength = 0; - mAccess = GL_WRITE_ONLY_OES; - mAccessFlags = 0; + mState.mMapped = GL_FALSE; + mState.mMapPointer = nullptr; + mState.mMapOffset = 0; + mState.mMapLength = 0; + mState.mAccess = GL_WRITE_ONLY_OES; + mState.mAccessFlags = 0; - return error; + return NoError(); } void Buffer::onTransformFeedback() @@ -171,7 +192,8 @@ void Buffer::onPixelUnpack() mIndexRangeCache.clear(); } -Error Buffer::getIndexRange(GLenum type, +Error Buffer::getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, @@ -179,18 +201,15 @@ Error Buffer::getIndexRange(GLenum type, { if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - Error error = mBuffer->getIndexRange(type, offset, count, primitiveRestartEnabled, outRange); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange)); mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange); - return Error(GL_NO_ERROR); + return NoError(); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.h b/src/3rdparty/angle/src/libANGLE/Buffer.h index 6c951ef586..86d4a9fd6f 100644 --- a/src/3rdparty/angle/src/libANGLE/Buffer.h +++ b/src/3rdparty/angle/src/libANGLE/Buffer.h @@ -15,69 +15,109 @@ #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/IndexRangeCache.h" +#include "libANGLE/PackedGLEnums.h" #include "libANGLE/RefCountObject.h" namespace rx { class BufferImpl; +class GLImplFactory; }; namespace gl { +class Buffer; +class Context; -class Buffer final : public RefCountObject, public LabeledObject +class BufferState final : angle::NonCopyable { public: - Buffer(rx::BufferImpl *impl, GLuint id); - virtual ~Buffer(); + BufferState(); + ~BufferState(); - void setLabel(const std::string &label) override; - const std::string &getLabel() const override; + const std::string &getLabel(); - 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(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; } + BufferUsage getUsage() const { return mUsage; } GLbitfield getAccessFlags() const { return mAccessFlags; } GLenum getAccess() const { return mAccess; } GLboolean isMapped() const { return mMapped; } - GLvoid *getMapPointer() const { return mMapPointer; } + void *getMapPointer() const { return mMapPointer; } GLint64 getMapOffset() const { return mMapOffset; } GLint64 getMapLength() const { return mMapLength; } GLint64 getSize() const { return mSize; } - rx::BufferImpl *getImplementation() const { return mBuffer; } - private: - rx::BufferImpl *mBuffer; + friend class Buffer; std::string mLabel; - GLenum mUsage; + BufferUsage mUsage; GLint64 mSize; GLbitfield mAccessFlags; GLenum mAccess; GLboolean mMapped; - GLvoid *mMapPointer; + void *mMapPointer; GLint64 mMapOffset; GLint64 mMapLength; +}; + +class Buffer final : public RefCountObject, public LabeledObject +{ + public: + Buffer(rx::GLImplFactory *factory, GLuint id); + ~Buffer() override; + Error onDestroy(const Context *context) override; + + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; + + Error bufferData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + BufferUsage usage); + Error bufferSubData(const Context *context, + BufferBinding target, + const void *data, + GLsizeiptr size, + GLintptr offset); + Error copyBufferSubData(const Context *context, + Buffer *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size); + Error map(const Context *context, GLenum access); + Error mapRange(const Context *context, GLintptr offset, GLsizeiptr length, GLbitfield access); + Error unmap(const Context *context, GLboolean *result); + + void onTransformFeedback(); + void onPixelUnpack(); + + Error getIndexRange(const gl::Context *context, + GLenum type, + size_t offset, + size_t count, + bool primitiveRestartEnabled, + IndexRange *outRange) const; + + BufferUsage getUsage() const { return mState.mUsage; } + GLbitfield getAccessFlags() const { return mState.mAccessFlags; } + GLenum getAccess() const { return mState.mAccess; } + GLboolean isMapped() const { return mState.mMapped; } + void *getMapPointer() const { return mState.mMapPointer; } + GLint64 getMapOffset() const { return mState.mMapOffset; } + GLint64 getMapLength() const { return mState.mMapLength; } + GLint64 getSize() const { return mState.mSize; } + + rx::BufferImpl *getImplementation() const { return mImpl; } + + private: + BufferState mState; + rx::BufferImpl *mImpl; mutable IndexRangeCache mIndexRangeCache; }; -} +} // namespace gl -#endif // LIBANGLE_BUFFER_H_ +#endif // LIBANGLE_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Caps.cpp b/src/3rdparty/angle/src/libANGLE/Caps.cpp index 1eb54a1589..44da2bbe27 100644 --- a/src/3rdparty/angle/src/libANGLE/Caps.cpp +++ b/src/3rdparty/angle/src/libANGLE/Caps.cpp @@ -5,9 +5,12 @@ // #include "libANGLE/Caps.h" + #include "common/debug.h" #include "common/angleutils.h" +#include "libANGLE/formatutils.h" + #include "angle_gl.h" #include @@ -32,6 +35,10 @@ TextureCaps::TextureCaps() { } +TextureCaps::TextureCaps(const TextureCaps &other) = default; + +TextureCaps::~TextureCaps() = default; + GLuint TextureCaps::getMaxSamples() const { return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0; @@ -56,40 +63,80 @@ GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const return 0; } +TextureCaps GenerateMinimumTextureCaps(GLenum sizedInternalFormat, + const Version &clientVersion, + const Extensions &extensions) +{ + TextureCaps caps; + + const InternalFormat &internalFormatInfo = GetSizedInternalFormatInfo(sizedInternalFormat); + caps.texturable = internalFormatInfo.textureSupport(clientVersion, extensions); + caps.renderable = internalFormatInfo.renderSupport(clientVersion, extensions); + caps.filterable = internalFormatInfo.filterSupport(clientVersion, extensions); + + caps.sampleCounts.insert(0); + if (internalFormatInfo.isRequiredRenderbufferFormat(clientVersion)) + { + if ((clientVersion.major >= 3 && clientVersion.minor >= 1) || + (clientVersion.major >= 3 && internalFormatInfo.componentType != GL_UNSIGNED_INT && + internalFormatInfo.componentType != GL_INT)) + { + caps.sampleCounts.insert(4); + } + } + + return caps; +} + +TextureCapsMap::TextureCapsMap() +{ +} + +TextureCapsMap::~TextureCapsMap() +{ +} + void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) { - mCapsMap[internalFormat] = caps; + angle::Format::ID formatID = angle::Format::InternalFormatToID(internalFormat); + get(formatID) = caps; } -void TextureCapsMap::remove(GLenum internalFormat) +void TextureCapsMap::clear() { - InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); - if (i != mCapsMap.end()) - { - mCapsMap.erase(i); - } + mFormatData.fill(TextureCaps()); } const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const { - static TextureCaps defaultUnsupportedTexture; - InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); - return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; + angle::Format::ID formatID = angle::Format::InternalFormatToID(internalFormat); + return get(formatID); } -TextureCapsMap::const_iterator TextureCapsMap::begin() const +const TextureCaps &TextureCapsMap::get(angle::Format::ID formatID) const { - return mCapsMap.begin(); + return mFormatData[static_cast(formatID)]; } -TextureCapsMap::const_iterator TextureCapsMap::end() const +TextureCaps &TextureCapsMap::get(angle::Format::ID formatID) { - return mCapsMap.end(); + return mFormatData[static_cast(formatID)]; } -size_t TextureCapsMap::size() const +void TextureCapsMap::set(angle::Format::ID formatID, const TextureCaps &caps) { - return mCapsMap.size(); + get(formatID) = caps; +} + +void InitMinimumTextureCapsMap(const Version &clientVersion, + const Extensions &extensions, + TextureCapsMap *capsMap) +{ + for (GLenum internalFormat : GetAllSizedInternalFormats()) + { + capsMap->insert(internalFormat, + GenerateMinimumTextureCaps(internalFormat, clientVersion, extensions)); + } } Extensions::Extensions() @@ -111,23 +158,25 @@ Extensions::Extensions() textureCompressionDXT1(false), textureCompressionDXT3(false), textureCompressionDXT5(false), + textureCompressionS3TCsRGB(false), textureCompressionASTCHDR(false), textureCompressionASTCLDR(false), compressedETC1RGB8Texture(false), + sRGB(false), depthTextures(false), depth32(false), textureStorage(false), textureNPOT(false), drawBuffers(false), textureFilterAnisotropic(false), - maxTextureAnisotropy(false), + maxTextureAnisotropy(0.0f), occlusionQueryBoolean(false), fence(false), - timerQuery(false), disjointTimerQuery(false), queryCounterBitsTimeElapsed(0), queryCounterBitsTimestamp(0), robustness(false), + robustBufferAccessBehavior(false), blendMinMax(false), framebufferBlit(false), framebufferMultisample(false), @@ -135,10 +184,9 @@ Extensions::Extensions() packReverseRowOrder(false), standardDerivatives(false), shaderTextureLOD(false), - shaderFramebufferFetch(false), - ARMshaderFramebufferFetch(false), - NVshaderFramebufferFetch(false), fragDepth(false), + multiview(false), + maxViews(1u), textureUsage(false), translatedShaderSource(false), fboRenderMipmap(false), @@ -147,6 +195,7 @@ Extensions::Extensions() eglImage(false), eglImageExternal(false), eglImageExternalEssl3(false), + eglStreamConsumerExternal(false), unpackSubimage(false), packSubimage(false), vertexArrayObject(false), @@ -157,7 +206,31 @@ Extensions::Extensions() maxLabelLength(0), noError(false), lossyETCDecode(false), - colorBufferFloat(false) + bindUniformLocation(false), + syncQuery(false), + copyTexture(false), + copyCompressedTexture(false), + webglCompatibility(false), + requestExtension(false), + bindGeneratesResource(false), + robustClientMemory(false), + textureSRGBDecode(false), + sRGBWriteControl(false), + colorBufferFloatRGB(false), + colorBufferFloatRGBA(false), + colorBufferFloat(false), + multisampleCompatibility(false), + framebufferMixedSamples(false), + textureNorm16(false), + pathRendering(false), + surfacelessContext(false), + clientArrays(false), + robustResourceInitialization(false), + programCacheControl(false), + textureRectangle(false), + geometryShader(false), + maxGeometryOutputVertices(0), + maxGeometryShaderInvocations(0) { } @@ -165,70 +238,13 @@ std::vector Extensions::getStrings() const { std::vector 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 + for (const auto &extensionInfo : GetExtensionInfoMap()) + { + if (this->*(extensionInfo.second.ExtensionsMember)) + { + extensionStrings.push_back(extensionInfo.first); + } + } return extensionStrings; } @@ -243,10 +259,14 @@ Limitations::Limitations() { } -static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector &requiredFormats, - bool requiresTexturing, bool requiresFiltering, bool requiresRendering) +static bool GetFormatSupportBase(const TextureCapsMap &textureCaps, + const GLenum *requiredFormats, + size_t requiredFormatsSize, + bool requiresTexturing, + bool requiresFiltering, + bool requiresRendering) { - for (size_t i = 0; i < requiredFormats.size(); i++) + for (size_t i = 0; i < requiredFormatsSize; i++) { const TextureCaps &cap = textureCaps.get(requiredFormats[i]); @@ -269,11 +289,23 @@ static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vecto return true; } +template +static bool GetFormatSupport(const TextureCapsMap &textureCaps, + const GLenum (&requiredFormats)[N], + bool requiresTexturing, + bool requiresFiltering, + bool requiresRendering) +{ + return GetFormatSupportBase(textureCaps, requiredFormats, N, requiresTexturing, + requiresFiltering, requiresRendering); +} + // Check for GL_OES_packed_depth_stencil static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH24_STENCIL8); + constexpr GLenum requiredFormats[] = { + GL_DEPTH24_STENCIL8, + }; return GetFormatSupport(textureCaps, requiredFormats, false, false, true); } @@ -281,9 +313,9 @@ static bool DeterminePackedDepthStencilSupport(const TextureCapsMap &textureCaps // Checks for GL_OES_rgb8_rgba8 support static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB8); - requiredFormats.push_back(GL_RGBA8); + constexpr GLenum requiredFormats[] = { + GL_RGB8, GL_RGBA8, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -291,8 +323,9 @@ static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCap // Checks for GL_EXT_texture_format_BGRA8888 support static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_BGRA8_EXT); + constexpr GLenum requiredFormats[] = { + GL_BGRA8_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -300,11 +333,9 @@ static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFormats[] = { + GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F, + }; return GetFormatSupport(textureCaps, requiredFormats, true, false, true); } @@ -312,19 +343,19 @@ static bool DetermineColorBufferHalfFloatSupport(const TextureCapsMap &textureCa // Checks for GL_OES_texture_half_float support static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB16F); - requiredFormats.push_back(GL_RGBA16F); + constexpr GLenum requiredFormats[] = { + GL_RGB16F, GL_RGBA16F, + }; - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); + return GetFormatSupport(textureCaps, requiredFormats, true, false, false); } // Checks for GL_OES_texture_half_float_linear support static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB16F); - requiredFormats.push_back(GL_RGBA16F); + constexpr GLenum requiredFormats[] = { + GL_RGB16F, GL_RGBA16F, + }; return DetermineHalfFloatTextureSupport(textureCaps) && GetFormatSupport(textureCaps, requiredFormats, true, true, false); @@ -333,50 +364,65 @@ static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &text // Checks for GL_OES_texture_float support static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB32F); - requiredFormats.push_back(GL_RGBA32F); + constexpr GLenum requiredFormats[] = { + GL_RGB32F, GL_RGBA32F, + }; - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); + return GetFormatSupport(textureCaps, requiredFormats, true, false, false); } // Checks for GL_OES_texture_float_linear support static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB32F); - requiredFormats.push_back(GL_RGBA32F); + constexpr GLenum requiredFormats[] = { + GL_RGB32F, GL_RGBA32F, + }; return DetermineFloatTextureSupport(textureCaps) && GetFormatSupport(textureCaps, requiredFormats, true, true, false); } // Checks for GL_EXT_texture_rg support +static bool DetermineRGHalfFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_R16F, GL_RG16F, + }; + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +static bool DetermineRGFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_R32F, GL_RG32F, + }; + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats) { - std::vector requiredFormats; - requiredFormats.push_back(GL_R8); - requiredFormats.push_back(GL_RG8); - if (checkHalfFloatFormats) + if (checkHalfFloatFormats && !DetermineRGHalfFloatTextureSupport(textureCaps)) { - requiredFormats.push_back(GL_R16F); - requiredFormats.push_back(GL_RG16F); + return false; } - if (checkFloatFormats) + + if (checkFloatFormats && !DetermineRGFloatTextureSupport(textureCaps)) { - requiredFormats.push_back(GL_R32F); - requiredFormats.push_back(GL_RG32F); + return false; } + constexpr GLenum requiredFormats[] = { + GL_R8, GL_RG8, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } // Check for GL_EXT_texture_compression_dxt1 static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGB_S3TC_DXT1_EXT); - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -384,8 +430,9 @@ static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ANGLE_texture_compression_dxt3 static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -393,8 +440,20 @@ static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ANGLE_texture_compression_dxt5 static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_EXT_texture_compression_s3tc_srgb +static bool DetermineS3TCsRGBTextureSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -402,35 +461,22 @@ static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) // 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); + constexpr GLenum requiredFormats[] = { + GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, + GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, + GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, + GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, + GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, + GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, + GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, + GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -438,8 +484,9 @@ static bool DetermineASTCTextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ETC1_RGB8_OES static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_ETC1_RGB8_OES); + constexpr GLenum requiredFormats[] = { + GL_ETC1_RGB8_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, false); } @@ -447,12 +494,13 @@ static bool DetermineETC1RGB8TextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ANGLE_texture_compression_dxt5 static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFilterFormats; - requiredFilterFormats.push_back(GL_SRGB8); - requiredFilterFormats.push_back(GL_SRGB8_ALPHA8); + constexpr GLenum requiredFilterFormats[] = { + GL_SRGB8, GL_SRGB8_ALPHA8, + }; - std::vector requiredRenderFormats; - requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); + constexpr GLenum requiredRenderFormats[] = { + GL_SRGB8_ALPHA8, + }; return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); @@ -461,10 +509,9 @@ static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) // Check for GL_ANGLE_depth_texture static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH_COMPONENT16); - requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); - requiredFormats.push_back(GL_DEPTH24_STENCIL8_OES); + constexpr GLenum requiredFormats[] = { + GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32_OES, GL_DEPTH24_STENCIL8_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, true, true, true); } @@ -472,27 +519,59 @@ static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) // Check for GL_OES_depth32 static bool DetermineDepth32Support(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); + constexpr GLenum requiredFormats[] = { + GL_DEPTH_COMPONENT32_OES, + }; return GetFormatSupport(textureCaps, requiredFormats, false, false, true); } +// Check for GL_CHROMIUM_color_buffer_float_rgb +static bool DetermineColorBufferFloatRGBSupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_RGB32F, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Check for GL_CHROMIUM_color_buffer_float_rgba +static bool DetermineColorBufferFloatRGBASupport(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFormats[] = { + GL_RGBA32F, + }; + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + // Check for GL_EXT_color_buffer_float static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps) { - std::vector requiredFormats; - requiredFormats.push_back(GL_R16F); - requiredFormats.push_back(GL_RG16F); - requiredFormats.push_back(GL_RGBA16F); - requiredFormats.push_back(GL_R32F); - requiredFormats.push_back(GL_RG32F); - requiredFormats.push_back(GL_RGBA32F); - requiredFormats.push_back(GL_R11F_G11F_B10F); + constexpr GLenum requiredFormats[] = { + GL_R16F, GL_RG16F, GL_RGBA16F, GL_R32F, GL_RG32F, GL_RGBA32F, GL_R11F_G11F_B10F, + }; return GetFormatSupport(textureCaps, requiredFormats, true, false, true); } +// Check for GL_EXT_texture_norm16 +static bool DetermineTextureNorm16Support(const TextureCapsMap &textureCaps) +{ + constexpr GLenum requiredFilterFormats[] = { + GL_R16_EXT, GL_RG16_EXT, GL_RGB16_EXT, GL_RGBA16_EXT, + GL_R16_SNORM_EXT, GL_RG16_SNORM_EXT, GL_RGB16_SNORM_EXT, GL_RGBA16_SNORM_EXT, + }; + + constexpr GLenum requiredRenderFormats[] = { + GL_R16_EXT, GL_RG16_EXT, GL_RGBA16_EXT, + }; + + return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && + GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); +} + void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) { packedDepthStencil = DeterminePackedDepthStencilSupport(textureCaps); @@ -507,47 +586,161 @@ void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); + textureCompressionS3TCsRGB = DetermineS3TCsRGBTextureSupport(textureCaps); textureCompressionASTCHDR = DetermineASTCTextureSupport(textureCaps); textureCompressionASTCLDR = textureCompressionASTCHDR; compressedETC1RGB8Texture = DetermineETC1RGB8TextureSupport(textureCaps); sRGB = DetermineSRGBTextureSupport(textureCaps); depthTextures = DetermineDepthTextureSupport(textureCaps); depth32 = DetermineDepth32Support(textureCaps); + colorBufferFloatRGB = DetermineColorBufferFloatRGBSupport(textureCaps); + colorBufferFloatRGBA = DetermineColorBufferFloatRGBASupport(textureCaps); colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); + textureNorm16 = DetermineTextureNorm16Support(textureCaps); } -TypePrecision::TypePrecision() +const ExtensionInfoMap &GetExtensionInfoMap() { - range[0] = 0; - range[1] = 0; - precision = 0; + auto buildExtensionInfoMap = []() { + auto enableableExtension = [](ExtensionInfo::ExtensionBool member) { + ExtensionInfo info; + info.Requestable = true; + info.ExtensionsMember = member; + return info; + }; + + auto esOnlyExtension = [](ExtensionInfo::ExtensionBool member) { + ExtensionInfo info; + info.ExtensionsMember = member; + return info; + }; + + // clang-format off + ExtensionInfoMap map; + map["GL_OES_element_index_uint"] = enableableExtension(&Extensions::elementIndexUint); + map["GL_OES_packed_depth_stencil"] = esOnlyExtension(&Extensions::packedDepthStencil); + map["GL_OES_get_program_binary"] = enableableExtension(&Extensions::getProgramBinary); + map["GL_OES_rgb8_rgba8"] = enableableExtension(&Extensions::rgb8rgba8); + map["GL_EXT_texture_format_BGRA8888"] = enableableExtension(&Extensions::textureFormatBGRA8888); + map["GL_EXT_read_format_bgra"] = esOnlyExtension(&Extensions::readFormatBGRA); + map["GL_NV_pixel_buffer_object"] = enableableExtension(&Extensions::pixelBufferObject); + map["GL_OES_mapbuffer"] = enableableExtension(&Extensions::mapBuffer); + map["GL_EXT_map_buffer_range"] = enableableExtension(&Extensions::mapBufferRange); + map["GL_EXT_color_buffer_half_float"] = enableableExtension(&Extensions::colorBufferHalfFloat); + map["GL_OES_texture_half_float"] = enableableExtension(&Extensions::textureHalfFloat); + map["GL_OES_texture_half_float_linear"] = enableableExtension(&Extensions::textureHalfFloatLinear); + map["GL_OES_texture_float"] = enableableExtension(&Extensions::textureFloat); + map["GL_OES_texture_float_linear"] = enableableExtension(&Extensions::textureFloatLinear); + map["GL_EXT_texture_rg"] = enableableExtension(&Extensions::textureRG); + map["GL_EXT_texture_compression_dxt1"] = enableableExtension(&Extensions::textureCompressionDXT1); + map["GL_ANGLE_texture_compression_dxt3"] = enableableExtension(&Extensions::textureCompressionDXT3); + map["GL_ANGLE_texture_compression_dxt5"] = enableableExtension(&Extensions::textureCompressionDXT5); + map["GL_EXT_texture_compression_s3tc_srgb"] = enableableExtension(&Extensions::textureCompressionS3TCsRGB); + map["GL_KHR_texture_compression_astc_hdr"] = enableableExtension(&Extensions::textureCompressionASTCHDR); + map["GL_KHR_texture_compression_astc_ldr"] = enableableExtension(&Extensions::textureCompressionASTCLDR); + map["GL_OES_compressed_ETC1_RGB8_texture"] = enableableExtension(&Extensions::compressedETC1RGB8Texture); + map["GL_EXT_sRGB"] = enableableExtension(&Extensions::sRGB); + map["GL_ANGLE_depth_texture"] = esOnlyExtension(&Extensions::depthTextures); + map["GL_OES_depth32"] = esOnlyExtension(&Extensions::depth32); + map["GL_EXT_texture_storage"] = esOnlyExtension(&Extensions::textureStorage); + map["GL_OES_texture_npot"] = enableableExtension(&Extensions::textureNPOT); + map["GL_EXT_draw_buffers"] = enableableExtension(&Extensions::drawBuffers); + map["GL_EXT_texture_filter_anisotropic"] = enableableExtension(&Extensions::textureFilterAnisotropic); + map["GL_EXT_occlusion_query_boolean"] = enableableExtension(&Extensions::occlusionQueryBoolean); + map["GL_NV_fence"] = esOnlyExtension(&Extensions::fence); + map["GL_EXT_disjoint_timer_query"] = enableableExtension(&Extensions::disjointTimerQuery); + map["GL_EXT_robustness"] = esOnlyExtension(&Extensions::robustness); + map["GL_KHR_robust_buffer_access_behavior"] = esOnlyExtension(&Extensions::robustBufferAccessBehavior); + map["GL_EXT_blend_minmax"] = enableableExtension(&Extensions::blendMinMax); + map["GL_ANGLE_framebuffer_blit"] = enableableExtension(&Extensions::framebufferBlit); + map["GL_ANGLE_framebuffer_multisample"] = enableableExtension(&Extensions::framebufferMultisample); + map["GL_ANGLE_instanced_arrays"] = enableableExtension(&Extensions::instancedArrays); + map["GL_ANGLE_pack_reverse_row_order"] = enableableExtension(&Extensions::packReverseRowOrder); + map["GL_OES_standard_derivatives"] = enableableExtension(&Extensions::standardDerivatives); + map["GL_EXT_shader_texture_lod"] = enableableExtension(&Extensions::shaderTextureLOD); + map["GL_EXT_frag_depth"] = enableableExtension(&Extensions::fragDepth); + map["GL_ANGLE_multiview"] = enableableExtension(&Extensions::multiview); + map["GL_ANGLE_texture_usage"] = enableableExtension(&Extensions::textureUsage); + map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource); + map["GL_OES_fbo_render_mipmap"] = enableableExtension(&Extensions::fboRenderMipmap); + map["GL_EXT_discard_framebuffer"] = esOnlyExtension(&Extensions::discardFramebuffer); + map["GL_EXT_debug_marker"] = esOnlyExtension(&Extensions::debugMarker); + map["GL_OES_EGL_image"] = esOnlyExtension(&Extensions::eglImage); + map["GL_OES_EGL_image_external"] = esOnlyExtension(&Extensions::eglImageExternal); + map["GL_OES_EGL_image_external_essl3"] = esOnlyExtension(&Extensions::eglImageExternalEssl3); + map["GL_NV_EGL_stream_consumer_external"] = esOnlyExtension(&Extensions::eglStreamConsumerExternal); + map["GL_EXT_unpack_subimage"] = enableableExtension(&Extensions::unpackSubimage); + map["GL_NV_pack_subimage"] = enableableExtension(&Extensions::packSubimage); + map["GL_EXT_color_buffer_float"] = enableableExtension(&Extensions::colorBufferFloat); + map["GL_OES_vertex_array_object"] = esOnlyExtension(&Extensions::vertexArrayObject); + map["GL_KHR_debug"] = esOnlyExtension(&Extensions::debug); + // TODO(jmadill): Enable this when complete. + //map["GL_KHR_no_error"] = esOnlyExtension(&Extensions::noError); + map["GL_ANGLE_lossy_etc_decode"] = enableableExtension(&Extensions::lossyETCDecode); + map["GL_CHROMIUM_bind_uniform_location"] = esOnlyExtension(&Extensions::bindUniformLocation); + map["GL_CHROMIUM_sync_query"] = enableableExtension(&Extensions::syncQuery); + map["GL_CHROMIUM_copy_texture"] = esOnlyExtension(&Extensions::copyTexture); + map["GL_CHROMIUM_copy_compressed_texture"] = esOnlyExtension(&Extensions::copyCompressedTexture); + map["GL_ANGLE_webgl_compatibility"] = esOnlyExtension(&Extensions::webglCompatibility); + map["GL_ANGLE_request_extension"] = esOnlyExtension(&Extensions::requestExtension); + map["GL_CHROMIUM_bind_generates_resource"] = esOnlyExtension(&Extensions::bindGeneratesResource); + map["GL_ANGLE_robust_client_memory"] = esOnlyExtension(&Extensions::robustClientMemory); + map["GL_EXT_texture_sRGB_decode"] = esOnlyExtension(&Extensions::textureSRGBDecode); + map["GL_EXT_sRGB_write_control"] = esOnlyExtension(&Extensions::sRGBWriteControl); + map["GL_CHROMIUM_color_buffer_float_rgb"] = enableableExtension(&Extensions::colorBufferFloatRGB); + map["GL_CHROMIUM_color_buffer_float_rgba"] = enableableExtension(&Extensions::colorBufferFloatRGBA); + map["GL_EXT_multisample_compatibility"] = esOnlyExtension(&Extensions::multisampleCompatibility); + map["GL_CHROMIUM_framebuffer_mixed_samples"] = esOnlyExtension(&Extensions::framebufferMixedSamples); + map["GL_EXT_texture_norm16"] = esOnlyExtension(&Extensions::textureNorm16); + map["GL_CHROMIUM_path_rendering"] = esOnlyExtension(&Extensions::pathRendering); + map["GL_OES_surfaceless_context"] = esOnlyExtension(&Extensions::surfacelessContext); + map["GL_ANGLE_client_arrays"] = esOnlyExtension(&Extensions::clientArrays); + map["GL_ANGLE_robust_resource_initialization"] = esOnlyExtension(&Extensions::robustResourceInitialization); + map["GL_ANGLE_program_cache_control"] = esOnlyExtension(&Extensions::programCacheControl); + map["GL_ANGLE_texture_rectangle"] = enableableExtension(&Extensions::textureRectangle); + map["GL_EXT_geometry_shader"] = enableableExtension(&Extensions::geometryShader); + // clang-format on + + return map; + }; + + static const ExtensionInfoMap extensionInfo = buildExtensionInfoMap(); + return extensionInfo; } +TypePrecision::TypePrecision() : range({{0, 0}}), precision(0) +{ +} + +TypePrecision::TypePrecision(const TypePrecision &other) = default; + void TypePrecision::setIEEEFloat() { - range[0] = 127; - range[1] = 127; + range = {{127, 127}}; precision = 23; } void TypePrecision::setTwosComplementInt(unsigned int bits) { - range[0] = GLint(bits) - 1; - range[1] = GLint(bits) - 2; + range = {{static_cast(bits) - 1, static_cast(bits) - 2}}; precision = 0; } +void TypePrecision::setSimulatedFloat(unsigned int r, unsigned int p) +{ + range = {{static_cast(r), static_cast(r)}}; + precision = static_cast(p); +} + void TypePrecision::setSimulatedInt(unsigned int r) { - range[0] = GLint(r); - range[1] = GLint(r); + range = {{static_cast(r), static_cast(r)}}; precision = 0; } void TypePrecision::get(GLint *returnRange, GLint *returnPrecision) const { - returnRange[0] = range[0]; - returnRange[1] = range[1]; + std::copy(range.begin(), range.end(), returnRange); *returnPrecision = precision; } @@ -555,37 +748,77 @@ Caps::Caps() : maxElementIndex(0), max3DTextureSize(0), max2DTextureSize(0), + maxRectangleTextureSize(0), maxArrayTextureLayers(0), maxLODBias(0), maxCubeMapTextureSize(0), maxRenderbufferSize(0), + minAliasedPointSize(0), + maxAliasedPointSize(0), + minAliasedLineWidth(0), + maxAliasedLineWidth(0), + + // Table 20.40 maxDrawBuffers(0), + maxFramebufferWidth(0), + maxFramebufferHeight(0), + maxFramebufferSamples(0), maxColorAttachments(0), maxViewportWidth(0), maxViewportHeight(0), - minAliasedPointSize(0), - maxAliasedPointSize(0), - minAliasedLineWidth(0), - // Table 6.29 + maxSampleMaskWords(0), + maxColorTextureSamples(0), + maxDepthTextureSamples(0), + maxIntegerSamples(0), + maxServerWaitTimeout(0), + + // Table 20.41 + maxVertexAttribRelativeOffset(0), + maxVertexAttribBindings(0), + maxVertexAttribStride(0), maxElementsIndices(0), maxElementsVertices(0), - maxServerWaitTimeout(0), - // Table 6.31 + + // Table 20.43 maxVertexAttributes(0), maxVertexUniformComponents(0), maxVertexUniformVectors(0), maxVertexUniformBlocks(0), maxVertexOutputComponents(0), maxVertexTextureImageUnits(0), - // Table 6.32 + maxVertexAtomicCounterBuffers(0), + maxVertexAtomicCounters(0), + maxVertexImageUniforms(0), + maxVertexShaderStorageBlocks(0), + + // Table 20.44 maxFragmentUniformComponents(0), maxFragmentUniformVectors(0), maxFragmentUniformBlocks(0), maxFragmentInputComponents(0), maxTextureImageUnits(0), + maxFragmentAtomicCounterBuffers(0), + maxFragmentAtomicCounters(0), + maxFragmentImageUniforms(0), + maxFragmentShaderStorageBlocks(0), + minProgramTextureGatherOffset(0), + maxProgramTextureGatherOffset(0), minProgramTexelOffset(0), maxProgramTexelOffset(0), - // Table 6.33 + + // Table 20.45 + maxComputeWorkGroupInvocations(0), + maxComputeUniformBlocks(0), + maxComputeTextureImageUnits(0), + maxComputeSharedMemorySize(0), + maxComputeUniformComponents(0), + maxComputeAtomicCounterBuffers(0), + maxComputeAtomicCounters(0), + maxComputeImageUniforms(0), + maxCombinedComputeUniformComponents(0), + maxComputeShaderStorageBlocks(0), + + // Table 20.46 maxUniformBufferBindings(0), maxUniformBlockSize(0), uniformBufferOffsetAlignment(0), @@ -595,15 +828,233 @@ Caps::Caps() maxVaryingComponents(0), maxVaryingVectors(0), maxCombinedTextureImageUnits(0), - // Table 6.34 + maxCombinedShaderOutputResources(0), + + // Table 20.47 + maxUniformLocations(0), + maxAtomicCounterBufferBindings(0), + maxAtomicCounterBufferSize(0), + maxCombinedAtomicCounterBuffers(0), + maxCombinedAtomicCounters(0), + maxImageUnits(0), + maxCombinedImageUniforms(0), + maxShaderStorageBufferBindings(0), + maxShaderStorageBlockSize(0), + maxCombinedShaderStorageBlocks(0), + shaderStorageBufferOffsetAlignment(0), + + // Table 20.48 maxTransformFeedbackInterleavedComponents(0), maxTransformFeedbackSeparateAttributes(0), maxTransformFeedbackSeparateComponents(0), - // Table 6.35 + + // Table 20.49 maxSamples(0) { + for (size_t i = 0; i < 3; ++i) + { + maxComputeWorkGroupCount[i] = 0; + maxComputeWorkGroupSize[i] = 0; + } } +Caps::Caps(const Caps &other) = default; +Caps::~Caps() = default; + +Caps GenerateMinimumCaps(const Version &clientVersion, const Extensions &extensions) +{ + Caps caps; + + if (clientVersion >= Version(2, 0)) + { + // Table 6.18 + caps.max2DTextureSize = 64; + caps.maxCubeMapTextureSize = 16; + caps.maxViewportWidth = caps.max2DTextureSize; + caps.maxViewportHeight = caps.max2DTextureSize; + caps.minAliasedPointSize = 1; + caps.maxAliasedPointSize = 1; + caps.minAliasedLineWidth = 1; + caps.maxAliasedLineWidth = 1; + + // Table 6.19 + caps.vertexHighpFloat.setSimulatedFloat(62, 16); + caps.vertexMediumpFloat.setSimulatedFloat(14, 10); + caps.vertexLowpFloat.setSimulatedFloat(1, 8); + caps.vertexHighpInt.setSimulatedInt(16); + caps.vertexMediumpInt.setSimulatedInt(10); + caps.vertexLowpInt.setSimulatedInt(8); + caps.fragmentHighpFloat.setSimulatedFloat(62, 16); + caps.fragmentMediumpFloat.setSimulatedFloat(14, 10); + caps.fragmentLowpFloat.setSimulatedFloat(1, 8); + caps.fragmentHighpInt.setSimulatedInt(16); + caps.fragmentMediumpInt.setSimulatedInt(10); + caps.fragmentLowpInt.setSimulatedInt(8); + + // Table 6.20 + caps.maxVertexAttributes = 8; + caps.maxVertexUniformVectors = 128; + caps.maxVaryingVectors = 8; + caps.maxCombinedTextureImageUnits = 8; + caps.maxTextureImageUnits = 8; + caps.maxFragmentUniformVectors = 16; + caps.maxRenderbufferSize = 1; + } + + if (clientVersion >= Version(3, 0)) + { + // Table 6.28 + caps.maxElementIndex = (1 << 24) - 1; + caps.max3DTextureSize = 256; + caps.max2DTextureSize = 2048; + caps.maxArrayTextureLayers = 256; + caps.maxLODBias = 2.0f; + caps.maxCubeMapTextureSize = 2048; + caps.maxRenderbufferSize = 2048; + caps.maxDrawBuffers = 4; + caps.maxColorAttachments = 4; + caps.maxViewportWidth = caps.max2DTextureSize; + caps.maxViewportHeight = caps.max2DTextureSize; + + // Table 6.29 + caps.compressedTextureFormats.push_back(GL_COMPRESSED_R11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_R11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RG11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SIGNED_RG11_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_RGBA8_ETC2_EAC); + caps.compressedTextureFormats.push_back(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC); + caps.vertexHighpFloat.setIEEEFloat(); + caps.vertexHighpInt.setTwosComplementInt(32); + caps.vertexMediumpInt.setTwosComplementInt(16); + caps.vertexLowpInt.setTwosComplementInt(8); + caps.fragmentHighpFloat.setIEEEFloat(); + caps.fragmentHighpInt.setSimulatedInt(32); + caps.fragmentMediumpInt.setTwosComplementInt(16); + caps.fragmentLowpInt.setTwosComplementInt(8); + caps.maxServerWaitTimeout = 0; + + // Table 6.31 + caps.maxVertexAttributes = 16; + caps.maxVertexUniformComponents = 1024; + caps.maxVertexUniformVectors = 256; + caps.maxVertexUniformBlocks = 12; + caps.maxVertexOutputComponents = 64; + caps.maxVertexTextureImageUnits = 16; + + // Table 6.32 + caps.maxFragmentUniformComponents = 896; + caps.maxFragmentUniformVectors = 224; + caps.maxFragmentUniformBlocks = 12; + caps.maxFragmentInputComponents = 60; + caps.maxTextureImageUnits = 16; + caps.minProgramTexelOffset = -8; + caps.maxProgramTexelOffset = 7; + + // Table 6.33 + caps.maxUniformBufferBindings = 24; + caps.maxUniformBlockSize = 16384; + caps.uniformBufferOffsetAlignment = 256; + caps.maxCombinedUniformBlocks = 24; + caps.maxCombinedVertexUniformComponents = + caps.maxVertexUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxVertexUniformComponents; + caps.maxCombinedFragmentUniformComponents = + caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxFragmentUniformComponents; + caps.maxVaryingComponents = 60; + caps.maxVaryingVectors = 15; + caps.maxCombinedTextureImageUnits = 32; + + // Table 6.34 + caps.maxTransformFeedbackInterleavedComponents = 64; + caps.maxTransformFeedbackSeparateAttributes = 4; + caps.maxTransformFeedbackSeparateComponents = 4; + + // Table 3.35 + caps.maxSamples = 4; + } + + if (clientVersion >= Version(3, 1)) + { + // Table 20.40 + caps.maxFramebufferWidth = 2048; + caps.maxFramebufferHeight = 2048; + caps.maxFramebufferSamples = 4; + caps.maxSampleMaskWords = 1; + caps.maxColorTextureSamples = 1; + caps.maxDepthTextureSamples = 1; + caps.maxIntegerSamples = 1; + + // Table 20.41 + caps.maxVertexAttribRelativeOffset = 2047; + caps.maxVertexAttribBindings = 16; + caps.maxVertexAttribStride = 2048; + + // Table 20.43 + caps.maxVertexAtomicCounterBuffers = 0; + caps.maxVertexAtomicCounters = 0; + caps.maxVertexImageUniforms = 0; + caps.maxVertexShaderStorageBlocks = 0; + + // Table 20.44 + caps.maxFragmentUniformComponents = 1024; + caps.maxFragmentUniformVectors = 256; + caps.maxFragmentAtomicCounterBuffers = 0; + caps.maxFragmentAtomicCounters = 0; + caps.maxFragmentImageUniforms = 0; + caps.maxFragmentShaderStorageBlocks = 0; + caps.minProgramTextureGatherOffset = 0; + caps.maxProgramTextureGatherOffset = 0; + + // Table 20.45 + caps.maxComputeWorkGroupCount = {{65535, 65535, 65535}}; + caps.maxComputeWorkGroupSize = {{128, 128, 64}}; + caps.maxComputeWorkGroupInvocations = 12; + caps.maxComputeUniformBlocks = 12; + caps.maxComputeTextureImageUnits = 16; + caps.maxComputeSharedMemorySize = 16384; + caps.maxComputeUniformComponents = 1024; + caps.maxComputeAtomicCounterBuffers = 1; + caps.maxComputeAtomicCounters = 8; + caps.maxComputeImageUniforms = 4; + caps.maxCombinedComputeUniformComponents = + caps.maxComputeUniformBlocks * static_cast(caps.maxUniformBlockSize / 4) + + caps.maxComputeUniformComponents; + caps.maxComputeShaderStorageBlocks = 4; + + // Table 20.46 + caps.maxUniformBufferBindings = 36; + caps.maxCombinedFragmentUniformComponents = + caps.maxFragmentUniformBlocks * (caps.maxUniformBlockSize / 4) + + caps.maxFragmentUniformComponents; + caps.maxCombinedTextureImageUnits = 48; + caps.maxCombinedShaderOutputResources = 4; + + // Table 20.47 + caps.maxUniformLocations = 1024; + caps.maxAtomicCounterBufferBindings = 1; + caps.maxAtomicCounterBufferSize = 32; + caps.maxCombinedAtomicCounterBuffers = 1; + caps.maxCombinedAtomicCounters = 8; + caps.maxImageUnits = 4; + caps.maxCombinedImageUniforms = 4; + caps.maxShaderStorageBufferBindings = 4; + caps.maxShaderStorageBlockSize = 1 << 27; + caps.maxCombinedShaderStorageBlocks = 4; + caps.shaderStorageBufferOffsetAlignment = 256; + } + + if (extensions.textureRectangle) + { + caps.maxRectangleTextureSize = 64; + } + + return caps; +} } namespace egl @@ -617,6 +1068,7 @@ Caps::Caps() DisplayExtensions::DisplayExtensions() : createContextRobustness(false), d3dShareHandleClientBuffer(false), + d3dTextureClientBuffer(false), surfaceD3DTexture2DShareHandle(false), querySurfacePointer(false), windowFixedSize(false), @@ -635,7 +1087,21 @@ DisplayExtensions::DisplayExtensions() getAllProcAddresses(false), flexibleSurfaceCompatibility(false), directComposition(false), - createContextNoError(false) + createContextNoError(false), + stream(false), + streamConsumerGLTexture(false), + streamConsumerGLTextureYUV(false), + streamProducerD3DTextureNV12(false), + createContextWebGLCompatibility(false), + createContextBindGeneratesResource(false), + getSyncValues(false), + swapBuffersWithDamage(false), + pixelFormatFloat(false), + surfacelessContext(false), + displayTextureShareGroup(false), + createContextClientArrays(false), + programCacheControl(false), + robustResourceInitialization(false) { } @@ -644,29 +1110,44 @@ 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); + // | 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_d3d_texture_client_buffer", d3dTextureClientBuffer, &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_KHR_stream", stream, &extensionStrings); + InsertExtensionString("EGL_KHR_stream_consumer_gltexture", streamConsumerGLTexture, &extensionStrings); + InsertExtensionString("EGL_NV_stream_consumer_gltexture_yuv", streamConsumerGLTextureYUV, &extensionStrings); + InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings); + InsertExtensionString("EGL_ANGLE_stream_producer_d3d_texture_nv12", streamProducerD3DTextureNV12, &extensionStrings); + InsertExtensionString("EGL_ANGLE_create_context_webgl_compatibility", createContextWebGLCompatibility, &extensionStrings); + InsertExtensionString("EGL_CHROMIUM_create_context_bind_generates_resource", createContextBindGeneratesResource, &extensionStrings); + InsertExtensionString("EGL_CHROMIUM_sync_control", getSyncValues, &extensionStrings); + InsertExtensionString("EGL_EXT_swap_buffers_with_damage", swapBuffersWithDamage, &extensionStrings); + InsertExtensionString("EGL_EXT_pixel_format_float", pixelFormatFloat, &extensionStrings); + InsertExtensionString("EGL_KHR_surfaceless_context", surfacelessContext, &extensionStrings); + InsertExtensionString("EGL_ANGLE_display_texture_share_group", displayTextureShareGroup, &extensionStrings); + InsertExtensionString("EGL_ANGLE_create_context_client_arrays", createContextClientArrays, &extensionStrings); + InsertExtensionString("EGL_ANGLE_program_cache_control", programCacheControl, &extensionStrings); + InsertExtensionString("EGL_ANGLE_robust_resource_initialization", robustResourceInitialization, &extensionStrings); // TODO(jmadill): Enable this when complete. - //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings); + //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings); // clang-format on return extensionStrings; @@ -694,6 +1175,7 @@ ClientExtensions::ClientExtensions() platformANGLE(false), platformANGLED3D(false), platformANGLEOpenGL(false), + platformANGLEVulkan(false), deviceCreation(false), deviceCreationD3D11(false), x11Visual(false), @@ -702,6 +1184,8 @@ ClientExtensions::ClientExtensions() { } +ClientExtensions::ClientExtensions(const ClientExtensions &other) = default; + std::vector ClientExtensions::getStrings() const { std::vector extensionStrings; @@ -714,6 +1198,8 @@ std::vector ClientExtensions::getStrings() const 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_platform_angle_null", platformANGLENULL, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_vulkan", platformANGLEVulkan, &extensionStrings); InsertExtensionString("EGL_ANGLE_device_creation", deviceCreation, &extensionStrings); InsertExtensionString("EGL_ANGLE_device_creation_d3d11", deviceCreationD3D11, &extensionStrings); InsertExtensionString("EGL_ANGLE_x11_visual", x11Visual, &extensionStrings); @@ -724,4 +1210,4 @@ std::vector ClientExtensions::getStrings() const return extensionStrings; } -} +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Caps.h b/src/3rdparty/angle/src/libANGLE/Caps.h index d0e839a2ba..64bdf97112 100644 --- a/src/3rdparty/angle/src/libANGLE/Caps.h +++ b/src/3rdparty/angle/src/libANGLE/Caps.h @@ -8,21 +8,28 @@ #define LIBANGLE_CAPS_H_ #include "angle_gl.h" +#include "libANGLE/Version.h" #include "libANGLE/angletypes.h" +#include "libANGLE/renderer/Format.h" #include #include #include #include +#include namespace gl { +struct Extensions; + typedef std::set SupportedSampleSet; struct TextureCaps { TextureCaps(); + TextureCaps(const TextureCaps &other); + ~TextureCaps(); // Supports for basic texturing: glTexImage, glTexSubImage, etc bool texturable; @@ -44,26 +51,37 @@ struct TextureCaps GLuint getNearestSamples(GLuint requestedSamples) const; }; -class TextureCapsMap +TextureCaps GenerateMinimumTextureCaps(GLenum internalFormat, + const Version &clientVersion, + const Extensions &extensions); + +class TextureCapsMap final : angle::NonCopyable { public: - typedef std::map::const_iterator const_iterator; + TextureCapsMap(); + ~TextureCapsMap(); + // These methods are deprecated. Please use angle::Format for new features. void insert(GLenum internalFormat, const TextureCaps &caps); - void remove(GLenum internalFormat); - const TextureCaps &get(GLenum internalFormat) const; - const_iterator begin() const; - const_iterator end() const; + void clear(); - size_t size() const; + // Prefer using angle::Format methods. + const TextureCaps &get(angle::Format::ID formatID) const; + void set(angle::Format::ID formatID, const TextureCaps &caps); private: - typedef std::map InternalFormatToCapsMap; - InternalFormatToCapsMap mCapsMap; + TextureCaps &get(angle::Format::ID formatID); + + // Indexed by angle::Format::ID + std::array mFormatData; }; +void InitMinimumTextureCapsMap(const Version &clientVersion, + const Extensions &extensions, + TextureCapsMap *capsMap); + struct Extensions { Extensions(); @@ -87,6 +105,7 @@ struct Extensions // GL_EXT_sRGB // GL_ANGLE_depth_texture, GL_OES_depth32 // GL_EXT_color_buffer_float + // GL_EXT_texture_norm16 void setTextureExtensionSupport(const TextureCapsMap &textureCaps); // ES2 Extension support @@ -141,12 +160,18 @@ struct Extensions bool textureRG; // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5 - // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + // Implies that TextureCaps exist for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE bool textureCompressionDXT1; bool textureCompressionDXT3; bool textureCompressionDXT5; + // GL_EXT_texture_compression_s3tc_srgb + // Implies that TextureCaps exist for GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, + // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, and + // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT + bool textureCompressionS3TCsRGB; + // GL_KHR_texture_compression_astc_hdr bool textureCompressionASTCHDR; @@ -188,9 +213,6 @@ struct Extensions // GL_NV_fence bool fence; - // GL_ANGLE_timer_query - bool timerQuery; - // GL_EXT_disjoint_timer_query bool disjointTimerQuery; GLuint queryCounterBitsTimeElapsed; @@ -199,6 +221,9 @@ struct Extensions // GL_EXT_robustness bool robustness; + // GL_KHR_robust_buffer_access_behavior + bool robustBufferAccessBehavior; + // GL_EXT_blend_minmax bool blendMinMax; @@ -220,18 +245,13 @@ struct Extensions // GL_EXT_shader_texture_lod bool shaderTextureLOD; - // GL_EXT_shader_framebuffer_fetch - bool shaderFramebufferFetch; - - // GL_ARM_shader_framebuffer_fetch - bool ARMshaderFramebufferFetch; - - // GL_NV_shader_framebuffer_fetch - bool NVshaderFramebufferFetch; - // GL_EXT_frag_depth bool fragDepth; + // ANGLE_multiview + bool multiview; + GLuint maxViews; + // GL_ANGLE_texture_usage bool textureUsage; @@ -256,6 +276,9 @@ struct Extensions // GL_OES_EGL_image_external_essl3 bool eglImageExternalEssl3; + // NV_EGL_stream_consumer_external + bool eglStreamConsumerExternal; + // EXT_unpack_subimage bool unpackSubimage; @@ -278,12 +301,98 @@ struct Extensions // GL_ANGLE_lossy_etc_decode bool lossyETCDecode; + // GL_CHROMIUM_bind_uniform_location + bool bindUniformLocation; + + // GL_CHROMIUM_sync_query + bool syncQuery; + + // GL_CHROMIUM_copy_texture + bool copyTexture; + + // GL_CHROMIUM_copy_compressed_texture + bool copyCompressedTexture; + + // GL_ANGLE_webgl_compatibility + bool webglCompatibility; + + // GL_ANGLE_request_extension + bool requestExtension; + + // GL_CHROMIUM_bind_generates_resource + bool bindGeneratesResource; + + // GL_ANGLE_robust_client_memory + bool robustClientMemory; + + // GL_EXT_texture_sRGB_decode + bool textureSRGBDecode; + + // GL_EXT_sRGB_write_control + bool sRGBWriteControl; + + // GL_CHROMIUM_color_buffer_float_rgb + bool colorBufferFloatRGB; + + // GL_CHROMIUM_color_buffer_float_rgba + bool colorBufferFloatRGBA; + // ES3 Extension support // GL_EXT_color_buffer_float bool colorBufferFloat; + + // GL_EXT_multisample_compatibility. + // written against ES 3.1 but can apply to earlier versions. + bool multisampleCompatibility; + + // GL_CHROMIUM_framebuffer_mixed_samples + bool framebufferMixedSamples; + + // GL_EXT_texture_norm16 + // written against ES 3.1 but can apply to ES 3.0 as well. + bool textureNorm16; + + // GL_CHROMIUM_path_rendering + bool pathRendering; + + // GL_OES_surfaceless_context + bool surfacelessContext; + + // GL_ANGLE_client_arrays + bool clientArrays; + + // GL_ANGLE_robust_resource_initialization + bool robustResourceInitialization; + + // GL_ANGLE_program_cache_control + bool programCacheControl; + + // GL_ANGLE_texture_rectangle + bool textureRectangle; + + // GL_EXT_geometry_shader + bool geometryShader; + // GL_EXT_geometry_shader (May 31, 2016) Table 20.43gs: Implementation dependent geometry shader + // limits + // TODO(jiawei.shao@intel.com): add all implementation dependent geometry shader limits. + GLuint maxGeometryOutputVertices; + GLuint maxGeometryShaderInvocations; }; +struct ExtensionInfo +{ + // If this extension can be enabled with glRequestExtension (GL_ANGLE_request_extension) + bool Requestable = false; + + // Pointer to a boolean member of the Extensions struct + typedef bool(Extensions::*ExtensionBool); + ExtensionBool ExtensionsMember = nullptr; +}; + +using ExtensionInfoMap = std::map; +const ExtensionInfoMap &GetExtensionInfoMap(); + struct Limitations { Limitations(); @@ -311,39 +420,57 @@ struct Limitations struct TypePrecision { TypePrecision(); + TypePrecision(const TypePrecision &other); void setIEEEFloat(); void setTwosComplementInt(unsigned int bits); + void setSimulatedFloat(unsigned int range, unsigned int precision); void setSimulatedInt(unsigned int range); void get(GLint *returnRange, GLint *returnPrecision) const; - GLint range[2]; + std::array range; GLint precision; }; struct Caps { Caps(); + Caps(const Caps &other); + ~Caps(); - // Table 6.28, implementation dependent values + // ES 3.1 (April 29, 2015) 20.39: implementation dependent values GLuint64 maxElementIndex; GLuint max3DTextureSize; GLuint max2DTextureSize; + GLuint maxRectangleTextureSize; GLuint maxArrayTextureLayers; GLfloat maxLODBias; GLuint maxCubeMapTextureSize; GLuint maxRenderbufferSize; - GLuint maxDrawBuffers; - GLuint maxColorAttachments; - GLuint maxViewportWidth; - GLuint maxViewportHeight; GLfloat minAliasedPointSize; GLfloat maxAliasedPointSize; GLfloat minAliasedLineWidth; GLfloat maxAliasedLineWidth; - // Table 6.29, implementation dependent values (cont.) + // ES 3.1 (April 29, 2015) 20.40: implementation dependent values (cont.) + GLuint maxDrawBuffers; + GLuint maxFramebufferWidth; + GLuint maxFramebufferHeight; + GLuint maxFramebufferSamples; + GLuint maxColorAttachments; + GLuint maxViewportWidth; + GLuint maxViewportHeight; + GLuint maxSampleMaskWords; + GLuint maxColorTextureSamples; + GLuint maxDepthTextureSamples; + GLuint maxIntegerSamples; + GLuint64 maxServerWaitTimeout; + + // ES 3.1 (April 29, 2015) Table 20.41: Implementation dependent values (cont.) + GLint maxVertexAttribRelativeOffset; + GLuint maxVertexAttribBindings; + GLint maxVertexAttribStride; GLuint maxElementsIndices; GLuint maxElementsVertices; std::vector compressedTextureFormats; @@ -361,26 +488,49 @@ struct Caps TypePrecision fragmentHighpInt; TypePrecision fragmentMediumpInt; TypePrecision fragmentLowpInt; - GLuint64 maxServerWaitTimeout; - // Table 6.31, implementation dependent vertex shader limits + // ES 3.1 (April 29, 2015) Table 20.43: Implementation dependent Vertex shader limits GLuint maxVertexAttributes; GLuint maxVertexUniformComponents; GLuint maxVertexUniformVectors; GLuint maxVertexUniformBlocks; GLuint maxVertexOutputComponents; GLuint maxVertexTextureImageUnits; + GLuint maxVertexAtomicCounterBuffers; + GLuint maxVertexAtomicCounters; + GLuint maxVertexImageUniforms; + GLuint maxVertexShaderStorageBlocks; - // Table 6.32, implementation dependent fragment shader limits + // ES 3.1 (April 29, 2015) Table 20.44: Implementation dependent Fragment shader limits GLuint maxFragmentUniformComponents; GLuint maxFragmentUniformVectors; GLuint maxFragmentUniformBlocks; GLuint maxFragmentInputComponents; GLuint maxTextureImageUnits; + GLuint maxFragmentAtomicCounterBuffers; + GLuint maxFragmentAtomicCounters; + GLuint maxFragmentImageUniforms; + GLuint maxFragmentShaderStorageBlocks; + GLint minProgramTextureGatherOffset; + GLuint maxProgramTextureGatherOffset; GLint minProgramTexelOffset; GLint maxProgramTexelOffset; - // Table 6.33, implementation dependent aggregate shader limits + // ES 3.1 (April 29, 2015) Table 20.45: implementation dependent compute shader limits + std::array maxComputeWorkGroupCount; + std::array maxComputeWorkGroupSize; + GLuint maxComputeWorkGroupInvocations; + GLuint maxComputeUniformBlocks; + GLuint maxComputeTextureImageUnits; + GLuint maxComputeSharedMemorySize; + GLuint maxComputeUniformComponents; + GLuint maxComputeAtomicCounterBuffers; + GLuint maxComputeAtomicCounters; + GLuint maxComputeImageUniforms; + GLuint maxCombinedComputeUniformComponents; + GLuint maxComputeShaderStorageBlocks; + + // ES 3.1 (April 29, 2015) Table 20.46: implementation dependent aggregate shader limits GLuint maxUniformBufferBindings; GLuint64 maxUniformBlockSize; GLuint uniformBufferOffsetAlignment; @@ -390,16 +540,31 @@ struct Caps GLuint maxVaryingComponents; GLuint maxVaryingVectors; GLuint maxCombinedTextureImageUnits; - - // Table 6.34, implementation dependent transform feedback limits + GLuint maxCombinedShaderOutputResources; + + // ES 3.1 (April 29, 2015) Table 20.47: implementation dependent aggregate shader limits (cont.) + GLuint maxUniformLocations; + GLuint maxAtomicCounterBufferBindings; + GLuint maxAtomicCounterBufferSize; + GLuint maxCombinedAtomicCounterBuffers; + GLuint maxCombinedAtomicCounters; + GLuint maxImageUnits; + GLuint maxCombinedImageUniforms; + GLuint maxShaderStorageBufferBindings; + GLuint64 maxShaderStorageBlockSize; + GLuint maxCombinedShaderStorageBlocks; + GLuint shaderStorageBufferOffsetAlignment; + + // ES 3.1 (April 29, 2015) Table 20.48: implementation dependent transform feedback limits GLuint maxTransformFeedbackInterleavedComponents; GLuint maxTransformFeedbackSeparateAttributes; GLuint maxTransformFeedbackSeparateComponents; - // Table 6.35, Framebuffer Dependent Values + // ES 3.1 (April 29, 2015) Table 20.49: Framebuffer Dependent Values GLuint maxSamples; }; +Caps GenerateMinimumCaps(const Version &clientVersion, const Extensions &extensions); } namespace egl @@ -426,6 +591,9 @@ struct DisplayExtensions // EGL_ANGLE_d3d_share_handle_client_buffer bool d3dShareHandleClientBuffer; + // EGL_ANGLE_d3d_texture_client_buffer + bool d3dTextureClientBuffer; + // EGL_ANGLE_surface_d3d_texture_2d_share_handle bool surfaceD3DTexture2DShareHandle; @@ -482,6 +650,48 @@ struct DisplayExtensions // KHR_create_context_no_error bool createContextNoError; + + // EGL_KHR_stream + bool stream; + + // EGL_KHR_stream_consumer_gltexture + bool streamConsumerGLTexture; + + // EGL_NV_stream_consumer_gltexture_yuv + bool streamConsumerGLTextureYUV; + + // EGL_ANGLE_stream_producer_d3d_texture_nv12 + bool streamProducerD3DTextureNV12; + + // EGL_ANGLE_create_context_webgl_compatibility + bool createContextWebGLCompatibility; + + // EGL_CHROMIUM_create_context_bind_generates_resource + bool createContextBindGeneratesResource; + + // EGL_CHROMIUM_get_sync_values + bool getSyncValues; + + // EGL_EXT_swap_buffers_with_damage + bool swapBuffersWithDamage; + + // EGL_EXT_pixel_format_float + bool pixelFormatFloat; + + // EGL_KHR_surfaceless_context + bool surfacelessContext; + + // EGL_ANGLE_display_texture_share_group + bool displayTextureShareGroup; + + // EGL_ANGLE_create_context_client_arrays + bool createContextClientArrays; + + // EGL_ANGLE_program_cache_control + bool programCacheControl; + + // EGL_ANGLE_robust_resource_initialization + bool robustResourceInitialization; }; struct DeviceExtensions @@ -498,6 +708,7 @@ struct DeviceExtensions struct ClientExtensions { ClientExtensions(); + ClientExtensions(const ClientExtensions &other); // Generate a vector of supported extension strings std::vector getStrings() const; @@ -520,6 +731,12 @@ struct ClientExtensions // EGL_ANGLE_platform_angle_opengl bool platformANGLEOpenGL; + // EGL_ANGLE_platform_angle_null + bool platformANGLENULL; + + // EGL_ANGLE_platform_angle_vulkan + bool platformANGLEVulkan; + // EGL_ANGLE_device_creation bool deviceCreation; @@ -536,6 +753,6 @@ struct ClientExtensions bool clientGetAllProcAddresses; }; -} +} // namespace egl #endif // LIBANGLE_CAPS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.cpp b/src/3rdparty/angle/src/libANGLE/Compiler.cpp index 348c41bef3..236c7e1fc2 100644 --- a/src/3rdparty/angle/src/libANGLE/Compiler.cpp +++ b/src/3rdparty/angle/src/libANGLE/Compiler.cpp @@ -9,9 +9,9 @@ #include "libANGLE/Compiler.h" #include "common/debug.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/renderer/CompilerImpl.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { @@ -19,26 +19,46 @@ namespace gl namespace { -// Global count of active shader compiler handles. Needed to know when to call ShInitialize and -// ShFinalize. +// Global count of active shader compiler handles. Needed to know when to call sh::Initialize and +// sh::Finalize. size_t activeCompilerHandles = 0; +ShShaderSpec SelectShaderSpec(GLint majorVersion, GLint minorVersion, bool isWebGL) +{ + if (majorVersion >= 3) + { + if (minorVersion == 1) + { + return isWebGL ? SH_WEBGL3_SPEC : SH_GLES3_1_SPEC; + } + else + { + return isWebGL ? SH_WEBGL2_SPEC : SH_GLES3_SPEC; + } + } + return isWebGL ? SH_WEBGL_SPEC : SH_GLES2_SPEC; +} + } // anonymous namespace -Compiler::Compiler(rx::ImplFactory *implFactory, const gl::Data &data) +Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state) : mImplementation(implFactory->createCompiler()), - mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC), + mSpec(SelectShaderSpec(state.getClientMajorVersion(), + state.getClientMinorVersion(), + state.getExtensions().webglCompatibility)), mOutputType(mImplementation->getTranslatorOutputType()), mResources(), mFragmentCompiler(nullptr), - mVertexCompiler(nullptr) + mVertexCompiler(nullptr), + mComputeCompiler(nullptr), + mGeometryCompiler(nullptr) { - ASSERT(data.clientVersion == 2 || data.clientVersion == 3); + ASSERT(state.getClientMajorVersion() == 2 || state.getClientMajorVersion() == 3); - const gl::Caps &caps = *data.caps; - const gl::Extensions &extensions = *data.extensions; + const gl::Caps &caps = state.getCaps(); + const gl::Extensions &extensions = state.getExtensions(); - ShInitBuiltInResources(&mResources); + sh::InitBuiltInResources(&mResources); mResources.MaxVertexAttribs = caps.maxVertexAttributes; mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; mResources.MaxVaryingVectors = caps.maxVaryingVectors; @@ -50,30 +70,79 @@ Compiler::Compiler(rx::ImplFactory *implFactory, const gl::Data &data) 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; + mResources.OES_EGL_image_external = extensions.eglImageExternal; + mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3; + mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal; + mResources.ARB_texture_rectangle = extensions.textureRectangle; // TODO: use shader precision caps to determine if high precision is supported? mResources.FragmentPrecisionHigh = 1; mResources.EXT_frag_depth = extensions.fragDepth; + // OVR_multiview state + mResources.OVR_multiview = extensions.multiview; + mResources.MaxViewsOVR = extensions.maxViews; + // 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() -{ - release(); - SafeDelete(mImplementation); + // GLSL ES 3.1 constants + mResources.MaxProgramTextureGatherOffset = caps.maxProgramTextureGatherOffset; + mResources.MinProgramTextureGatherOffset = caps.minProgramTextureGatherOffset; + mResources.MaxImageUnits = caps.maxImageUnits; + mResources.MaxVertexImageUniforms = caps.maxVertexImageUniforms; + mResources.MaxFragmentImageUniforms = caps.maxFragmentImageUniforms; + mResources.MaxComputeImageUniforms = caps.maxComputeImageUniforms; + mResources.MaxCombinedImageUniforms = caps.maxCombinedImageUniforms; + mResources.MaxCombinedShaderOutputResources = caps.maxCombinedShaderOutputResources; + mResources.MaxUniformLocations = caps.maxUniformLocations; + + for (size_t index = 0u; index < 3u; ++index) + { + mResources.MaxComputeWorkGroupCount[index] = caps.maxComputeWorkGroupCount[index]; + mResources.MaxComputeWorkGroupSize[index] = caps.maxComputeWorkGroupSize[index]; + } + + mResources.MaxComputeUniformComponents = caps.maxComputeUniformComponents; + mResources.MaxComputeTextureImageUnits = caps.maxComputeTextureImageUnits; + + mResources.MaxComputeAtomicCounters = caps.maxComputeAtomicCounters; + mResources.MaxComputeAtomicCounterBuffers = caps.maxComputeAtomicCounterBuffers; + + mResources.MaxVertexAtomicCounters = caps.maxVertexAtomicCounters; + mResources.MaxFragmentAtomicCounters = caps.maxFragmentAtomicCounters; + mResources.MaxCombinedAtomicCounters = caps.maxCombinedAtomicCounters; + mResources.MaxAtomicCounterBindings = caps.maxAtomicCounterBufferBindings; + mResources.MaxVertexAtomicCounterBuffers = caps.maxVertexAtomicCounterBuffers; + mResources.MaxFragmentAtomicCounterBuffers = caps.maxFragmentAtomicCounterBuffers; + mResources.MaxCombinedAtomicCounterBuffers = caps.maxCombinedAtomicCounterBuffers; + mResources.MaxAtomicCounterBufferSize = caps.maxAtomicCounterBufferSize; + + mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings; + mResources.MaxShaderStorageBufferBindings = caps.maxShaderStorageBufferBindings; + + // Needed by point size clamping workaround + mResources.MaxPointSize = caps.maxAliasedPointSize; + + if (state.getClientMajorVersion() == 2 && !extensions.drawBuffers) + { + mResources.MaxDrawBuffers = 1; + } + + // Geometry Shader constants + mResources.OES_geometry_shader = extensions.geometryShader; + // TODO(jiawei.shao@intel.com): initialize all implementation dependent geometry shader limits. + mResources.MaxGeometryOutputVertices = extensions.maxGeometryOutputVertices; + mResources.MaxGeometryShaderInvocations = extensions.maxGeometryShaderInvocations; } -Error Compiler::release() +Compiler::~Compiler() { if (mFragmentCompiler) { - ShDestruct(mFragmentCompiler); + sh::Destruct(mFragmentCompiler); mFragmentCompiler = nullptr; ASSERT(activeCompilerHandles > 0); @@ -82,21 +151,28 @@ Error Compiler::release() if (mVertexCompiler) { - ShDestruct(mVertexCompiler); + sh::Destruct(mVertexCompiler); mVertexCompiler = nullptr; ASSERT(activeCompilerHandles > 0); activeCompilerHandles--; } - if (activeCompilerHandles == 0) + if (mComputeCompiler) { - ShFinalize(); + sh::Destruct(mComputeCompiler); + mComputeCompiler = nullptr; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; } - mImplementation->release(); + if (activeCompilerHandles == 0) + { + sh::Finalize(); + } - return gl::Error(GL_NO_ERROR); + ANGLE_SWALLOW_ERR(mImplementation->release()); } ShHandle Compiler::getCompilerHandle(GLenum type) @@ -111,7 +187,12 @@ ShHandle Compiler::getCompilerHandle(GLenum type) case GL_FRAGMENT_SHADER: compiler = &mFragmentCompiler; break; - + case GL_COMPUTE_SHADER: + compiler = &mComputeCompiler; + break; + case GL_GEOMETRY_SHADER_EXT: + compiler = &mGeometryCompiler; + break; default: UNREACHABLE(); return nullptr; @@ -121,14 +202,20 @@ ShHandle Compiler::getCompilerHandle(GLenum type) { if (activeCompilerHandles == 0) { - ShInitialize(); + sh::Initialize(); } - *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources); + *compiler = sh::ConstructCompiler(type, mSpec, mOutputType, &mResources); + ASSERT(*compiler); activeCompilerHandles++; } return *compiler; } +const std::string &Compiler::getBuiltinResourcesString(GLenum type) +{ + return sh::GetBuiltInResourcesString(getCompilerHandle(type)); +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.h b/src/3rdparty/angle/src/libANGLE/Compiler.h index 8634e39a45..b7f7e9f31b 100644 --- a/src/3rdparty/angle/src/libANGLE/Compiler.h +++ b/src/3rdparty/angle/src/libANGLE/Compiler.h @@ -10,38 +10,40 @@ #ifndef LIBANGLE_COMPILER_H_ #define LIBANGLE_COMPILER_H_ -#include "libANGLE/Error.h" #include "GLSLANG/ShaderLang.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" namespace rx { class CompilerImpl; -class ImplFactory; +class GLImplFactory; } namespace gl { -struct Data; +class ContextState; -class Compiler final : angle::NonCopyable +class Compiler final : public RefCountObjectNoID { public: - Compiler(rx::ImplFactory *implFactory, const Data &data); - ~Compiler(); - - Error release(); + Compiler(rx::GLImplFactory *implFactory, const ContextState &data); ShHandle getCompilerHandle(GLenum type); ShShaderOutput getShaderOutputType() const { return mOutputType; } + const std::string &getBuiltinResourcesString(GLenum type); private: - rx::CompilerImpl *mImplementation; + ~Compiler() override; + std::unique_ptr mImplementation; ShShaderSpec mSpec; ShShaderOutput mOutputType; ShBuiltInResources mResources; ShHandle mFragmentCompiler; ShHandle mVertexCompiler; + ShHandle mComputeCompiler; + ShHandle mGeometryCompiler; }; } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Config.cpp b/src/3rdparty/angle/src/libANGLE/Config.cpp index d511df3a69..172c312ae0 100644 --- a/src/3rdparty/angle/src/libANGLE/Config.cpp +++ b/src/3rdparty/angle/src/libANGLE/Config.cpp @@ -58,10 +58,27 @@ Config::Config() transparentRedValue(0), transparentGreenValue(0), transparentBlueValue(0), - optimalOrientation(0) + optimalOrientation(0), + colorComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { } +Config::~Config() +{ +} + +Config::Config(const Config &other) = default; + +Config &Config::operator=(const Config &other) = default; + +ConfigSet::ConfigSet() = default; + +ConfigSet::ConfigSet(const ConfigSet &other) = default; + +ConfigSet &ConfigSet::operator=(const ConfigSet &other) = default; + +ConfigSet::~ConfigSet() = default; + 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) @@ -134,6 +151,10 @@ class ConfigSorter static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, "Unexpected EGL enum value."); SORT(configCaveat); + static_assert(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT < EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + "Unexpected order of EGL enums."); + SORT(colorComponentType); + static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value."); SORT(colorBufferType); @@ -160,6 +181,7 @@ class ConfigSorter } private: + void scanForWantedComponents(const AttributeMap &attributeMap) { // [EGL 1.5] section 3.4.1.2 page 30 @@ -215,8 +237,13 @@ std::vector ConfigSet::filter(const AttributeMap &attributeMap) c for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) { - EGLint attributeKey = attribIter->first; - EGLint attributeValue = attribIter->second; + EGLAttrib attributeKey = attribIter->first; + EGLAttrib attributeValue = attribIter->second; + + if (attributeValue == EGL_DONT_CARE) + { + continue; + } switch (attributeKey) { @@ -255,6 +282,9 @@ std::vector ConfigSet::filter(const AttributeMap &attributeMap) c case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: match = config.optimalOrientation == attributeValue; break; + case EGL_COLOR_COMPONENT_TYPE_EXT: + match = config.colorComponentType == static_cast(attributeValue); + break; default: UNREACHABLE(); } diff --git a/src/3rdparty/angle/src/libANGLE/Config.h b/src/3rdparty/angle/src/libANGLE/Config.h index 00f5673b59..f2fbe8b95a 100644 --- a/src/3rdparty/angle/src/libANGLE/Config.h +++ b/src/3rdparty/angle/src/libANGLE/Config.h @@ -27,6 +27,9 @@ namespace egl struct Config { Config(); + ~Config(); + Config(const Config &other); + Config &operator=(const Config &other); GLenum renderTargetFormat; // TODO(geofflang): remove this GLenum depthStencilFormat; // TODO(geofflang): remove this @@ -65,11 +68,17 @@ struct Config EGLint transparentGreenValue; // Transparent green value EGLint transparentBlueValue; // Transparent blue value EGLint optimalOrientation; // Optimal window surface orientation + EGLenum colorComponentType; // Color component type }; class ConfigSet { public: + ConfigSet(); + ConfigSet(const ConfigSet &other); + ~ConfigSet(); + ConfigSet &operator=(const ConfigSet &other); + EGLint add(const Config &config); const Config &get(EGLint id) const; @@ -83,7 +92,7 @@ class ConfigSet std::vector filter(const AttributeMap &attributeMap) const; private: - typedef std::map ConfigMap; + typedef std::map ConfigMap; ConfigMap mConfigs; }; diff --git a/src/3rdparty/angle/src/libANGLE/Constants.h b/src/3rdparty/angle/src/libANGLE/Constants.h index dc8f9555b8..2fe921af38 100644 --- a/src/3rdparty/angle/src/libANGLE/Constants.h +++ b/src/3rdparty/angle/src/libANGLE/Constants.h @@ -9,36 +9,54 @@ #ifndef LIBANGLE_CONSTANTS_H_ #define LIBANGLE_CONSTANTS_H_ +#include "common/platform.h" + namespace gl { +// The binary cache is currently left disable by default, and the application can enable it. +const size_t kDefaultMaxProgramCacheMemoryBytes = 0; + enum { - MAX_VERTEX_ATTRIBS = 16, + // Implementation upper limits, real maximums depend on the hardware + MAX_SAMPLE_MASK_WORDS = 2, + + MAX_VERTEX_ATTRIBS = 16, + MAX_VERTEX_ATTRIB_BINDINGS = 16, // Implementation upper limits, real maximums depend on the hardware IMPLEMENTATION_MAX_VARYING_VECTORS = 32, - IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, - IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers + IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = + IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers - IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, - IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + - IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, + // Maximum number of views which are supported by the implementation of ANGLE_multiview. + IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 4, + // These are the maximums the implementation can support // The actual GL caps are limited by the device caps // and should be queried from the Context - IMPLEMENTATION_MAX_2D_TEXTURE_SIZE = 16384, - IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, - IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, + IMPLEMENTATION_MAX_2D_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048, - IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE -}; + // 1+log2 of max of MAX_*_TEXTURE_SIZE + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15, + // Limit active textures so we can use fast bitsets. + IMPLEMENTATION_MAX_SHADER_TEXTURES = 32, + IMPLEMENTATION_MAX_ACTIVE_TEXTURES = IMPLEMENTATION_MAX_SHADER_TEXTURES * 2, +}; } #endif // LIBANGLE_CONSTANTS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp index 26f2970068..f638beda58 100644 --- a/src/3rdparty/angle/src/libANGLE/Context.cpp +++ b/src/3rdparty/angle/src/libANGLE/Context.cpp @@ -9,18 +9,24 @@ #include "libANGLE/Context.h" +#include #include #include +#include +#include "common/matrix_utils.h" #include "common/platform.h" #include "common/utilities.h" +#include "common/version.h" #include "libANGLE/Buffer.h" #include "libANGLE/Compiler.h" #include "libANGLE/Display.h" #include "libANGLE/Fence.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Path.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/Query.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/ResourceManager.h" @@ -29,36 +35,97 @@ #include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/Workarounds.h" #include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/queryutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/EGLImplFactory.h" +#include "libANGLE/renderer/Format.h" #include "libANGLE/validationES.h" -#include "libANGLE/renderer/Renderer.h" namespace { +#define ANGLE_HANDLE_ERR(X) \ + handleError(X); \ + return; +#define ANGLE_CONTEXT_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_HANDLE_ERR); + +template +std::vector GatherPaths(gl::PathManager &resourceManager, + GLsizei numPaths, + const void *paths, + GLuint pathBase) +{ + std::vector ret; + ret.reserve(numPaths); + + const auto *nameArray = static_cast(paths); + + for (GLsizei i = 0; i < numPaths; ++i) + { + const GLuint pathName = nameArray[i] + pathBase; + + ret.push_back(resourceManager.getPath(pathName)); + } + + return ret; +} + +std::vector GatherPaths(gl::PathManager &resourceManager, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase) +{ + switch (pathNameType) + { + case GL_UNSIGNED_BYTE: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_BYTE: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_UNSIGNED_SHORT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_SHORT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_UNSIGNED_INT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + + case GL_INT: + return GatherPaths(resourceManager, numPaths, paths, pathBase); + } + + UNREACHABLE(); + return std::vector(); +} + template -gl::Error GetQueryObjectParameter(gl::Context *context, GLuint id, GLenum pname, T *params) +gl::Error GetQueryObjectParameter(gl::Query *query, GLenum pname, T *params) { - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); - ASSERT(queryObject != nullptr); + ASSERT(query != nullptr); switch (pname) { case GL_QUERY_RESULT_EXT: - return queryObject->getResult(params); + return query->getResult(params); case GL_QUERY_RESULT_AVAILABLE_EXT: { bool available; - gl::Error error = queryObject->isResultAvailable(&available); + gl::Error error = query->isResultAvailable(&available); if (!error.isError()) { - *params = static_cast(available ? GL_TRUE : GL_FALSE); + *params = gl::CastFromStateValue(pname, static_cast(available)); } return error; } default: UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Unreachable Error"); + return gl::InternalError() << "Unreachable Error"; } } @@ -69,7 +136,7 @@ void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback) for (size_t tfBufferIndex = 0; tfBufferIndex < transformFeedback->getIndexedBufferCount(); tfBufferIndex++) { - const OffsetBindingPointer &buffer = + const gl::OffsetBindingPointer &buffer = transformFeedback->getIndexedBuffer(tfBufferIndex); if (buffer.get() != nullptr) { @@ -80,15 +147,25 @@ void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback) } // Attribute map queries. -EGLint GetClientVersion(const egl::AttributeMap &attribs) +EGLint GetClientMajorVersion(const egl::AttributeMap &attribs) +{ + return static_cast(attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1)); +} + +EGLint GetClientMinorVersion(const egl::AttributeMap &attribs) +{ + return static_cast(attribs.get(EGL_CONTEXT_MINOR_VERSION, 0)); +} + +gl::Version GetClientVersion(const egl::AttributeMap &attribs) { - return attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1); + return gl::Version(GetClientMajorVersion(attribs), GetClientMinorVersion(attribs)); } GLenum GetResetStrategy(const egl::AttributeMap &attribs) { - EGLenum attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, - EGL_NO_RESET_NOTIFICATION_EXT); + EGLAttrib attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, + EGL_NO_RESET_NOTIFICATION); switch (attrib) { case EGL_NO_RESET_NOTIFICATION: @@ -103,12 +180,15 @@ GLenum GetResetStrategy(const egl::AttributeMap &attribs) bool GetRobustAccess(const egl::AttributeMap &attribs) { - return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE); + return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE) || + ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != + 0); } bool GetDebug(const egl::AttributeMap &attribs) { - return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE); + return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE) || + ((attribs.get(EGL_CONTEXT_FLAGS_KHR, 0) & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) != 0); } bool GetNoError(const egl::AttributeMap &attribs) @@ -116,504 +196,657 @@ bool GetNoError(const egl::AttributeMap &attribs) return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE); } +bool GetWebGLContext(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE); +} + +bool GetBindGeneratesResource(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE) == EGL_TRUE); +} + +bool GetClientArraysEnabled(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE) == EGL_TRUE); +} + +bool GetRobustResourceInit(const egl::AttributeMap &attribs) +{ + return (attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); +} + +std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label) +{ + std::string labelName; + if (label != nullptr) + { + size_t labelLength = length < 0 ? strlen(label) : length; + labelName = std::string(label, labelLength); + } + return labelName; +} + +void GetObjectLabelBase(const std::string &objectLabel, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + size_t writeLength = objectLabel.length(); + if (label != nullptr && bufSize > 0) + { + writeLength = std::min(static_cast(bufSize) - 1, objectLabel.length()); + std::copy(objectLabel.begin(), objectLabel.begin() + writeLength, label); + label[writeLength] = '\0'; + } + + if (length != nullptr) + { + *length = static_cast(writeLength); + } +} + +template +void LimitCap(CapT *cap, MaxT maximum) +{ + *cap = std::min(*cap, static_cast(maximum)); +} + } // anonymous namespace namespace gl { -Context::Context(const egl::Config *config, +Context::Context(rx::EGLImplFactory *implFactory, + const egl::Config *config, const Context *shareContext, - rx::Renderer *renderer, - const egl::AttributeMap &attribs) - : ValidationContext(GetClientVersion(attribs), - mState, + TextureManager *shareTextures, + MemoryProgramCache *memoryProgramCache, + const egl::AttributeMap &attribs, + const egl::DisplayExtensions &displayExtensions) + + : ValidationContext(shareContext, + shareTextures, + GetClientVersion(attribs), + &mGLState, mCaps, mTextureCaps, mExtensions, - nullptr, mLimitations, GetNoError(attribs)), - mCompiler(nullptr), - mRenderer(renderer), - mClientVersion(GetClientVersion(attribs)), + mImplementation(implFactory->createContext(mState)), + mCompiler(), mConfig(config), mClientType(EGL_OPENGL_ES_API), mHasBeenCurrent(false), mContextLost(false), mResetStatus(GL_NO_ERROR), + mContextLostForced(false), mResetStrategy(GetResetStrategy(attribs)), mRobustAccess(GetRobustAccess(attribs)), - mCurrentSurface(nullptr), - mResourceManager(nullptr) + mCurrentSurface(static_cast(EGL_NO_SURFACE)), + mCurrentDisplay(static_cast(EGL_NO_DISPLAY)), + mSurfacelessFramebuffer(nullptr), + mWebGLContext(GetWebGLContext(attribs)), + mMemoryProgramCache(memoryProgramCache), + mScratchBuffer(1000u), + mZeroFilledBuffer(1000u) { - ASSERT(!mRobustAccess); // Unimplemented + mImplementation->setMemoryProgramCache(memoryProgramCache); - initCaps(mClientVersion); + bool robustResourceInit = GetRobustResourceInit(attribs); + initCaps(displayExtensions, robustResourceInit); + initWorkarounds(); - mState.initialize(mCaps, mExtensions, mClientVersion, GetDebug(attribs)); + mGLState.initialize(this, GetDebug(attribs), GetBindGeneratesResource(attribs), + GetClientArraysEnabled(attribs), robustResourceInit, + mMemoryProgramCache != nullptr); mFenceNVHandleAllocator.setBaseHandle(0); - if (shareContext != NULL) - { - mResourceManager = shareContext->mResourceManager; - mResourceManager->addRef(); - } - else - { - 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 + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have two-dimensional // and cube map texture state vectors respectively associated with them. // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0. - Texture *zeroTexture2D = new Texture(mRenderer->createTexture(GL_TEXTURE_2D), 0, GL_TEXTURE_2D); - mZeroTextures[GL_TEXTURE_2D].set(zeroTexture2D); + Texture *zeroTexture2D = new Texture(mImplementation.get(), 0, GL_TEXTURE_2D); + mZeroTextures[GL_TEXTURE_2D].set(this, zeroTexture2D); - Texture *zeroTextureCube = new Texture(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0, GL_TEXTURE_CUBE_MAP); - mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); + Texture *zeroTextureCube = new Texture(mImplementation.get(), 0, GL_TEXTURE_CUBE_MAP); + mZeroTextures[GL_TEXTURE_CUBE_MAP].set(this, zeroTextureCube); - if (mClientVersion >= 3) + if (getClientVersion() >= Version(3, 0)) { // TODO: These could also be enabled via extension - Texture *zeroTexture3D = new Texture(mRenderer->createTexture(GL_TEXTURE_3D), 0, GL_TEXTURE_3D); - mZeroTextures[GL_TEXTURE_3D].set(zeroTexture3D); + Texture *zeroTexture3D = new Texture(mImplementation.get(), 0, GL_TEXTURE_3D); + mZeroTextures[GL_TEXTURE_3D].set(this, zeroTexture3D); - Texture *zeroTexture2DArray = new Texture(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0, GL_TEXTURE_2D_ARRAY); - mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); + Texture *zeroTexture2DArray = new Texture(mImplementation.get(), 0, GL_TEXTURE_2D_ARRAY); + mZeroTextures[GL_TEXTURE_2D_ARRAY].set(this, zeroTexture2DArray); } + if (getClientVersion() >= Version(3, 1)) + { + Texture *zeroTexture2DMultisample = + new Texture(mImplementation.get(), 0, GL_TEXTURE_2D_MULTISAMPLE); + mZeroTextures[GL_TEXTURE_2D_MULTISAMPLE].set(this, zeroTexture2DMultisample); - mState.initializeZeroTextures(mZeroTextures); + for (unsigned int i = 0; i < mCaps.maxAtomicCounterBufferBindings; i++) + { + bindBufferRange(BufferBinding::AtomicCounter, 0, i, 0, 0); + } - bindVertexArray(0); - bindArrayBuffer(0); - bindElementArrayBuffer(0); + for (unsigned int i = 0; i < mCaps.maxShaderStorageBufferBindings; i++) + { + bindBufferRange(BufferBinding::ShaderStorage, i, 0, 0, 0); + } + } - bindRenderbuffer(0); + const Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + if (nativeExtensions.textureRectangle) + { + Texture *zeroTextureRectangle = + new Texture(mImplementation.get(), 0, GL_TEXTURE_RECTANGLE_ANGLE); + mZeroTextures[GL_TEXTURE_RECTANGLE_ANGLE].set(this, zeroTextureRectangle); + } - bindGenericUniformBuffer(0); - for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) + if (nativeExtensions.eglImageExternal || nativeExtensions.eglStreamConsumerExternal) { - bindIndexedUniformBuffer(0, i, 0, -1); + Texture *zeroTextureExternal = + new Texture(mImplementation.get(), 0, GL_TEXTURE_EXTERNAL_OES); + mZeroTextures[GL_TEXTURE_EXTERNAL_OES].set(this, zeroTextureExternal); } - bindCopyReadBuffer(0); - bindCopyWriteBuffer(0); - bindPixelPackBuffer(0); - bindPixelUnpackBuffer(0); + mGLState.initializeZeroTextures(this, mZeroTextures); - if (mClientVersion >= 3) + bindVertexArray(0); + + if (getClientVersion() >= Version(3, 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 - bindTransformFeedback(0); + bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); } - mCompiler = new Compiler(mRenderer, getData()); -} + for (auto type : angle::AllEnums()) + { + bindBuffer(type, 0); + } -Context::~Context() -{ - mState.reset(); + bindRenderbuffer(GL_RENDERBUFFER, 0); - for (auto framebuffer : mFramebufferMap) + for (unsigned int i = 0; i < mCaps.maxUniformBufferBindings; i++) { - // Default framebuffer are owned by their respective Surface - if (framebuffer.second != nullptr && framebuffer.second->id() != 0) - { - SafeDelete(framebuffer.second); - } + bindBufferRange(BufferBinding::Uniform, i, 0, 0, -1); } + // Initialize dirty bit masks + mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_STATE); + mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_BUFFER_BINDING); + // No dirty objects. + + // Readpixels uses the pack state and read FBO + mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_STATE); + mReadPixelsDirtyBits.set(State::DIRTY_BIT_PACK_BUFFER_BINDING); + mReadPixelsDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER); + + mClearDirtyBits.set(State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED); + mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED); + mClearDirtyBits.set(State::DIRTY_BIT_SCISSOR); + mClearDirtyBits.set(State::DIRTY_BIT_VIEWPORT); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_COLOR); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_DEPTH); + mClearDirtyBits.set(State::DIRTY_BIT_CLEAR_STENCIL); + mClearDirtyBits.set(State::DIRTY_BIT_COLOR_MASK); + mClearDirtyBits.set(State::DIRTY_BIT_DEPTH_MASK); + mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + mClearDirtyBits.set(State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); + mClearDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); + + mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR_TEST_ENABLED); + mBlitDirtyBits.set(State::DIRTY_BIT_SCISSOR); + mBlitDirtyBits.set(State::DIRTY_BIT_FRAMEBUFFER_SRGB); + mBlitDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER); + mBlitDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); + + handleError(mImplementation->initialize()); +} + +egl::Error Context::onDestroy(const egl::Display *display) +{ for (auto fence : mFenceNVMap) { SafeDelete(fence.second); } + mFenceNVMap.clear(); for (auto query : mQueryMap) { if (query.second != nullptr) { - query.second->release(); + query.second->release(this); } } + mQueryMap.clear(); for (auto vertexArray : mVertexArrayMap) { - SafeDelete(vertexArray.second); + if (vertexArray.second) + { + vertexArray.second->onDestroy(this); + } } + mVertexArrayMap.clear(); for (auto transformFeedback : mTransformFeedbackMap) { if (transformFeedback.second != nullptr) { - transformFeedback.second->release(); + transformFeedback.second->release(this); } } + mTransformFeedbackMap.clear(); for (auto &zeroTexture : mZeroTextures) { - zeroTexture.second.set(NULL); + ANGLE_TRY(zeroTexture.second->onDestroy(this)); + zeroTexture.second.set(this, nullptr); } mZeroTextures.clear(); - if (mCurrentSurface != nullptr) - { - releaseSurface(); - } + SafeDelete(mSurfacelessFramebuffer); - if (mResourceManager) - { - mResourceManager->release(); - } + ANGLE_TRY(releaseSurface(display)); + releaseShaderCompiler(); + + mGLState.reset(this); - SafeDelete(mCompiler); + mState.mBuffers->release(this); + mState.mShaderPrograms->release(this); + mState.mTextures->release(this); + mState.mRenderbuffers->release(this); + mState.mSamplers->release(this); + mState.mSyncs->release(this); + mState.mPaths->release(this); + mState.mFramebuffers->release(this); + mState.mPipelines->release(this); + + mImplementation->onDestroy(this); + + return egl::NoError(); +} + +Context::~Context() +{ } -void Context::makeCurrent(egl::Surface *surface) +egl::Error Context::makeCurrent(egl::Display *display, egl::Surface *surface) { - ASSERT(surface != nullptr); + mCurrentDisplay = display; if (!mHasBeenCurrent) { initRendererString(); + initVersionStrings(); initExtensionStrings(); - mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); - mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); + int width = 0; + int height = 0; + if (surface != nullptr) + { + width = surface->getWidth(); + height = surface->getHeight(); + } + + mGLState.setViewportParams(0, 0, width, height); + mGLState.setScissorParams(0, 0, width, height); mHasBeenCurrent = true; } // TODO(jmadill): Rework this when we support ContextImpl - mState.setAllDirtyBits(); + mGLState.setAllDirtyBits(); + mGLState.setAllDirtyObjects(); - if (mCurrentSurface) + ANGLE_TRY(releaseSurface(display)); + + Framebuffer *newDefault = nullptr; + if (surface != nullptr) + { + ANGLE_TRY(surface->setIsCurrent(this, true)); + mCurrentSurface = surface; + newDefault = surface->getDefaultFramebuffer(); + } + else { - releaseSurface(); + if (mSurfacelessFramebuffer == nullptr) + { + mSurfacelessFramebuffer = new Framebuffer(mImplementation.get()); + } + + newDefault = mSurfacelessFramebuffer; } - 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) + if (mGLState.getReadFramebuffer() == nullptr) { - mState.setReadFramebufferBinding(newDefault); + mGLState.setReadFramebufferBinding(newDefault); } - if (mState.getDrawFramebuffer() == nullptr) + if (mGLState.getDrawFramebuffer() == nullptr) { - mState.setDrawFramebufferBinding(newDefault); + mGLState.setDrawFramebufferBinding(newDefault); } - mFramebufferMap[0] = newDefault; + mState.mFramebuffers->setDefaultFramebuffer(newDefault); } // Notify the renderer of a context switch - mRenderer->onMakeCurrent(getData()); + mImplementation->onMakeCurrent(this); + return egl::NoError(); } -void Context::releaseSurface() +egl::Error Context::releaseSurface(const egl::Display *display) { - ASSERT(mCurrentSurface != nullptr); - // Remove the default framebuffer + Framebuffer *currentDefault = nullptr; + if (mCurrentSurface != nullptr) { - Framebuffer *currentDefault = mCurrentSurface->getDefaultFramebuffer(); - if (mState.getReadFramebuffer() == currentDefault) - { - mState.setReadFramebufferBinding(nullptr); - } - if (mState.getDrawFramebuffer() == currentDefault) - { - mState.setDrawFramebufferBinding(nullptr); - } - mFramebufferMap.erase(0); + currentDefault = mCurrentSurface->getDefaultFramebuffer(); + } + else if (mSurfacelessFramebuffer != nullptr) + { + currentDefault = mSurfacelessFramebuffer; } - mCurrentSurface->setIsCurrent(false); - mCurrentSurface = nullptr; -} + if (mGLState.getReadFramebuffer() == currentDefault) + { + mGLState.setReadFramebufferBinding(nullptr); + } + if (mGLState.getDrawFramebuffer() == currentDefault) + { + mGLState.setDrawFramebufferBinding(nullptr); + } + mState.mFramebuffers->setDefaultFramebuffer(nullptr); -// NOTE: this function should not assume that this context is current! -void Context::markContextLost() -{ - if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) - mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; - mContextLost = true; -} + if (mCurrentSurface) + { + ANGLE_TRY(mCurrentSurface->setIsCurrent(this, false)); + mCurrentSurface = nullptr; + } -bool Context::isContextLost() -{ - return mContextLost; + return egl::NoError(); } GLuint Context::createBuffer() { - return mResourceManager->createBuffer(); + return mState.mBuffers->createBuffer(); } GLuint Context::createProgram() { - return mResourceManager->createProgram(); + return mState.mShaderPrograms->createProgram(mImplementation.get()); } GLuint Context::createShader(GLenum type) { - return mResourceManager->createShader(mRenderer->getRendererLimitations(), type); + return mState.mShaderPrograms->createShader(mImplementation.get(), mLimitations, type); } GLuint Context::createTexture() { - return mResourceManager->createTexture(); + return mState.mTextures->createTexture(); } GLuint Context::createRenderbuffer() { - return mResourceManager->createRenderbuffer(); -} - -GLsync Context::createFenceSync() -{ - GLuint handle = mResourceManager->createFenceSync(); - - return reinterpret_cast(static_cast(handle)); -} - -GLuint Context::createVertexArray() -{ - GLuint vertexArray = mVertexArrayHandleAllocator.allocate(); - mVertexArrayMap[vertexArray] = nullptr; - return vertexArray; -} - -GLuint Context::createSampler() -{ - return mResourceManager->createSampler(); + return mState.mRenderbuffers->createRenderbuffer(); } -GLuint Context::createTransformFeedback() +GLuint Context::createPaths(GLsizei range) { - GLuint transformFeedback = mTransformFeedbackAllocator.allocate(); - mTransformFeedbackMap[transformFeedback] = nullptr; - return transformFeedback; + auto resultOrError = mState.mPaths->createPaths(mImplementation.get(), range); + if (resultOrError.isError()) + { + handleError(resultOrError.getError()); + return 0; + } + return resultOrError.getResult(); } // Returns an unused framebuffer name GLuint Context::createFramebuffer() { - GLuint handle = mFramebufferHandleAllocator.allocate(); - - mFramebufferMap[handle] = NULL; - - return handle; + return mState.mFramebuffers->createFramebuffer(); } GLuint Context::createFenceNV() { GLuint handle = mFenceNVHandleAllocator.allocate(); - - mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); - + mFenceNVMap.assign(handle, new FenceNV(mImplementation->createFenceNV())); return handle; } -// Returns an unused query name -GLuint Context::createQuery() +GLuint Context::createProgramPipeline() { - GLuint handle = mQueryHandleAllocator.allocate(); - - mQueryMap[handle] = NULL; + return mState.mPipelines->createProgramPipeline(); +} - return handle; +GLuint Context::createShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings) +{ + UNIMPLEMENTED(); + return 0u; } void Context::deleteBuffer(GLuint buffer) { - if (mResourceManager->getBuffer(buffer)) + if (mState.mBuffers->getBuffer(buffer)) { detachBuffer(buffer); } - mResourceManager->deleteBuffer(buffer); + mState.mBuffers->deleteObject(this, buffer); } void Context::deleteShader(GLuint shader) { - mResourceManager->deleteShader(shader); + mState.mShaderPrograms->deleteShader(this, shader); } void Context::deleteProgram(GLuint program) { - mResourceManager->deleteProgram(program); + mState.mShaderPrograms->deleteProgram(this, program); } void Context::deleteTexture(GLuint texture) { - if (mResourceManager->getTexture(texture)) + if (mState.mTextures->getTexture(texture)) { detachTexture(texture); } - mResourceManager->deleteTexture(texture); + mState.mTextures->deleteObject(this, texture); } void Context::deleteRenderbuffer(GLuint renderbuffer) { - if (mResourceManager->getRenderbuffer(renderbuffer)) + if (mState.mRenderbuffers->getRenderbuffer(renderbuffer)) { detachRenderbuffer(renderbuffer); } - mResourceManager->deleteRenderbuffer(renderbuffer); + mState.mRenderbuffers->deleteObject(this, renderbuffer); } -void Context::deleteFenceSync(GLsync fenceSync) +void Context::deleteSync(GLsync sync) { // The spec specifies the underlying Fence object is not deleted until all current // 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(static_cast(reinterpret_cast(fenceSync))); + mState.mSyncs->deleteObject(this, static_cast(reinterpret_cast(sync))); } -void Context::deleteVertexArray(GLuint vertexArray) +void Context::deleteProgramPipeline(GLuint pipeline) { - auto iter = mVertexArrayMap.find(vertexArray); - if (iter != mVertexArrayMap.end()) + if (mState.mPipelines->getProgramPipeline(pipeline)) { - VertexArray *vertexArrayObject = iter->second; - if (vertexArrayObject != nullptr) - { - detachVertexArray(vertexArray); - delete vertexArrayObject; - } - - mVertexArrayMap.erase(iter); - mVertexArrayHandleAllocator.release(vertexArray); + detachProgramPipeline(pipeline); } + + mState.mPipelines->deleteObject(this, pipeline); } -void Context::deleteSampler(GLuint sampler) +void Context::deletePaths(GLuint first, GLsizei range) { - if (mResourceManager->getSampler(sampler)) - { - detachSampler(sampler); - } - - mResourceManager->deleteSampler(sampler); + mState.mPaths->deletePaths(first, range); } -void Context::deleteTransformFeedback(GLuint transformFeedback) +bool Context::hasPathData(GLuint path) const { - auto iter = mTransformFeedbackMap.find(transformFeedback); - if (iter != mTransformFeedbackMap.end()) - { - TransformFeedback *transformFeedbackObject = iter->second; - if (transformFeedbackObject != nullptr) - { - detachTransformFeedback(transformFeedback); - transformFeedbackObject->release(); - } + const auto *pathObj = mState.mPaths->getPath(path); + if (pathObj == nullptr) + return false; - mTransformFeedbackMap.erase(iter); - mTransformFeedbackAllocator.release(transformFeedback); - } + return pathObj->hasPathData(); } -void Context::deleteFramebuffer(GLuint framebuffer) +bool Context::hasPath(GLuint path) const { - FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + return mState.mPaths->hasPath(path); +} - if (framebufferObject != mFramebufferMap.end()) - { - detachFramebuffer(framebuffer); +void Context::setPathCommands(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + auto *pathObject = mState.mPaths->getPath(path); - mFramebufferHandleAllocator.release(framebufferObject->first); - delete framebufferObject->second; - mFramebufferMap.erase(framebufferObject); - } + handleError(pathObject->setCommands(numCommands, commands, numCoords, coordType, coords)); } -void Context::deleteFenceNV(GLuint fence) +void Context::setPathParameterf(GLuint path, GLenum pname, GLfloat value) { - FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + auto *pathObj = mState.mPaths->getPath(path); - if (fenceObject != mFenceNVMap.end()) + switch (pname) { - mFenceNVHandleAllocator.release(fenceObject->first); - delete fenceObject->second; - mFenceNVMap.erase(fenceObject); + case GL_PATH_STROKE_WIDTH_CHROMIUM: + pathObj->setStrokeWidth(value); + break; + case GL_PATH_END_CAPS_CHROMIUM: + pathObj->setEndCaps(static_cast(value)); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + pathObj->setJoinStyle(static_cast(value)); + break; + case GL_PATH_MITER_LIMIT_CHROMIUM: + pathObj->setMiterLimit(value); + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + pathObj->setStrokeBound(value); + break; + default: + UNREACHABLE(); + break; } } -void Context::deleteQuery(GLuint query) +void Context::getPathParameterfv(GLuint path, GLenum pname, GLfloat *value) const { - QueryMap::iterator queryObject = mQueryMap.find(query); - if (queryObject != mQueryMap.end()) + const auto *pathObj = mState.mPaths->getPath(path); + + switch (pname) { - mQueryHandleAllocator.release(queryObject->first); - if (queryObject->second) - { - queryObject->second->release(); - } - mQueryMap.erase(queryObject); + case GL_PATH_STROKE_WIDTH_CHROMIUM: + *value = pathObj->getStrokeWidth(); + break; + case GL_PATH_END_CAPS_CHROMIUM: + *value = static_cast(pathObj->getEndCaps()); + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + *value = static_cast(pathObj->getJoinStyle()); + break; + case GL_PATH_MITER_LIMIT_CHROMIUM: + *value = pathObj->getMiterLimit(); + break; + case GL_PATH_STROKE_BOUND_CHROMIUM: + *value = pathObj->getStrokeBound(); + break; + default: + UNREACHABLE(); + break; } } -Buffer *Context::getBuffer(GLuint handle) const +void Context::setPathStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + mGLState.setPathStencilFunc(func, ref, mask); +} + +void Context::deleteFramebuffer(GLuint framebuffer) { - return mResourceManager->getBuffer(handle); + if (mState.mFramebuffers->getFramebuffer(framebuffer)) + { + detachFramebuffer(framebuffer); + } + + mState.mFramebuffers->deleteObject(this, framebuffer); } -Shader *Context::getShader(GLuint handle) const +void Context::deleteFenceNV(GLuint fence) { - return mResourceManager->getShader(handle); + FenceNV *fenceObject = nullptr; + if (mFenceNVMap.erase(fence, &fenceObject)) + { + mFenceNVHandleAllocator.release(fence); + delete fenceObject; + } } -Program *Context::getProgram(GLuint handle) const +Buffer *Context::getBuffer(GLuint handle) const { - return mResourceManager->getProgram(handle); + return mState.mBuffers->getBuffer(handle); } Texture *Context::getTexture(GLuint handle) const { - return mResourceManager->getTexture(handle); + return mState.mTextures->getTexture(handle); } Renderbuffer *Context::getRenderbuffer(GLuint handle) const { - return mResourceManager->getRenderbuffer(handle); + return mState.mRenderbuffers->getRenderbuffer(handle); } -FenceSync *Context::getFenceSync(GLsync handle) const +Sync *Context::getSync(GLsync handle) const { - return mResourceManager->getFenceSync(static_cast(reinterpret_cast(handle))); + return mState.mSyncs->getSync(static_cast(reinterpret_cast(handle))); } VertexArray *Context::getVertexArray(GLuint handle) const { - auto vertexArray = mVertexArrayMap.find(handle); - return (vertexArray != mVertexArrayMap.end()) ? vertexArray->second : nullptr; + return mVertexArrayMap.query(handle); } Sampler *Context::getSampler(GLuint handle) const { - return mResourceManager->getSampler(handle); + return mState.mSamplers->getSampler(handle); } TransformFeedback *Context::getTransformFeedback(GLuint handle) const { - auto iter = mTransformFeedbackMap.find(handle); - return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr; + return mTransformFeedbackMap.query(handle); +} + +ProgramPipeline *Context::getProgramPipeline(GLuint handle) const +{ + return mState.mPipelines->getProgramPipeline(handle); } LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const @@ -648,31 +881,64 @@ LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const { - return getFenceSync(reinterpret_cast(const_cast(ptr))); + return getSync(reinterpret_cast(const_cast(ptr))); } -bool Context::isSampler(GLuint samplerName) const +void Context::objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +{ + LabeledObject *object = getLabeledObject(identifier, name); + ASSERT(object != nullptr); + + std::string labelName = GetObjectLabelFromPointer(length, label); + object->setLabel(labelName); + + // TODO(jmadill): Determine if the object is dirty based on 'name'. Conservatively assume the + // specified object is active until we do this. + mGLState.setObjectDirty(identifier); +} + +void Context::objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label) { - return mResourceManager->isSampler(samplerName); + LabeledObject *object = getLabeledObjectFromPtr(ptr); + ASSERT(object != nullptr); + + std::string labelName = GetObjectLabelFromPointer(length, label); + object->setLabel(labelName); } -void Context::bindArrayBuffer(unsigned int buffer) +void Context::getObjectLabel(GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const { - mResourceManager->checkBufferAllocation(buffer); + LabeledObject *object = getLabeledObject(identifier, name); + ASSERT(object != nullptr); - mState.setArrayBufferBinding(getBuffer(buffer)); + const std::string &objectLabel = object->getLabel(); + GetObjectLabelBase(objectLabel, bufSize, length, label); } -void Context::bindElementArrayBuffer(unsigned int buffer) +void Context::getObjectPtrLabel(const void *ptr, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const { - mResourceManager->checkBufferAllocation(buffer); + LabeledObject *object = getLabeledObjectFromPtr(ptr); + ASSERT(object != nullptr); - mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); + const std::string &objectLabel = object->getLabel(); + GetObjectLabelBase(objectLabel, bufSize, length, label); +} + +bool Context::isSampler(GLuint samplerName) const +{ + return mState.mSamplers->isSampler(samplerName); } void Context::bindTexture(GLenum target, GLuint handle) { - Texture *texture = NULL; + Texture *texture = nullptr; if (handle == 0) { @@ -680,164 +946,126 @@ void Context::bindTexture(GLenum target, GLuint handle) } else { - mResourceManager->checkTextureAllocation(handle, target); - texture = getTexture(handle); + texture = mState.mTextures->checkTextureAllocation(mImplementation.get(), handle, target); } ASSERT(texture); - - mState.setSamplerTexture(target, texture); + mGLState.setSamplerTexture(this, target, texture); } void Context::bindReadFramebuffer(GLuint framebufferHandle) { - Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle); - mState.setReadFramebufferBinding(framebuffer); + Framebuffer *framebuffer = mState.mFramebuffers->checkFramebufferAllocation( + mImplementation.get(), mCaps, framebufferHandle); + mGLState.setReadFramebufferBinding(framebuffer); } void Context::bindDrawFramebuffer(GLuint framebufferHandle) { - Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle); - mState.setDrawFramebufferBinding(framebuffer); + Framebuffer *framebuffer = mState.mFramebuffers->checkFramebufferAllocation( + mImplementation.get(), mCaps, framebufferHandle); + mGLState.setDrawFramebufferBinding(framebuffer); } -void Context::bindRenderbuffer(GLuint renderbuffer) +void Context::bindVertexArray(GLuint vertexArrayHandle) { - mResourceManager->checkRenderbufferAllocation(renderbuffer); - - mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); + VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle); + mGLState.setVertexArrayBinding(vertexArray); } -void Context::bindVertexArray(GLuint vertexArray) +void Context::bindVertexBuffer(GLuint bindingIndex, + GLuint bufferHandle, + GLintptr offset, + GLsizei stride) { - checkVertexArrayAllocation(vertexArray); - - mState.setVertexArrayBinding(getVertexArray(vertexArray)); + Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle); + mGLState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride); } -void Context::bindSampler(GLuint textureUnit, GLuint sampler) +void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle) { ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); - mResourceManager->checkSamplerAllocation(sampler); - - mState.setSamplerBinding(textureUnit, getSampler(sampler)); + Sampler *sampler = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), samplerHandle); + mGLState.setSamplerBinding(this, textureUnit, sampler); } -void Context::bindGenericUniformBuffer(GLuint buffer) +void Context::bindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setGenericUniformBufferBinding(getBuffer(buffer)); + Texture *tex = mState.mTextures->getTexture(texture); + mGLState.setImageUnit(this, unit, tex, level, layered, layer, access, format); } -void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +void Context::useProgram(GLuint program) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); + mGLState.setProgram(this, getProgram(program)); } -void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) +void Context::useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) { - mResourceManager->checkBufferAllocation(buffer); - - mState.getCurrentTransformFeedback()->bindGenericBuffer(getBuffer(buffer)); + UNIMPLEMENTED(); } -void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +void Context::bindTransformFeedback(GLenum target, GLuint transformFeedbackHandle) { - mResourceManager->checkBufferAllocation(buffer); - - mState.getCurrentTransformFeedback()->bindIndexedBuffer(index, getBuffer(buffer), offset, size); + ASSERT(target == GL_TRANSFORM_FEEDBACK); + TransformFeedback *transformFeedback = + checkTransformFeedbackAllocation(transformFeedbackHandle); + mGLState.setTransformFeedbackBinding(this, transformFeedback); } -void Context::bindCopyReadBuffer(GLuint buffer) +void Context::bindProgramPipeline(GLuint pipelineHandle) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyReadBufferBinding(getBuffer(buffer)); + ProgramPipeline *pipeline = + mState.mPipelines->checkProgramPipelineAllocation(mImplementation.get(), pipelineHandle); + mGLState.setProgramPipelineBinding(this, pipeline); } -void Context::bindCopyWriteBuffer(GLuint buffer) +void Context::beginQuery(GLenum target, GLuint query) { - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyWriteBufferBinding(getBuffer(buffer)); -} + Query *queryObject = getQuery(query, true, target); + ASSERT(queryObject); -void Context::bindPixelPackBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); + // begin query + ANGLE_CONTEXT_TRY(queryObject->begin()); - mState.setPixelPackBufferBinding(getBuffer(buffer)); + // set query as active for specified target only if begin succeeded + mGLState.setActiveQuery(this, target, queryObject); } -void Context::bindPixelUnpackBuffer(GLuint buffer) +void Context::endQuery(GLenum target) { - mResourceManager->checkBufferAllocation(buffer); + Query *queryObject = mGLState.getActiveQuery(target); + ASSERT(queryObject); - mState.setPixelUnpackBufferBinding(getBuffer(buffer)); -} + handleError(queryObject->end()); -void Context::useProgram(GLuint program) -{ - mState.setProgram(getProgram(program)); + // Always unbind the query, even if there was an error. This may delete the query object. + mGLState.setActiveQuery(this, target, nullptr); } -void Context::bindTransformFeedback(GLuint transformFeedback) +void Context::queryCounter(GLuint id, GLenum target) { - checkTransformFeedbackAllocation(transformFeedback); + ASSERT(target == GL_TIMESTAMP_EXT); + + Query *queryObject = getQuery(id, true, target); + ASSERT(queryObject); - mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); + handleError(queryObject->queryCounter()); } -Error Context::beginQuery(GLenum target, GLuint query) -{ - Query *queryObject = getQuery(query, true, target); - ASSERT(queryObject); - - // begin query - Error error = queryObject->begin(); - if (error.isError()) - { - return error; - } - - // set query as active for specified target only if begin succeeded - mState.setActiveQuery(target, queryObject); - - return Error(GL_NO_ERROR); -} - -Error Context::endQuery(GLenum target) -{ - Query *queryObject = mState.getActiveQuery(target); - ASSERT(queryObject); - - gl::Error error = queryObject->end(); - - // Always unbind the query, even if there was an error. This may delete the query object. - mState.setActiveQuery(target, NULL); - - return error; -} - -Error Context::queryCounter(GLuint id, GLenum target) -{ - ASSERT(target == GL_TIMESTAMP_EXT); - - Query *queryObject = getQuery(id, true, target); - ASSERT(queryObject); - - return queryObject->queryCounter(); -} - -void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) +void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) { switch (pname) { case GL_CURRENT_QUERY_EXT: - params[0] = getState().getActiveQueryId(target); + params[0] = mGLState.getActiveQueryId(target); break; case GL_QUERY_COUNTER_BITS_EXT: switch (target) @@ -860,763 +1088,992 @@ void Context::getQueryiv(GLenum target, GLenum pname, GLint *params) } } -Error Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params) +void Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) +void Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) +void Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Error Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) +void Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) { - return GetQueryObjectParameter(this, id, pname, params); + handleError(GetQueryObjectParameter(getQuery(id), pname, params)); } -Framebuffer *Context::getFramebuffer(unsigned int handle) const +Framebuffer *Context::getFramebuffer(GLuint handle) const { - auto framebufferIt = mFramebufferMap.find(handle); - return ((framebufferIt == mFramebufferMap.end()) ? nullptr : framebufferIt->second); + return mState.mFramebuffers->getFramebuffer(handle); } -FenceNV *Context::getFenceNV(unsigned int handle) +FenceNV *Context::getFenceNV(GLuint handle) { - FenceNVMap::iterator fence = mFenceNVMap.find(handle); - - if (fence == mFenceNVMap.end()) - { - return NULL; - } - else - { - return fence->second; - } + return mFenceNVMap.query(handle); } -Query *Context::getQuery(unsigned int handle, bool create, GLenum type) +Query *Context::getQuery(GLuint handle, bool create, GLenum type) { - QueryMap::iterator query = mQueryMap.find(handle); - - if (query == mQueryMap.end()) + if (!mQueryMap.contains(handle)) { - return NULL; + return nullptr; } - else + + Query *query = mQueryMap.query(handle); + if (!query && create) { - if (!query->second && create) - { - query->second = new Query(mRenderer->createQuery(type), handle); - query->second->addRef(); - } - return query->second; + query = new Query(mImplementation->createQuery(type), handle); + query->addRef(); + mQueryMap.assign(handle, query); } + return query; } Query *Context::getQuery(GLuint handle) const { - auto iter = mQueryMap.find(handle); - return (iter != mQueryMap.end()) ? iter->second : nullptr; + return mQueryMap.query(handle); } Texture *Context::getTargetTexture(GLenum target) const { - ASSERT(ValidTextureTarget(this, target)); - return mState.getTargetTexture(target); + ASSERT(ValidTextureTarget(this, target) || ValidTextureExternalTarget(this, target)); + return mGLState.getTargetTexture(target); } Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const { - return mState.getSamplerTexture(sampler, type); + return mGLState.getSamplerTexture(sampler, type); } Compiler *Context::getCompiler() const { - return mCompiler; + if (mCompiler.get() == nullptr) + { + mCompiler.set(this, new Compiler(mImplementation.get(), mState)); + } + return mCompiler.get(); } -void Context::getBooleanv(GLenum pname, GLboolean *params) +void Context::getBooleanvImpl(GLenum pname, GLboolean *params) { switch (pname) { - case GL_SHADER_COMPILER: *params = GL_TRUE; break; - case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; - default: - mState.getBooleanv(pname, params); - break; + case GL_SHADER_COMPILER: + *params = GL_TRUE; + break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: + *params = mRobustAccess ? GL_TRUE : GL_FALSE; + break; + default: + mGLState.getBooleanv(pname, params); + break; } } -void Context::getFloatv(GLenum pname, GLfloat *params) +void Context::getFloatvImpl(GLenum pname, GLfloat *params) { // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State. switch (pname) { - case GL_ALIASED_LINE_WIDTH_RANGE: - params[0] = mCaps.minAliasedLineWidth; - params[1] = mCaps.maxAliasedLineWidth; - break; - case GL_ALIASED_POINT_SIZE_RANGE: - params[0] = mCaps.minAliasedPointSize; - params[1] = mCaps.maxAliasedPointSize; - break; - case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - ASSERT(mExtensions.textureFilterAnisotropic); - *params = mExtensions.maxTextureAnisotropy; - break; - case GL_MAX_TEXTURE_LOD_BIAS: - *params = mCaps.maxLODBias; - break; - default: - mState.getFloatv(pname, params); + case GL_ALIASED_LINE_WIDTH_RANGE: + params[0] = mCaps.minAliasedLineWidth; + params[1] = mCaps.maxAliasedLineWidth; + break; + case GL_ALIASED_POINT_SIZE_RANGE: + params[0] = mCaps.minAliasedPointSize; + params[1] = mCaps.maxAliasedPointSize; + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + ASSERT(mExtensions.textureFilterAnisotropic); + *params = mExtensions.maxTextureAnisotropy; + break; + case GL_MAX_TEXTURE_LOD_BIAS: + *params = mCaps.maxLODBias; + break; + + case GL_PATH_MODELVIEW_MATRIX_CHROMIUM: + case GL_PATH_PROJECTION_MATRIX_CHROMIUM: + { + ASSERT(mExtensions.pathRendering); + const GLfloat *m = mGLState.getPathRenderingMatrix(pname); + memcpy(params, m, 16 * sizeof(GLfloat)); + } break; + + default: + mGLState.getFloatv(pname, params); + break; } } -void Context::getIntegerv(GLenum pname, GLint *params) +void Context::getIntegervImpl(GLenum pname, GLint *params) { // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State. switch (pname) { - case GL_MAX_VERTEX_ATTRIBS: *params = mCaps.maxVertexAttributes; break; - case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mCaps.maxVertexUniformVectors; break; - case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mCaps.maxVertexUniformComponents; break; - case GL_MAX_VARYING_VECTORS: *params = mCaps.maxVaryingVectors; break; - case GL_MAX_VARYING_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mCaps.maxCombinedTextureImageUnits; break; - 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.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; - //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_SUBPIXEL_BITS: *params = 4; break; - case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; - case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; - case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; - case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = mCaps.uniformBufferOffsetAlignment; break; - case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = mCaps.maxUniformBufferBindings; break; - 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; - case GL_MAX_ELEMENTS_VERTICES: *params = mCaps.maxElementsVertices; break; - 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 = static_cast(mCaps.compressedTextureFormats.size()); - break; - case GL_MAX_SAMPLES_ANGLE: *params = mCaps.maxSamples; break; - case GL_MAX_VIEWPORT_DIMS: + case GL_MAX_VERTEX_ATTRIBS: + *params = mCaps.maxVertexAttributes; + break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: + *params = mCaps.maxVertexUniformVectors; + break; + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + *params = mCaps.maxVertexUniformComponents; + break; + case GL_MAX_VARYING_VECTORS: + *params = mCaps.maxVaryingVectors; + break; + case GL_MAX_VARYING_COMPONENTS: + *params = mCaps.maxVertexOutputComponents; + break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + *params = mCaps.maxCombinedTextureImageUnits; + break; + 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.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; + // case GL_FRAMEBUFFER_BINDING: // now equivalent to + // GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_SUBPIXEL_BITS: + *params = 4; + break; + case GL_MAX_TEXTURE_SIZE: + *params = mCaps.max2DTextureSize; + break; + case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: + *params = mCaps.maxRectangleTextureSize; + break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + *params = mCaps.maxCubeMapTextureSize; + break; + case GL_MAX_3D_TEXTURE_SIZE: + *params = mCaps.max3DTextureSize; + break; + case GL_MAX_ARRAY_TEXTURE_LAYERS: + *params = mCaps.maxArrayTextureLayers; + break; + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + *params = mCaps.uniformBufferOffsetAlignment; + break; + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + *params = mCaps.maxUniformBufferBindings; + break; + 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 = getClientVersion().major; + break; + case GL_MINOR_VERSION: + *params = getClientVersion().minor; + break; + case GL_MAX_ELEMENTS_INDICES: + *params = mCaps.maxElementsIndices; + break; + case GL_MAX_ELEMENTS_VERTICES: + *params = mCaps.maxElementsVertices; + break; + 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 = static_cast(mCaps.compressedTextureFormats.size()); + break; + case GL_MAX_SAMPLES_ANGLE: + *params = mCaps.maxSamples; + break; + case GL_MAX_VIEWPORT_DIMS: { params[0] = mCaps.maxViewportWidth; params[1] = mCaps.maxViewportHeight; } break; - case GL_COMPRESSED_TEXTURE_FORMATS: - std::copy(mCaps.compressedTextureFormats.begin(), mCaps.compressedTextureFormats.end(), params); - break; - case GL_RESET_NOTIFICATION_STRATEGY_EXT: - *params = mResetStrategy; - break; - case GL_NUM_SHADER_BINARY_FORMATS: - *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 = static_cast(mCaps.programBinaryFormats.size()); - break; - case GL_PROGRAM_BINARY_FORMATS: - std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params); - break; - case GL_NUM_EXTENSIONS: - *params = static_cast(mExtensionStrings.size()); - break; + case GL_COMPRESSED_TEXTURE_FORMATS: + std::copy(mCaps.compressedTextureFormats.begin(), mCaps.compressedTextureFormats.end(), + params); + break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; + case GL_NUM_SHADER_BINARY_FORMATS: + *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 = static_cast(mCaps.programBinaryFormats.size()); + break; + case GL_PROGRAM_BINARY_FORMATS: + std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params); + break; + 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; + // 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_ANGLE_multiview + case GL_MAX_VIEWS_ANGLE: + *params = mExtensions.maxViews; + break; + + // GL_EXT_disjoint_timer_query + case GL_GPU_DISJOINT_EXT: + *params = mImplementation->getGPUDisjoint(); + break; + case GL_MAX_FRAMEBUFFER_WIDTH: + *params = mCaps.maxFramebufferWidth; + break; + case GL_MAX_FRAMEBUFFER_HEIGHT: + *params = mCaps.maxFramebufferHeight; + break; + case GL_MAX_FRAMEBUFFER_SAMPLES: + *params = mCaps.maxFramebufferSamples; + break; + case GL_MAX_SAMPLE_MASK_WORDS: + *params = mCaps.maxSampleMaskWords; + break; + case GL_MAX_COLOR_TEXTURE_SAMPLES: + *params = mCaps.maxColorTextureSamples; + break; + case GL_MAX_DEPTH_TEXTURE_SAMPLES: + *params = mCaps.maxDepthTextureSamples; + break; + case GL_MAX_INTEGER_SAMPLES: + *params = mCaps.maxIntegerSamples; + break; + case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: + *params = mCaps.maxVertexAttribRelativeOffset; + break; + case GL_MAX_VERTEX_ATTRIB_BINDINGS: + *params = mCaps.maxVertexAttribBindings; + break; + case GL_MAX_VERTEX_ATTRIB_STRIDE: + *params = mCaps.maxVertexAttribStride; + break; + case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxVertexAtomicCounterBuffers; + break; + case GL_MAX_VERTEX_ATOMIC_COUNTERS: + *params = mCaps.maxVertexAtomicCounters; + break; + case GL_MAX_VERTEX_IMAGE_UNIFORMS: + *params = mCaps.maxVertexImageUniforms; + break; + case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxVertexShaderStorageBlocks; + break; + case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxFragmentAtomicCounterBuffers; + break; + case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: + *params = mCaps.maxFragmentAtomicCounters; + break; + case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: + *params = mCaps.maxFragmentImageUniforms; + break; + case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxFragmentShaderStorageBlocks; + break; + case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: + *params = mCaps.minProgramTextureGatherOffset; + break; + case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: + *params = mCaps.maxProgramTextureGatherOffset; + break; + case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: + *params = mCaps.maxComputeWorkGroupInvocations; + break; + case GL_MAX_COMPUTE_UNIFORM_BLOCKS: + *params = mCaps.maxComputeUniformBlocks; + break; + case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: + *params = mCaps.maxComputeTextureImageUnits; + break; + case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: + *params = mCaps.maxComputeSharedMemorySize; + break; + case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: + *params = mCaps.maxComputeUniformComponents; + break; + case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxComputeAtomicCounterBuffers; + break; + case GL_MAX_COMPUTE_ATOMIC_COUNTERS: + *params = mCaps.maxComputeAtomicCounters; + break; + case GL_MAX_COMPUTE_IMAGE_UNIFORMS: + *params = mCaps.maxComputeImageUniforms; + break; + case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedComputeUniformComponents; + break; + case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxComputeShaderStorageBlocks; + break; + case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: + *params = mCaps.maxCombinedShaderOutputResources; + break; + case GL_MAX_UNIFORM_LOCATIONS: + *params = mCaps.maxUniformLocations; + break; + case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: + *params = mCaps.maxAtomicCounterBufferBindings; + break; + case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: + *params = mCaps.maxAtomicCounterBufferSize; + break; + case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: + *params = mCaps.maxCombinedAtomicCounterBuffers; + break; + case GL_MAX_COMBINED_ATOMIC_COUNTERS: + *params = mCaps.maxCombinedAtomicCounters; + break; + case GL_MAX_IMAGE_UNITS: + *params = mCaps.maxImageUnits; + break; + case GL_MAX_COMBINED_IMAGE_UNIFORMS: + *params = mCaps.maxCombinedImageUniforms; + break; + case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: + *params = mCaps.maxShaderStorageBufferBindings; + break; + case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: + *params = mCaps.maxCombinedShaderStorageBlocks; + break; + case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: + *params = mCaps.shaderStorageBufferOffsetAlignment; + break; + default: + mGLState.getIntegerv(this, pname, params); + break; } } -void Context::getInteger64v(GLenum pname, GLint64 *params) +void Context::getInteger64vImpl(GLenum pname, GLint64 *params) { // Queries about context capabilities and maximums are answered by Context. // Queries about current GL state values are answered by State. switch (pname) { - case GL_MAX_ELEMENT_INDEX: - *params = mCaps.maxElementIndex; - break; - case GL_MAX_UNIFORM_BLOCK_SIZE: - *params = mCaps.maxUniformBlockSize; - break; - case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: - *params = mCaps.maxCombinedVertexUniformComponents; - break; - case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: - *params = mCaps.maxCombinedFragmentUniformComponents; - break; - case GL_MAX_SERVER_WAIT_TIMEOUT: - *params = mCaps.maxServerWaitTimeout; - break; + case GL_MAX_ELEMENT_INDEX: + *params = mCaps.maxElementIndex; + break; + case GL_MAX_UNIFORM_BLOCK_SIZE: + *params = mCaps.maxUniformBlockSize; + break; + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedVertexUniformComponents; + break; + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedFragmentUniformComponents; + break; + 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; + // GL_EXT_disjoint_timer_query + case GL_TIMESTAMP_EXT: + *params = mImplementation->getTimestamp(); + break; + + case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: + *params = mCaps.maxShaderStorageBlockSize; + break; + default: + UNREACHABLE(); + break; } } void Context::getPointerv(GLenum pname, void **params) const { - mState.getPointerv(pname, params); + mGLState.getPointerv(pname, params); } -bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +void Context::getIntegeri_v(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 - // mere passthrough. - return mState.getIndexedIntegerv(target, index, data); + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_INT) + { + switch (target) + { + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + ASSERT(index < 3u); + *data = mCaps.maxComputeWorkGroupCount[index]; + break; + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + ASSERT(index < 3u); + *data = mCaps.maxComputeWorkGroupSize[index]; + break; + default: + mGLState.getIntegeri_v(target, index, data); + } + } + else + { + CastIndexedStateValues(this, nativeType, target, index, numParams, data); + } } -bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +void Context::getInteger64i_v(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 - // mere passthrough. - return mState.getIndexedInteger64v(target, index, data); + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_INT_64_ANGLEX) + { + mGLState.getInteger64i_v(target, index, data); + } + else + { + CastIndexedStateValues(this, nativeType, target, index, numParams, data); + } } -bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +void Context::getBooleani_v(GLenum target, GLuint index, GLboolean *data) { - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + + GLenum nativeType; + unsigned int numParams; + bool queryStatus = getIndexedQueryParameterInfo(target, &nativeType, &numParams); + ASSERT(queryStatus); + + if (nativeType == GL_BOOL) { - *type = GL_INT; - *numParams = 1; - return true; + mGLState.getBooleani_v(target, index, data); } - - // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation - // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due - // to the fact that it is stored internally as a float, and so would require conversion - // if returned from Context::getIntegerv. Since this conversion is already implemented - // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we - // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling - // application. - switch (pname) + else { - case GL_COMPRESSED_TEXTURE_FORMATS: - { - *type = GL_INT; - *numParams = static_cast(mCaps.compressedTextureFormats.size()); - } - return true; - case GL_PROGRAM_BINARY_FORMATS_OES: - { - *type = GL_INT; - *numParams = static_cast(mCaps.programBinaryFormats.size()); - } - return true; - case GL_SHADER_BINARY_FORMATS: - { - *type = GL_INT; - *numParams = static_cast(mCaps.shaderBinaryFormats.size()); - } - return true; - - case GL_MAX_VERTEX_ATTRIBS: - case GL_MAX_VERTEX_UNIFORM_VECTORS: - case GL_MAX_VARYING_VECTORS: - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: - case GL_MAX_TEXTURE_IMAGE_UNITS: - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: - case GL_MAX_RENDERBUFFER_SIZE: - case GL_MAX_COLOR_ATTACHMENTS_EXT: - case GL_MAX_DRAW_BUFFERS_EXT: - case GL_NUM_SHADER_BINARY_FORMATS: - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: - case GL_ARRAY_BUFFER_BINDING: - //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: - case GL_READ_FRAMEBUFFER_BINDING_ANGLE: - case GL_RENDERBUFFER_BINDING: - case GL_CURRENT_PROGRAM: - case GL_PACK_ALIGNMENT: - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: - case GL_UNPACK_ALIGNMENT: - case GL_GENERATE_MIPMAP_HINT: - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: - case GL_RED_BITS: - case GL_GREEN_BITS: - case GL_BLUE_BITS: - case GL_ALPHA_BITS: - case GL_DEPTH_BITS: - case GL_STENCIL_BITS: - case GL_ELEMENT_ARRAY_BUFFER_BINDING: - case GL_CULL_FACE_MODE: - case GL_FRONT_FACE: - case GL_ACTIVE_TEXTURE: - case GL_STENCIL_FUNC: - case GL_STENCIL_VALUE_MASK: - case GL_STENCIL_REF: - case GL_STENCIL_FAIL: - case GL_STENCIL_PASS_DEPTH_FAIL: - case GL_STENCIL_PASS_DEPTH_PASS: - case GL_STENCIL_BACK_FUNC: - case GL_STENCIL_BACK_VALUE_MASK: - case GL_STENCIL_BACK_REF: - case GL_STENCIL_BACK_FAIL: - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: - case GL_STENCIL_BACK_PASS_DEPTH_PASS: - case GL_DEPTH_FUNC: - case GL_BLEND_SRC_RGB: - case GL_BLEND_SRC_ALPHA: - case GL_BLEND_DST_RGB: - case GL_BLEND_DST_ALPHA: - case GL_BLEND_EQUATION_RGB: - case GL_BLEND_EQUATION_ALPHA: - case GL_STENCIL_WRITEMASK: - case GL_STENCIL_BACK_WRITEMASK: - case GL_STENCIL_CLEAR_VALUE: - case GL_SUBPIXEL_BITS: - case GL_MAX_TEXTURE_SIZE: - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: - case GL_SAMPLE_BUFFERS: - case GL_SAMPLES: - case GL_IMPLEMENTATION_COLOR_READ_TYPE: - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: - case GL_TEXTURE_BINDING_2D: - case GL_TEXTURE_BINDING_CUBE_MAP: - case GL_RESET_NOTIFICATION_STRATEGY_EXT: - case GL_NUM_PROGRAM_BINARY_FORMATS_OES: - { - *type = GL_INT; - *numParams = 1; - } - return true; - case GL_MAX_SAMPLES_ANGLE: - { - if (mExtensions.framebufferMultisample) - { - *type = GL_INT; - *numParams = 1; - } - else - { - return false; - } - } - return true; - case GL_MAX_VIEWPORT_DIMS: - { - *type = GL_INT; - *numParams = 2; - } - return true; - case GL_VIEWPORT: - case GL_SCISSOR_BOX: - { - *type = GL_INT; - *numParams = 4; - } - return true; - case GL_SHADER_COMPILER: - case GL_SAMPLE_COVERAGE_INVERT: - case GL_DEPTH_WRITEMASK: - case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, - case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. - case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural - case GL_SAMPLE_COVERAGE: - case GL_SCISSOR_TEST: - case GL_STENCIL_TEST: - case GL_DEPTH_TEST: - case GL_BLEND: - case GL_DITHER: - case GL_CONTEXT_ROBUST_ACCESS_EXT: - { - *type = GL_BOOL; - *numParams = 1; - } - return true; - case GL_COLOR_WRITEMASK: - { - *type = GL_BOOL; - *numParams = 4; - } - return true; - case GL_POLYGON_OFFSET_FACTOR: - case GL_POLYGON_OFFSET_UNITS: - case GL_SAMPLE_COVERAGE_VALUE: - case GL_DEPTH_CLEAR_VALUE: - case GL_LINE_WIDTH: - { - *type = GL_FLOAT; - *numParams = 1; - } - return true; - case GL_ALIASED_LINE_WIDTH_RANGE: - case GL_ALIASED_POINT_SIZE_RANGE: - case GL_DEPTH_RANGE: - { - *type = GL_FLOAT; - *numParams = 2; - } - return true; - case GL_COLOR_CLEAR_VALUE: - case GL_BLEND_COLOR: - { - *type = GL_FLOAT; - *numParams = 4; - } - return true; - case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!mExtensions.maxTextureAnisotropy) - { - return false; - } - *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; - } + CastIndexedStateValues(this, nativeType, target, index, numParams, data); } +} - // 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; - } +void Context::getBufferParameteriv(BufferBinding target, GLenum pname, GLint *params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + QueryBufferParameteriv(buffer, pname, params); +} - if (mClientVersion < 3) - { - return false; - } +void Context::getFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) +{ + const Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + QueryFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params); +} - // Check for ES3.0+ parameter names - switch (pname) - { - case GL_MAX_UNIFORM_BUFFER_BINDINGS: - 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: - case GL_TEXTURE_BINDING_2D_ARRAY: - case GL_MAX_3D_TEXTURE_SIZE: - case GL_MAX_ARRAY_TEXTURE_LAYERS: - 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_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: - case GL_MAX_ELEMENTS_INDICES: - case GL_MAX_ELEMENTS_VERTICES: - 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; - } - return true; +void Context::getRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + QueryRenderbufferiv(this, renderbuffer, pname, params); +} - case GL_MAX_ELEMENT_INDEX: - case GL_MAX_UNIFORM_BLOCK_SIZE: - case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: - case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: - case GL_MAX_SERVER_WAIT_TIMEOUT: - { - *type = GL_INT_64_ANGLEX; - *numParams = 1; - } - return true; +void Context::getTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + Texture *texture = getTargetTexture(target); + QueryTexParameterfv(texture, pname, params); +} - 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; +void Context::getTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Texture *texture = getTargetTexture(target); + QueryTexParameteriv(texture, pname, params); +} - case GL_MAX_TEXTURE_LOD_BIAS: - { - *type = GL_FLOAT; - *numParams = 1; - } - return true; - } +void Context::getTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + QueryTexLevelParameteriv(texture, target, level, pname, params); +} - return false; +void Context::getTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + QueryTexLevelParameterfv(texture, target, level, pname, params); } -bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) +void Context::texParameterf(GLenum target, GLenum pname, GLfloat param) { - if (mClientVersion < 3) - { - return false; - } + Texture *texture = getTargetTexture(target); + SetTexParameterf(this, texture, pname, param); + onTextureChange(texture); +} - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - case GL_UNIFORM_BUFFER_BINDING: - { - *type = GL_INT; - *numParams = 1; - } - return true; - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - { - *type = GL_INT_64_ANGLEX; - *numParams = 1; - } - } +void Context::texParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + Texture *texture = getTargetTexture(target); + SetTexParameterfv(this, texture, pname, params); + onTextureChange(texture); +} - return false; +void Context::texParameteri(GLenum target, GLenum pname, GLint param) +{ + Texture *texture = getTargetTexture(target); + SetTexParameteri(this, texture, pname, param); + onTextureChange(texture); +} + +void Context::texParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + Texture *texture = getTargetTexture(target); + SetTexParameteriv(this, texture, pname, params); + onTextureChange(texture); +} + +void Context::drawArrays(GLenum mode, GLint first, GLsizei count) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawArrays(this, mode, first, count)); + MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback()); +} + +void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount)); + MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback()); +} + +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawElements(this, mode, count, type, indices)); +} + +void Context::drawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawElementsInstanced(this, mode, count, type, indices, instances)); +} + +void Context::drawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY( + mImplementation->drawRangeElements(this, mode, start, end, count, type, indices)); +} + +void Context::drawArraysIndirect(GLenum mode, const void *indirect) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawArraysIndirect(this, mode, indirect)); +} + +void Context::drawElementsIndirect(GLenum mode, GLenum type, const void *indirect) +{ + ANGLE_CONTEXT_TRY(prepareForDraw()); + ANGLE_CONTEXT_TRY(mImplementation->drawElementsIndirect(this, mode, type, indirect)); +} + +void Context::flush() +{ + handleError(mImplementation->flush(this)); +} + +void Context::finish() +{ + handleError(mImplementation->finish(this)); +} + +void Context::insertEventMarker(GLsizei length, const char *marker) +{ + ASSERT(mImplementation); + mImplementation->insertEventMarker(length, marker); +} + +void Context::pushGroupMarker(GLsizei length, const char *marker) +{ + ASSERT(mImplementation); + mImplementation->pushGroupMarker(length, marker); +} + +void Context::popGroupMarker() +{ + ASSERT(mImplementation); + mImplementation->popGroupMarker(); } -Error Context::drawArrays(GLenum mode, GLint first, GLsizei count) +void Context::bindUniformLocation(GLuint program, GLint location, const GLchar *name) { + Program *programObject = getProgram(program); + ASSERT(programObject); + + programObject->bindUniformLocation(location, name); +} + +void Context::setCoverageModulation(GLenum components) +{ + mGLState.setCoverageModulation(components); +} + +void Context::loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix) +{ + mGLState.loadPathRenderingMatrix(matrixMode, matrix); +} + +void Context::loadPathRenderingIdentityMatrix(GLenum matrixMode) +{ + GLfloat I[16]; + angle::Matrix::setToIdentity(I); + + mGLState.loadPathRenderingMatrix(matrixMode, I); +} + +void Context::stencilFillPath(GLuint path, GLenum fillMode, GLuint mask) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - Error error = mRenderer->drawArrays(getData(), mode, first, count); - if (error.isError()) - { - return error; - } - MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback()); + mImplementation->stencilFillPath(pathObj, fillMode, mask); +} + +void Context::stencilStrokePath(GLuint path, GLint reference, GLuint mask) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); - return Error(GL_NO_ERROR); + mImplementation->stencilStrokePath(pathObj, reference, mask); } -Error Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +void Context::coverFillPath(GLuint path, GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - Error error = mRenderer->drawArraysInstanced(getData(), mode, first, count, instanceCount); - if (error.isError()) - { - return error; - } - MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback()); + mImplementation->coverFillPath(pathObj, coverMode); +} + +void Context::coverStrokePath(GLuint path, GLenum coverMode) +{ + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; - return Error(GL_NO_ERROR); + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->coverStrokePath(pathObj, coverMode); } -Error Context::drawElements(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange) +void Context::stencilThenCoverFillPath(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawElements(getData(), mode, count, type, indices, indexRange); + + mImplementation->stencilThenCoverFillPath(pathObj, fillMode, mask, coverMode); } -Error Context::drawElementsInstanced(GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei instances, - const IndexRange &indexRange) +void Context::stencilThenCoverStrokePath(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) { + const auto *pathObj = mState.mPaths->getPath(path); + if (!pathObj) + return; + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawElementsInstanced(getData(), mode, count, type, indices, instances, - indexRange); + + mImplementation->stencilThenCoverStrokePath(pathObj, reference, mask, coverMode); } -Error Context::drawRangeElements(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid *indices, - const IndexRange &indexRange) +void Context::coverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? syncRendererState(); - return mRenderer->drawRangeElements(getData(), mode, start, end, count, type, indices, - indexRange); + + mImplementation->coverFillPathInstanced(pathObjects, coverMode, transformType, transformValues); } -Error Context::flush() +void Context::coverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - return mRenderer->flush(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->coverStrokePathInstanced(pathObjects, coverMode, transformType, + transformValues); } -Error Context::finish() +void Context::stencilFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) { - return mRenderer->finish(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilFillPathInstanced(pathObjects, fillMode, mask, transformType, + transformValues); } -void Context::insertEventMarker(GLsizei length, const char *marker) +void Context::stencilStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->insertEventMarker(length, marker); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilStrokePathInstanced(pathObjects, reference, mask, transformType, + transformValues); } -void Context::pushGroupMarker(GLsizei length, const char *marker) +void Context::stencilThenCoverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->pushGroupMarker(length, marker); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilThenCoverFillPathInstanced(pathObjects, coverMode, fillMode, mask, + transformType, transformValues); } -void Context::popGroupMarker() +void Context::stencilThenCoverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) { - ASSERT(mRenderer); - mRenderer->popGroupMarker(); + const auto &pathObjects = GatherPaths(*mState.mPaths, numPaths, pathNameType, paths, pathBase); + + // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering? + syncRendererState(); + + mImplementation->stencilThenCoverStrokePathInstanced(pathObjects, coverMode, reference, mask, + transformType, transformValues); +} + +void Context::bindFragmentInputLocation(GLuint program, GLint location, const GLchar *name) +{ + auto *programObject = getProgram(program); + + programObject->bindFragmentInputLocation(location, name); +} + +void Context::programPathFragmentInputGen(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + auto *programObject = getProgram(program); + + programObject->pathFragmentInputGen(this, location, genMode, components, coeffs); +} + +GLuint Context::getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name) +{ + const auto *programObject = getProgram(program); + return QueryProgramResourceIndex(programObject, programInterface, name); +} + +void Context::getProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + const auto *programObject = getProgram(program); + QueryProgramResourceName(programObject, programInterface, index, bufSize, length, name); +} + +GLint Context::getProgramResourceLocation(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + const auto *programObject = getProgram(program); + return QueryProgramResourceLocation(programObject, programInterface, name); +} + +void Context::getProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + const auto *programObject = getProgram(program); + QueryProgramResourceiv(programObject, programInterface, index, propCount, props, bufSize, + length, params); +} + +void Context::getProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + const auto *programObject = getProgram(program); + QueryProgramInterfaceiv(programObject, programInterface, pname, params); } -void Context::recordError(const Error &error) +void Context::handleError(const Error &error) { if (error.isError()) { - mErrors.insert(error.getCode()); - - if (!error.getMessage().empty()) + GLenum code = error.getCode(); + mErrors.insert(code); + if (code == GL_OUT_OF_MEMORY && getWorkarounds().loseContextOnOutOfMemory) { - auto &debug = mState.getDebug(); - debug.insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(), - GL_DEBUG_SEVERITY_HIGH, error.getMessage()); + markContextLost(); } + + ASSERT(!error.getMessage().empty()); + mGLState.getDebug().insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(), + GL_DEBUG_SEVERITY_HIGH, error.getMessage()); } } @@ -1636,32 +2093,61 @@ GLenum Context::getError() } } +// NOTE: this function should not assume that this context is current! +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + { + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLostForced = true; + } + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + GLenum Context::getResetStatus() { - //TODO(jmadill): needs MANGLE reworking - if (mResetStatus == GL_NO_ERROR && !mContextLost) + // Even if the application doesn't want to know about resets, we want to know + // as it will allow us to skip all the calls. + if (mResetStrategy == GL_NO_RESET_NOTIFICATION_EXT) { - // mResetStatus will be set by the markContextLost callback - // in the case a notification is sent - if (mRenderer->testDeviceLost()) + if (!mContextLost && mImplementation->getResetStatus() != GL_NO_ERROR) { - mRenderer->notifyDeviceLost(); + mContextLost = true; } - } - GLenum status = mResetStatus; + // EXT_robustness, section 2.6: If the reset notification behavior is + // NO_RESET_NOTIFICATION_EXT, then the implementation will never deliver notification of + // reset events, and GetGraphicsResetStatusEXT will always return NO_ERROR. + return GL_NO_ERROR; + } - if (mResetStatus != GL_NO_ERROR) + // The GL_EXT_robustness spec says that if a reset is encountered, a reset + // status should be returned at least once, and GL_NO_ERROR should be returned + // once the device has finished resetting. + if (!mContextLost) { - ASSERT(mContextLost); + ASSERT(mResetStatus == GL_NO_ERROR); + mResetStatus = mImplementation->getResetStatus(); - if (mRenderer->testDeviceResettable()) + if (mResetStatus != GL_NO_ERROR) { - mResetStatus = GL_NO_ERROR; + mContextLost = true; } } + else if (!mContextLostForced && mResetStatus != GL_NO_ERROR) + { + // If markContextLost was used to mark the context lost then + // assume that is not recoverable, and continue to report the + // lost reset status for the lifetime of this context. + mResetStatus = mImplementation->getResetStatus(); + } - return status; + return mResetStatus; } bool Context::isResetNotificationEnabled() @@ -1681,73 +2167,57 @@ EGLenum Context::getClientType() const EGLenum Context::getRenderBuffer() const { - 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 + const Framebuffer *framebuffer = mState.mFramebuffers->getFramebuffer(0); + if (framebuffer == nullptr) { 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; - } + const FramebufferAttachment *backAttachment = framebuffer->getAttachment(GL_BACK); + ASSERT(backAttachment != nullptr); + return backAttachment->getSurface()->getRenderBuffer(); } -void Context::checkTransformFeedbackAllocation(GLuint transformFeedback) +VertexArray *Context::checkVertexArrayAllocation(GLuint vertexArrayHandle) { // Only called after a prior call to Gen. - if (!getTransformFeedback(transformFeedback)) + VertexArray *vertexArray = getVertexArray(vertexArrayHandle); + if (!vertexArray) { - TransformFeedback *transformFeedbackObject = - new TransformFeedback(mRenderer->createTransformFeedback(), transformFeedback, mCaps); - transformFeedbackObject->addRef(); - mTransformFeedbackMap[transformFeedback] = transformFeedbackObject; + vertexArray = new VertexArray(mImplementation.get(), vertexArrayHandle, + mCaps.maxVertexAttributes, mCaps.maxVertexAttribBindings); + + mVertexArrayMap.assign(vertexArrayHandle, vertexArray); } + + return vertexArray; } -Framebuffer *Context::checkFramebufferAllocation(GLuint framebuffer) +TransformFeedback *Context::checkTransformFeedbackAllocation(GLuint transformFeedbackHandle) { - // 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) + // Only called after a prior call to Gen. + TransformFeedback *transformFeedback = getTransformFeedback(transformFeedbackHandle); + if (!transformFeedback) { - Framebuffer *newFBO = new Framebuffer(mCaps, mRenderer, framebuffer); - if (neverCreated) - { - mFramebufferHandleAllocator.reserve(framebuffer); - mFramebufferMap[framebuffer] = newFBO; - return newFBO; - } - - framebufferIt->second = newFBO; + transformFeedback = + new TransformFeedback(mImplementation.get(), transformFeedbackHandle, mCaps); + transformFeedback->addRef(); + mTransformFeedbackMap.assign(transformFeedbackHandle, transformFeedback); } - return framebufferIt->second; + return transformFeedback; } bool Context::isVertexArrayGenerated(GLuint vertexArray) { - return mVertexArrayMap.find(vertexArray) != mVertexArrayMap.end(); + ASSERT(mVertexArrayMap.contains(0)); + return mVertexArrayMap.contains(vertexArray); } bool Context::isTransformFeedbackGenerated(GLuint transformFeedback) { - return mTransformFeedbackMap.find(transformFeedback) != mTransformFeedbackMap.end(); + ASSERT(mTransformFeedbackMap.contains(0)); + return mTransformFeedbackMap.contains(transformFeedback); } void Context::detachTexture(GLuint texture) @@ -1756,7 +2226,7 @@ void Context::detachTexture(GLuint texture) // allocation map management either here or in the resource manager at detach time. // Zero textures are held by the Context, and we don't attempt to request them from // the State. - mState.detachTexture(mZeroTextures, texture); + mGLState.detachTexture(this, mZeroTextures, texture); } void Context::detachBuffer(GLuint buffer) @@ -1769,7 +2239,7 @@ void Context::detachBuffer(GLuint buffer) // 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); + mGLState.detachBuffer(this, buffer); } void Context::detachFramebuffer(GLuint framebuffer) @@ -1779,15 +2249,16 @@ void Context::detachFramebuffer(GLuint framebuffer) // to State at binding time. // [OpenGL ES 2.0.24] section 4.4 page 107: - // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though - // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. + // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as + // though BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of + // zero. - if (mState.removeReadFramebufferBinding(framebuffer) && framebuffer != 0) + if (mGLState.removeReadFramebufferBinding(framebuffer) && framebuffer != 0) { bindReadFramebuffer(0); } - if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) + if (mGLState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) { bindDrawFramebuffer(0); } @@ -1795,7 +2266,7 @@ void Context::detachFramebuffer(GLuint framebuffer) void Context::detachRenderbuffer(GLuint renderbuffer) { - mState.detachRenderbuffer(renderbuffer); + mGLState.detachRenderbuffer(this, renderbuffer); } void Context::detachVertexArray(GLuint vertexArray) @@ -1807,7 +2278,7 @@ void Context::detachVertexArray(GLuint vertexArray) // [OpenGL ES 3.0.2] section 2.10 page 43: // If a vertex array object that is currently bound is deleted, the binding // for that object reverts to zero and the default vertex array becomes current. - if (mState.removeVertexArrayBinding(vertexArray)) + if (mGLState.removeVertexArrayBinding(vertexArray)) { bindVertexArray(0); } @@ -1815,151 +2286,188 @@ void Context::detachVertexArray(GLuint vertexArray) void Context::detachTransformFeedback(GLuint transformFeedback) { - mState.detachTransformFeedback(transformFeedback); + // Transform feedback detachment is handled by Context, because 0 is a valid + // transform feedback, and a pointer to it must be passed from Context to State at + // binding time. + + // The OpenGL specification doesn't mention what should happen when the currently bound + // transform feedback object is deleted. Since it is a container object, we treat it like + // VAOs and FBOs and set the current bound transform feedback back to 0. + if (mGLState.removeTransformFeedbackBinding(this, transformFeedback)) + { + bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); + } } void Context::detachSampler(GLuint sampler) { - mState.detachSampler(sampler); + mGLState.detachSampler(this, sampler); } -void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +void Context::detachProgramPipeline(GLuint pipeline) { - mState.setVertexAttribDivisor(index, divisor); + mGLState.detachProgramPipeline(this, pipeline); } -void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +void Context::vertexAttribDivisor(GLuint index, GLuint divisor) { - mResourceManager->checkSamplerAllocation(sampler); + mGLState.setVertexAttribDivisor(this, index, divisor); +} - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameteri(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); +} - // 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_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::samplerParameteriv(GLuint sampler, GLenum pname, const GLint *param) +{ + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameteriv(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { - mResourceManager->checkSamplerAllocation(sampler); - - 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_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 + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameterf(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } -GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +void Context::samplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param) { - mResourceManager->checkSamplerAllocation(sampler); - - 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_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 + Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + SetSamplerParameterfv(samplerObject, pname, param); + mGLState.setObjectDirty(GL_SAMPLER); } -GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +void Context::getSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params) { - mResourceManager->checkSamplerAllocation(sampler); + const Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + QuerySamplerParameteriv(samplerObject, pname, params); + mGLState.setObjectDirty(GL_SAMPLER); +} - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); +void Context::getSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params) +{ + const Sampler *samplerObject = + mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler); + QuerySamplerParameterfv(samplerObject, pname, params); + mGLState.setObjectDirty(GL_SAMPLER); +} - // 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_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::programParameteri(GLuint program, GLenum pname, GLint value) +{ + gl::Program *programObject = getProgram(program); + SetProgramParameteri(programObject, pname, value); } void Context::initRendererString() { std::ostringstream rendererString; rendererString << "ANGLE ("; - rendererString << mRenderer->getRendererDescription(); + rendererString << mImplementation->getRendererDescription(); rendererString << ")"; mRendererString = MakeStaticString(rendererString.str()); } -const std::string &Context::getRendererString() const +void Context::initVersionStrings() { - return mRendererString; + const Version &clientVersion = getClientVersion(); + + std::ostringstream versionString; + versionString << "OpenGL ES " << clientVersion.major << "." << clientVersion.minor << " (ANGLE " + << ANGLE_VERSION_STRING << ")"; + mVersionString = MakeStaticString(versionString.str()); + + std::ostringstream shadingLanguageVersionString; + shadingLanguageVersionString << "OpenGL ES GLSL ES " + << (clientVersion.major == 2 ? 1 : clientVersion.major) << "." + << clientVersion.minor << "0 (ANGLE " << ANGLE_VERSION_STRING + << ")"; + mShadingLanguageString = MakeStaticString(shadingLanguageVersionString.str()); } void Context::initExtensionStrings() { - mExtensionStrings = mExtensions.getStrings(); + auto mergeExtensionStrings = [](const std::vector &strings) { + std::ostringstream combinedStringStream; + std::copy(strings.begin(), strings.end(), + std::ostream_iterator(combinedStringStream, " ")); + return MakeStaticString(combinedStringStream.str()); + }; - std::ostringstream combinedStringStream; - std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); - mExtensionString = combinedStringStream.str(); + mExtensionStrings.clear(); + for (const auto &extensionString : mExtensions.getStrings()) + { + mExtensionStrings.push_back(MakeStaticString(extensionString)); + } + mExtensionString = mergeExtensionStrings(mExtensionStrings); + + const gl::Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + + mRequestableExtensionStrings.clear(); + for (const auto &extensionInfo : GetExtensionInfoMap()) + { + if (extensionInfo.second.Requestable && + !(mExtensions.*(extensionInfo.second.ExtensionsMember)) && + nativeExtensions.*(extensionInfo.second.ExtensionsMember)) + { + mRequestableExtensionStrings.push_back(MakeStaticString(extensionInfo.first)); + } + } + mRequestableExtensionString = mergeExtensionStrings(mRequestableExtensionStrings); } -const std::string &Context::getExtensionString() const +const GLubyte *Context::getString(GLenum name) const { - return mExtensionString; + switch (name) + { + case GL_VENDOR: + return reinterpret_cast("Google Inc."); + + case GL_RENDERER: + return reinterpret_cast(mRendererString); + + case GL_VERSION: + return reinterpret_cast(mVersionString); + + case GL_SHADING_LANGUAGE_VERSION: + return reinterpret_cast(mShadingLanguageString); + + case GL_EXTENSIONS: + return reinterpret_cast(mExtensionString); + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + return reinterpret_cast(mRequestableExtensionString); + + default: + UNREACHABLE(); + return nullptr; + } } -const std::string &Context::getExtensionString(size_t idx) const +const GLubyte *Context::getStringi(GLenum name, GLuint index) const { - return mExtensionStrings[idx]; + switch (name) + { + case GL_EXTENSIONS: + return reinterpret_cast(mExtensionStrings[index]); + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + return reinterpret_cast(mRequestableExtensionStrings[index]); + + default: + UNREACHABLE(); + return nullptr; + } } size_t Context::getExtensionStringCount() const @@ -1967,26 +2475,117 @@ size_t Context::getExtensionStringCount() const return mExtensionStrings.size(); } -void Context::initCaps(GLuint clientVersion) +bool Context::isExtensionRequestable(const char *name) +{ + const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap(); + auto extension = extensionInfos.find(name); + + const Extensions &nativeExtensions = mImplementation->getNativeExtensions(); + return extension != extensionInfos.end() && extension->second.Requestable && + nativeExtensions.*(extension->second.ExtensionsMember); +} + +void Context::requestExtension(const char *name) +{ + const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap(); + ASSERT(extensionInfos.find(name) != extensionInfos.end()); + const auto &extension = extensionInfos.at(name); + ASSERT(extension.Requestable); + ASSERT(mImplementation->getNativeExtensions().*(extension.ExtensionsMember)); + + if (mExtensions.*(extension.ExtensionsMember)) + { + // Extension already enabled + return; + } + + mExtensions.*(extension.ExtensionsMember) = true; + updateCaps(); + initExtensionStrings(); + + // Release the shader compiler so it will be re-created with the requested extensions enabled. + releaseShaderCompiler(); + + // Invalidate all textures and framebuffer. Some extensions make new formats renderable or + // sampleable. + mState.mTextures->signalAllTexturesDirty(); + for (auto &zeroTexture : mZeroTextures) + { + zeroTexture.second->signalDirty(InitState::Initialized); + } + + mState.mFramebuffers->invalidateFramebufferComplenessCache(); +} + +size_t Context::getRequestableExtensionStringCount() const +{ + return mRequestableExtensionStrings.size(); +} + +void Context::beginTransformFeedback(GLenum primitiveMode) +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + ASSERT(!transformFeedback->isPaused()); + + transformFeedback->begin(this, primitiveMode, mGLState.getProgram()); +} + +bool Context::hasActiveTransformFeedback(GLuint program) const +{ + for (auto pair : mTransformFeedbackMap) + { + if (pair.second != nullptr && pair.second->hasBoundProgram(program)) + { + return true; + } + } + return false; +} + +void Context::initCaps(const egl::DisplayExtensions &displayExtensions, bool robustResourceInit) { - mCaps = mRenderer->getRendererCaps(); + mCaps = mImplementation->getNativeCaps(); - mExtensions = mRenderer->getRendererExtensions(); + mExtensions = mImplementation->getNativeExtensions(); - mLimitations = mRenderer->getRendererLimitations(); + mLimitations = mImplementation->getNativeLimitations(); - if (clientVersion < 3) + if (getClientVersion() < Version(3, 0)) { // Disable ES3+ extensions - mExtensions.colorBufferFloat = false; + mExtensions.colorBufferFloat = false; + mExtensions.eglImageExternalEssl3 = false; + mExtensions.textureNorm16 = false; + mExtensions.multiview = false; + mExtensions.maxViews = 1u; } - if (clientVersion > 2) + if (getClientVersion() < ES_3_1) + { + // Disable ES3.1+ extensions + mExtensions.geometryShader = false; + } + + if (getClientVersion() > Version(2, 0)) { // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts - //mExtensions.sRGB = false; + // mExtensions.sRGB = false; } + // Some extensions are always available because they are implemented in the GL layer. + mExtensions.bindUniformLocation = true; + mExtensions.vertexArrayObject = true; + mExtensions.bindGeneratesResource = true; + mExtensions.clientArrays = true; + mExtensions.requestExtension = true; + + // Enable the no error extension if the context was created with the flag. + mExtensions.noError = mSkipValidation; + + // Enable surfaceless to advertise we'll have the correct behavior when there is no default FBO + mExtensions.surfacelessContext = displayExtensions.surfacelessContext; + // Explicitly enable GL_KHR_debug mExtensions.debug = true; mExtensions.maxDebugMessageLength = 1024; @@ -1994,64 +2593,186 @@ void Context::initCaps(GLuint clientVersion) mExtensions.maxDebugGroupStackDepth = 1024; mExtensions.maxLabelLength = 1024; + // Explicitly enable GL_ANGLE_robust_client_memory + mExtensions.robustClientMemory = true; + + // Determine robust resource init availability from EGL. + mExtensions.robustResourceInitialization = robustResourceInit; + + // mExtensions.robustBufferAccessBehavior is true only if robust access is true and the backend + // supports it. + mExtensions.robustBufferAccessBehavior = + mRobustAccess && mExtensions.robustBufferAccessBehavior; + + // Enable the cache control query unconditionally. + mExtensions.programCacheControl = true; + // Apply implementation limits - mCaps.maxVertexAttributes = std::min(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); - mCaps.maxVertexUniformBlocks = std::min(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); - mCaps.maxVertexOutputComponents = std::min(mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + LimitCap(&mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); + + if (getClientVersion() < ES_3_1) + { + mCaps.maxVertexAttribBindings = mCaps.maxVertexAttributes; + } + else + { + LimitCap(&mCaps.maxVertexAttribBindings, MAX_VERTEX_ATTRIB_BINDINGS); + } - mCaps.maxFragmentInputComponents = std::min(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + LimitCap(&mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); + LimitCap(&mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + LimitCap(&mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); - mCaps.compressedTextureFormats.clear(); + // Limit textures as well, so we can use fast bitsets with texture bindings. + LimitCap(&mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES); + LimitCap(&mCaps.maxVertexTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2); + LimitCap(&mCaps.maxTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2); + + mCaps.maxSampleMaskWords = std::min(mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS); - const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); - for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) + // WebGL compatibility + mExtensions.webglCompatibility = mWebGLContext; + for (const auto &extensionInfo : GetExtensionInfoMap()) { - GLenum format = i->first; - TextureCaps formatCaps = i->second; + // If this context is for WebGL, disable all enableable extensions + if (mWebGLContext && extensionInfo.second.Requestable) + { + mExtensions.*(extensionInfo.second.ExtensionsMember) = false; + } + } + + // Generate texture caps + updateCaps(); +} + +void Context::updateCaps() +{ + mCaps.compressedTextureFormats.clear(); + mTextureCaps.clear(); - const InternalFormat &formatInfo = GetInternalFormatInfo(format); + for (GLenum sizedInternalFormat : GetAllSizedInternalFormats()) + { + TextureCaps formatCaps = mImplementation->getNativeTextureCaps().get(sizedInternalFormat); + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(sizedInternalFormat); // 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.texturable && formatInfo.textureSupport(getClientVersion(), mExtensions); formatCaps.renderable = - formatCaps.renderable && formatInfo.renderSupport(clientVersion, mExtensions); + formatCaps.renderable && formatInfo.renderSupport(getClientVersion(), mExtensions); formatCaps.filterable = - formatCaps.filterable && formatInfo.filterSupport(clientVersion, mExtensions); + formatCaps.filterable && formatInfo.filterSupport(getClientVersion(), mExtensions); - // OpenGL ES does not support multisampling with integer formats - if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT) + // OpenGL ES does not support multisampling with non-rendererable formats + // OpenGL ES 3.0 or prior does not support multisampling with integer formats + if (!formatCaps.renderable || + (getClientVersion() < ES_3_1 && + (formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT))) { formatCaps.sampleCounts.clear(); } + else + { + // We may have limited the max samples for some required renderbuffer formats due to + // non-conformant formats. In this case MAX_SAMPLES needs to be lowered accordingly. + GLuint formatMaxSamples = formatCaps.getMaxSamples(); + + // GLES 3.0.5 section 4.4.2.2: "Implementations must support creation of renderbuffers + // in these required formats with up to the value of MAX_SAMPLES multisamples, with the + // exception of signed and unsigned integer formats." + if (formatInfo.componentType != GL_INT && formatInfo.componentType != GL_UNSIGNED_INT && + formatInfo.isRequiredRenderbufferFormat(getClientVersion())) + { + ASSERT(getClientVersion() < ES_3_0 || formatMaxSamples >= 4); + mCaps.maxSamples = std::min(mCaps.maxSamples, formatMaxSamples); + } + + // Handle GLES 3.1 MAX_*_SAMPLES values similarly to MAX_SAMPLES. + if (getClientVersion() >= ES_3_1) + { + // GLES 3.1 section 9.2.5: "Implementations must support creation of renderbuffers + // in these required formats with up to the value of MAX_SAMPLES multisamples, with + // the exception that the signed and unsigned integer formats are required only to + // support creation of renderbuffers with up to the value of MAX_INTEGER_SAMPLES + // multisamples, which must be at least one." + if (formatInfo.componentType == GL_INT || + formatInfo.componentType == GL_UNSIGNED_INT) + { + mCaps.maxIntegerSamples = std::min(mCaps.maxIntegerSamples, formatMaxSamples); + } + + // GLES 3.1 section 19.3.1. + if (formatCaps.texturable) + { + if (formatInfo.depthBits > 0) + { + mCaps.maxDepthTextureSamples = + std::min(mCaps.maxDepthTextureSamples, formatMaxSamples); + } + else if (formatInfo.redBits > 0) + { + mCaps.maxColorTextureSamples = + std::min(mCaps.maxColorTextureSamples, formatMaxSamples); + } + } + } + } if (formatCaps.texturable && formatInfo.compressed) { - mCaps.compressedTextureFormats.push_back(format); + mCaps.compressedTextureFormats.push_back(sizedInternalFormat); } - mTextureCaps.insert(format, formatCaps); + mTextureCaps.insert(sizedInternalFormat, formatCaps); + } + + // If program binary is disabled, blank out the memory cache pointer. + if (!mImplementation->getNativeExtensions().getProgramBinary) + { + mMemoryProgramCache = nullptr; } } -void Context::syncRendererState() +void Context::initWorkarounds() +{ + // Apply back-end workarounds. + mImplementation->applyNativeWorkarounds(&mWorkarounds); + + // Lose the context upon out of memory error if the application is + // expecting to watch for those events. + mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + +Error Context::prepareForDraw() { - const State::DirtyBits &dirtyBits = mState.getDirtyBits(); - mRenderer->syncState(mState, dirtyBits); - mState.clearDirtyBits(); - mState.syncDirtyObjects(); + syncRendererState(); + + if (isRobustResourceInitEnabled()) + { + ANGLE_TRY(mGLState.clearUnclearedActiveTextures(this)); + ANGLE_TRY(mGLState.getDrawFramebuffer()->ensureDrawAttachmentsInitialized(this)); + } + + return NoError(); } -void Context::syncRendererState(const State::DirtyBits &bitMask) +void Context::syncRendererState() { - const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask); - mRenderer->syncState(mState, dirtyBits); - mState.clearDirtyBits(dirtyBits); + mGLState.syncDirtyObjects(this); + const State::DirtyBits &dirtyBits = mGLState.getDirtyBits(); + mImplementation->syncState(this, dirtyBits); + mGLState.clearDirtyBits(); +} - // TODO(jmadill): Filter objects by bitMask somehow? - mState.syncDirtyObjects(); +void Context::syncRendererState(const State::DirtyBits &bitMask, + const State::DirtyObjects &objectMask) +{ + mGLState.syncDirtyObjects(this, objectMask); + const State::DirtyBits &dirtyBits = (mGLState.getDirtyBits() & bitMask); + mImplementation->syncState(this, dirtyBits); + mGLState.clearDirtyBits(dirtyBits); } void Context::blitFramebuffer(GLint srcX0, @@ -2065,76 +2786,44 @@ void Context::blitFramebuffer(GLint srcX0, GLbitfield mask, GLenum filter) { - Framebuffer *readFramebuffer = mState.getReadFramebuffer(); - ASSERT(readFramebuffer); - - Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); + Framebuffer *drawFramebuffer = mGLState.getDrawFramebuffer(); ASSERT(drawFramebuffer); Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); - syncRendererState(mState.blitStateBitMask()); + syncStateForBlit(); - Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer); - if (error.isError()) - { - recordError(error); - return; - } + handleError(drawFramebuffer->blit(this, srcArea, dstArea, mask, filter)); } void Context::clear(GLbitfield mask) { - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = mState.getDrawFramebuffer()->clear(mData, mask); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clear(this, mask)); } 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); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferfv(this, buffer, drawbuffer, values)); } 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); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferuiv(this, buffer, drawbuffer, values)); } 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); - } + syncStateForClear(); + handleError(mGLState.getDrawFramebuffer()->clearBufferiv(this, buffer, drawbuffer, values)); } void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - Framebuffer *framebufferObject = mState.getDrawFramebuffer(); + Framebuffer *framebufferObject = mGLState.getDrawFramebuffer(); ASSERT(framebufferObject); // If a buffer is not present, the clear has no effect @@ -2144,14 +2833,8 @@ void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLin return; } - // Sync the clear state - syncRendererState(mState.clearStateBitMask()); - - Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil); - if (error.isError()) - { - recordError(error); - } + syncStateForClear(); + handleError(framebufferObject->clearBufferfi(this, buffer, drawbuffer, depth, stencil)); } void Context::readPixels(GLint x, @@ -2160,20 +2843,20 @@ void Context::readPixels(GLint x, GLsizei height, GLenum format, GLenum type, - GLvoid *pixels) + void *pixels) { - // Sync pack state - syncRendererState(mState.packStateBitMask()); + if (width == 0 || height == 0) + { + return; + } - Framebuffer *framebufferObject = mState.getReadFramebuffer(); - ASSERT(framebufferObject); + syncStateForReadPixels(); + + Framebuffer *readFBO = mGLState.getReadFramebuffer(); + ASSERT(readFBO); Rectangle area(x, y, width, height); - Error error = framebufferObject->readPixels(mState, area, format, type, pixels); - if (error.isError()) - { - recordError(error); - } + handleError(readFBO->readPixels(this, area, format, type, pixels)); } void Context::copyTexImage2D(GLenum target, @@ -2186,18 +2869,14 @@ void Context::copyTexImage2D(GLenum target, GLint border) { // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, GL_READ_FRAMEBUFFER); Rectangle sourceArea(x, y, width, height); - const Framebuffer *framebuffer = mState.getReadFramebuffer(); + Framebuffer *framebuffer = mGLState.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); - } + handleError(texture->copyImage(this, target, level, sourceArea, internalformat, framebuffer)); } void Context::copyTexSubImage2D(GLenum target, @@ -2209,20 +2888,21 @@ void Context::copyTexSubImage2D(GLenum target, GLsizei width, GLsizei height) { + if (width == 0 || height == 0) + { + return; + } + // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, GL_READ_FRAMEBUFFER); Offset destOffset(xoffset, yoffset, 0); Rectangle sourceArea(x, y, width, height); - const Framebuffer *framebuffer = mState.getReadFramebuffer(); + Framebuffer *framebuffer = mGLState.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); - } + handleError(texture->copySubImage(this, target, level, destOffset, sourceArea, framebuffer)); } void Context::copyTexSubImage3D(GLenum target, @@ -2235,19 +2915,20 @@ void Context::copyTexSubImage3D(GLenum target, GLsizei width, GLsizei height) { + if (width == 0 || height == 0) + { + return; + } + // Only sync the read FBO - mState.syncDirtyObject(GL_READ_FRAMEBUFFER); + mGLState.syncDirtyObject(this, 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); - } + Framebuffer *framebuffer = mGLState.getReadFramebuffer(); + Texture *texture = getTargetTexture(target); + handleError(texture->copySubImage(this, target, level, destOffset, sourceArea, framebuffer)); } void Context::framebufferTexture2D(GLenum target, @@ -2256,7 +2937,7 @@ void Context::framebufferTexture2D(GLenum target, GLuint texture, GLint level) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (texture != 0) @@ -2269,20 +2950,29 @@ void Context::framebufferTexture2D(GLenum target, { index = ImageIndex::Make2D(level); } + else if (textarget == GL_TEXTURE_RECTANGLE_ANGLE) + { + index = ImageIndex::MakeRectangle(level); + } + else if (textarget == GL_TEXTURE_2D_MULTISAMPLE) + { + ASSERT(level == 0); + index = ImageIndex::Make2DMultisample(); + } else { ASSERT(IsCubeMapTextureTarget(textarget)); index = ImageIndex::MakeCube(textarget, level); } - framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj); + framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::framebufferRenderbuffer(GLenum target, @@ -2290,21 +2980,22 @@ void Context::framebufferRenderbuffer(GLenum target, GLenum renderbuffertarget, GLuint renderbuffer) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (renderbuffer != 0) { Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer); - framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(), + + framebuffer->setAttachment(this, GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(), renderbufferObject); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::framebufferTextureLayer(GLenum target, @@ -2313,7 +3004,7 @@ void Context::framebufferTextureLayer(GLenum target, GLint level, GLint layer) { - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); if (texture != 0) @@ -2332,46 +3023,94 @@ void Context::framebufferTextureLayer(GLenum target, index = ImageIndex::Make2DArray(level, layer); } - framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject); + framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObject); + } + else + { + framebuffer->resetAttachment(this, attachment); + } + + mGLState.setObjectDirty(target); +} + +void Context::framebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObj = getTexture(texture); + + ImageIndex index = ImageIndex::Make2DArrayRange(level, baseViewIndex, numViews); + framebuffer->setAttachmentMultiviewLayered(this, GL_TEXTURE, attachment, index, textureObj, + numViews, baseViewIndex); + } + else + { + framebuffer->resetAttachment(this, attachment); + } + + mGLState.setObjectDirty(target); +} + +void Context::framebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObj = getTexture(texture); + + ImageIndex index = ImageIndex::Make2D(level); + framebuffer->setAttachmentMultiviewSideBySide(this, GL_TEXTURE, attachment, index, + textureObj, numViews, viewportOffsets); } else { - framebuffer->resetAttachment(attachment); + framebuffer->resetAttachment(this, attachment); } - mState.setObjectDirty(target); + mGLState.setObjectDirty(target); } void Context::drawBuffers(GLsizei n, const GLenum *bufs) { - Framebuffer *framebuffer = mState.getDrawFramebuffer(); + Framebuffer *framebuffer = mGLState.getDrawFramebuffer(); ASSERT(framebuffer); framebuffer->setDrawBuffers(n, bufs); - mState.setObjectDirty(GL_DRAW_FRAMEBUFFER); + mGLState.setObjectDirty(GL_DRAW_FRAMEBUFFER); } void Context::readBuffer(GLenum mode) { - Framebuffer *readFBO = mState.getReadFramebuffer(); + Framebuffer *readFBO = mGLState.getReadFramebuffer(); readFBO->setReadBuffer(mode); - mState.setObjectDirty(GL_READ_FRAMEBUFFER); + mGLState.setObjectDirty(GL_READ_FRAMEBUFFER); } void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.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); - } + handleError(framebuffer->discard(this, numAttachments, attachments)); } void Context::invalidateFramebuffer(GLenum target, @@ -2379,20 +3118,17 @@ void Context::invalidateFramebuffer(GLenum target, const GLenum *attachments) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); - if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(this) != GL_FRAMEBUFFER_COMPLETE) { - Error error = framebuffer->invalidate(numAttachments, attachments); - if (error.isError()) - { - recordError(error); - return; - } + return; } + + handleError(framebuffer->invalidate(this, numAttachments, attachments)); } void Context::invalidateSubFramebuffer(GLenum target, @@ -2404,21 +3140,2419 @@ void Context::invalidateSubFramebuffer(GLenum target, GLsizei height) { // Only sync the FBO - mState.syncDirtyObject(target); + mGLState.syncDirtyObject(this, target); - Framebuffer *framebuffer = mState.getTargetFramebuffer(target); + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); ASSERT(framebuffer); - if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(this) != GL_FRAMEBUFFER_COMPLETE) { - Rectangle area(x, y, width, height); - Error error = framebuffer->invalidateSub(numAttachments, attachments, area); - if (error.isError()) - { - recordError(error); - return; - } + return; + } + + Rectangle area(x, y, width, height); + handleError(framebuffer->invalidateSub(this, numAttachments, attachments, area)); +} + +void Context::texImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + syncStateForTexImage(); + + Extents size(width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setImage(this, mGLState.getUnpackState(), target, level, internalformat, + size, format, type, reinterpret_cast(pixels))); +} + +void Context::texImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + syncStateForTexImage(); + + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setImage(this, mGLState.getUnpackState(), target, level, internalformat, + size, format, type, reinterpret_cast(pixels))); +} + +void Context::texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setSubImage(this, mGLState.getUnpackState(), target, level, area, format, + type, reinterpret_cast(pixels))); +} + +void Context::texSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0 || depth == 0) + { + return; } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setSubImage(this, mGLState.getUnpackState(), target, level, area, format, + type, reinterpret_cast(pixels))); +} + +void Context::compressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Extents size(width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setCompressedImage(this, mGLState.getUnpackState(), target, level, + internalformat, size, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setCompressedImage(this, mGLState.getUnpackState(), target, level, + internalformat, size, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) +{ + syncStateForTexImage(); + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = + getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + handleError(texture->setCompressedSubImage(this, mGLState.getUnpackState(), target, level, area, + format, imageSize, + reinterpret_cast(data))); +} + +void Context::compressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) +{ + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setCompressedSubImage(this, mGLState.getUnpackState(), target, level, area, + format, imageSize, + reinterpret_cast(data))); +} + +void Context::generateMipmap(GLenum target) +{ + Texture *texture = getTargetTexture(target); + handleError(texture->generateMipmap(this)); +} + +void Context::copyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + handleError(destTexture->copyTexture(this, destTarget, destLevel, internalFormat, destType, + sourceLevel, ConvertToBool(unpackFlipY), + ConvertToBool(unpackPremultiplyAlpha), + ConvertToBool(unpackUnmultiplyAlpha), sourceTexture)); +} + +void Context::copySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + // Zero sized copies are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + Offset offset(xoffset, yoffset, 0); + Rectangle area(x, y, width, height); + handleError(destTexture->copySubTexture(this, destTarget, destLevel, offset, sourceLevel, area, + ConvertToBool(unpackFlipY), + ConvertToBool(unpackPremultiplyAlpha), + ConvertToBool(unpackUnmultiplyAlpha), sourceTexture)); +} + +void Context::compressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId) +{ + syncStateForTexImage(); + + gl::Texture *sourceTexture = getTexture(sourceId); + gl::Texture *destTexture = getTexture(destId); + handleError(destTexture->copyCompressedTexture(this, sourceTexture)); +} + +void Context::getBufferPointerv(BufferBinding target, GLenum pname, void **params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + QueryBufferPointerv(buffer, pname, params); +} + +void *Context::mapBuffer(BufferBinding target, GLenum access) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + Error error = buffer->map(this, access); + if (error.isError()) + { + handleError(error); + return nullptr; + } + + return buffer->getMapPointer(); +} + +GLboolean Context::unmapBuffer(BufferBinding target) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + GLboolean result; + Error error = buffer->unmap(this, &result); + if (error.isError()) + { + handleError(error); + return GL_FALSE; + } + + return result; +} + +void *Context::mapBufferRange(BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + + Error error = buffer->mapRange(this, offset, length, access); + if (error.isError()) + { + handleError(error); + return nullptr; + } + + return buffer->getMapPointer(); +} + +void Context::flushMappedBufferRange(BufferBinding /*target*/, + GLintptr /*offset*/, + GLsizeiptr /*length*/) +{ + // We do not currently support a non-trivial implementation of FlushMappedBufferRange +} + +void Context::syncStateForReadPixels() +{ + syncRendererState(mReadPixelsDirtyBits, mReadPixelsDirtyObjects); +} + +void Context::syncStateForTexImage() +{ + syncRendererState(mTexImageDirtyBits, mTexImageDirtyObjects); +} + +void Context::syncStateForClear() +{ + syncRendererState(mClearDirtyBits, mClearDirtyObjects); +} + +void Context::syncStateForBlit() +{ + syncRendererState(mBlitDirtyBits, mBlitDirtyObjects); +} + +void Context::activeShaderProgram(GLuint pipeline, GLuint program) +{ + UNIMPLEMENTED(); +} + +void Context::activeTexture(GLenum texture) +{ + mGLState.setActiveSampler(texture - GL_TEXTURE0); +} + +void Context::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + mGLState.setBlendColor(clamp01(red), clamp01(green), clamp01(blue), clamp01(alpha)); +} + +void Context::blendEquation(GLenum mode) +{ + mGLState.setBlendEquation(mode, mode); +} + +void Context::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + mGLState.setBlendEquation(modeRGB, modeAlpha); +} + +void Context::blendFunc(GLenum sfactor, GLenum dfactor) +{ + mGLState.setBlendFactors(sfactor, dfactor, sfactor, dfactor); +} + +void Context::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + mGLState.setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void Context::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + mGLState.setColorClearValue(red, green, blue, alpha); +} + +void Context::clearDepthf(GLfloat depth) +{ + mGLState.setDepthClearValue(depth); +} + +void Context::clearStencil(GLint s) +{ + mGLState.setStencilClearValue(s); +} + +void Context::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + mGLState.setColorMask(ConvertToBool(red), ConvertToBool(green), ConvertToBool(blue), + ConvertToBool(alpha)); +} + +void Context::cullFace(CullFaceMode mode) +{ + mGLState.setCullMode(mode); +} + +void Context::depthFunc(GLenum func) +{ + mGLState.setDepthFunc(func); +} + +void Context::depthMask(GLboolean flag) +{ + mGLState.setDepthMask(ConvertToBool(flag)); +} + +void Context::depthRangef(GLfloat zNear, GLfloat zFar) +{ + mGLState.setDepthRange(zNear, zFar); +} + +void Context::disable(GLenum cap) +{ + mGLState.setEnableFeature(cap, false); +} + +void Context::disableVertexAttribArray(GLuint index) +{ + mGLState.setEnableVertexAttribArray(index, false); +} + +void Context::enable(GLenum cap) +{ + mGLState.setEnableFeature(cap, true); +} + +void Context::enableVertexAttribArray(GLuint index) +{ + mGLState.setEnableVertexAttribArray(index, true); +} + +void Context::frontFace(GLenum mode) +{ + mGLState.setFrontFace(mode); +} + +void Context::hint(GLenum target, GLenum mode) +{ + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + mGLState.setGenerateMipmapHint(mode); + break; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + mGLState.setFragmentShaderDerivativeHint(mode); + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::lineWidth(GLfloat width) +{ + mGLState.setLineWidth(width); +} + +void Context::pixelStorei(GLenum pname, GLint param) +{ + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + mGLState.setUnpackAlignment(param); + break; + + case GL_PACK_ALIGNMENT: + mGLState.setPackAlignment(param); + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + mGLState.setPackReverseRowOrder(param != 0); + break; + + case GL_UNPACK_ROW_LENGTH: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackRowLength(param); + break; + + case GL_UNPACK_IMAGE_HEIGHT: + ASSERT(getClientMajorVersion() >= 3); + mGLState.setUnpackImageHeight(param); + break; + + case GL_UNPACK_SKIP_IMAGES: + ASSERT(getClientMajorVersion() >= 3); + mGLState.setUnpackSkipImages(param); + break; + + case GL_UNPACK_SKIP_ROWS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackSkipRows(param); + break; + + case GL_UNPACK_SKIP_PIXELS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().unpackSubimage); + mGLState.setUnpackSkipPixels(param); + break; + + case GL_PACK_ROW_LENGTH: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackRowLength(param); + break; + + case GL_PACK_SKIP_ROWS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackSkipRows(param); + break; + + case GL_PACK_SKIP_PIXELS: + ASSERT((getClientMajorVersion() >= 3) || getExtensions().packSubimage); + mGLState.setPackSkipPixels(param); + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::polygonOffset(GLfloat factor, GLfloat units) +{ + mGLState.setPolygonOffsetParams(factor, units); +} + +void Context::sampleCoverage(GLfloat value, GLboolean invert) +{ + mGLState.setSampleCoverageParams(clamp01(value), ConvertToBool(invert)); +} + +void Context::sampleMaski(GLuint maskNumber, GLbitfield mask) +{ + mGLState.setSampleMaskParams(maskNumber, mask); +} + +void Context::scissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mGLState.setScissorParams(x, y, width, height); +} + +void Context::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackParams(func, ref, mask); + } +} + +void Context::stencilMaskSeparate(GLenum face, GLuint mask) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackWritemask(mask); + } +} + +void Context::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + mGLState.setStencilBackOperations(fail, zfail, zpass); + } +} + +void Context::vertexAttrib1f(GLuint index, GLfloat x) +{ + GLfloat vals[4] = {x, 0, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib1fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], 0, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + GLfloat vals[4] = {x, y, 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib2fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], values[1], 0, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat vals[4] = {x, y, z, 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib3fv(GLuint index, const GLfloat *values) +{ + GLfloat vals[4] = {values[0], values[1], values[2], 1}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat vals[4] = {x, y, z, w}; + mGLState.setVertexAttribf(index, vals); +} + +void Context::vertexAttrib4fv(GLuint index, const GLfloat *values) +{ + mGLState.setVertexAttribf(index, values); +} + +void Context::vertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr) +{ + mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), + size, type, ConvertToBool(normalized), false, stride, ptr); +} + +void Context::vertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeOffset) +{ + mGLState.setVertexAttribFormat(attribIndex, size, type, ConvertToBool(normalized), false, + relativeOffset); +} + +void Context::vertexAttribIFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLuint relativeOffset) +{ + mGLState.setVertexAttribFormat(attribIndex, size, type, false, true, relativeOffset); +} + +void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) +{ + mGLState.setVertexAttribBinding(this, attribIndex, bindingIndex); +} + +void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + mGLState.setVertexBindingDivisor(bindingIndex, divisor); +} + +void Context::viewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mGLState.setViewportParams(x, y, width, height); +} + +void Context::vertexAttribIPointer(GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer) +{ + mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array), + size, type, false, true, stride, pointer); +} + +void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + GLint vals[4] = {x, y, z, w}; + mGLState.setVertexAttribi(index, vals); +} + +void Context::vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +{ + GLuint vals[4] = {x, y, z, w}; + mGLState.setVertexAttribu(index, vals); +} + +void Context::vertexAttribI4iv(GLuint index, const GLint *v) +{ + mGLState.setVertexAttribi(index, v); +} + +void Context::vertexAttribI4uiv(GLuint index, const GLuint *v) +{ + mGLState.setVertexAttribu(index, v); +} + +void Context::getVertexAttribiv(GLuint index, GLenum pname, GLint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribfv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribIiv(GLuint index, GLenum pname, GLint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribIiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params) +{ + const VertexAttribCurrentValueData ¤tValues = + getGLState().getVertexAttribCurrentValue(index); + const VertexArray *vao = getGLState().getVertexArray(); + QueryVertexAttribIuiv(vao->getVertexAttribute(index), vao->getBindingFromAttribIndex(index), + currentValues, pname, params); +} + +void Context::getVertexAttribPointerv(GLuint index, GLenum pname, void **pointer) +{ + const VertexAttribute &attrib = getGLState().getVertexArray()->getVertexAttribute(index); + QueryVertexAttribPointerv(attrib, pname, pointer); +} + +void Context::debugMessageControl(GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled) +{ + std::vector idVector(ids, ids + count); + mGLState.getDebug().setMessageControl(source, type, severity, std::move(idVector), + ConvertToBool(enabled)); +} + +void Context::debugMessageInsert(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf) +{ + std::string msg(buf, (length > 0) ? static_cast(length) : strlen(buf)); + mGLState.getDebug().insertMessage(source, type, id, severity, std::move(msg)); +} + +void Context::debugMessageCallback(GLDEBUGPROCKHR callback, const void *userParam) +{ + mGLState.getDebug().setCallback(callback, userParam); +} + +GLuint Context::getDebugMessageLog(GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog) +{ + return static_cast(mGLState.getDebug().getMessages(count, bufSize, sources, types, ids, + severities, lengths, messageLog)); +} + +void Context::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message) +{ + std::string msg(message, (length > 0) ? static_cast(length) : strlen(message)); + mGLState.getDebug().pushGroup(source, id, std::move(msg)); + mImplementation->pushDebugGroup(source, id, length, message); +} + +void Context::popDebugGroup() +{ + mGLState.getDebug().popGroup(); + mImplementation->popDebugGroup(); +} + +void Context::bufferData(BufferBinding target, GLsizeiptr size, const void *data, BufferUsage usage) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + handleError(buffer->bufferData(this, target, data, size, usage)); +} + +void Context::bufferSubData(BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data) +{ + if (data == nullptr) + { + return; + } + + Buffer *buffer = mGLState.getTargetBuffer(target); + ASSERT(buffer); + handleError(buffer->bufferSubData(this, target, data, size, offset)); +} + +void Context::attachShader(GLuint program, GLuint shader) +{ + Program *programObject = mState.mShaderPrograms->getProgram(program); + Shader *shaderObject = mState.mShaderPrograms->getShader(shader); + ASSERT(programObject && shaderObject); + programObject->attachShader(shaderObject); +} + +const Workarounds &Context::getWorkarounds() const +{ + return mWorkarounds; +} + +void Context::copyBufferSubData(BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) +{ + // if size is zero, the copy is a successful no-op + if (size == 0) + { + return; + } + + // TODO(jmadill): cache these. + Buffer *readBuffer = mGLState.getTargetBuffer(readTarget); + Buffer *writeBuffer = mGLState.getTargetBuffer(writeTarget); + + handleError(writeBuffer->copyBufferSubData(this, readBuffer, readOffset, writeOffset, size)); +} + +void Context::bindAttribLocation(GLuint program, GLuint index, const GLchar *name) +{ + Program *programObject = getProgram(program); + // TODO(jmadill): Re-use this from the validation if possible. + ASSERT(programObject); + programObject->bindAttributeLocation(index, name); +} + +void Context::bindBuffer(BufferBinding target, GLuint buffer) +{ + Buffer *bufferObject = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer); + mGLState.setBufferBinding(this, target, bufferObject); +} + +void Context::bindBufferBase(BufferBinding target, GLuint index, GLuint buffer) +{ + bindBufferRange(target, index, buffer, 0, 0); +} + +void Context::bindBufferRange(BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) +{ + Buffer *bufferObject = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer); + mGLState.setIndexedBufferBinding(this, target, index, bufferObject, offset, size); +} + +void Context::bindFramebuffer(GLenum target, GLuint framebuffer) +{ + if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) + { + bindReadFramebuffer(framebuffer); + } + + if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) + { + bindDrawFramebuffer(framebuffer); + } +} + +void Context::bindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + ASSERT(target == GL_RENDERBUFFER); + Renderbuffer *object = + mState.mRenderbuffers->checkRenderbufferAllocation(mImplementation.get(), renderbuffer); + mGLState.setRenderbufferBinding(this, object); +} + +void Context::texStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations) +{ + Extents size(width, height, 1); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorageMultisample(this, target, samples, internalformat, size, + ConvertToBool(fixedsamplelocations))); +} + +void Context::getMultisamplefv(GLenum pname, GLuint index, GLfloat *val) +{ + // According to spec 3.1 Table 20.49: Framebuffer Dependent Values, + // the sample position should be queried by DRAW_FRAMEBUFFER. + mGLState.syncDirtyObject(this, GL_DRAW_FRAMEBUFFER); + const Framebuffer *framebuffer = mGLState.getDrawFramebuffer(); + + switch (pname) + { + case GL_SAMPLE_POSITION: + handleError(framebuffer->getSamplePosition(index, val)); + break; + default: + UNREACHABLE(); + } +} + +void Context::renderbufferStorage(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat); + + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + handleError(renderbuffer->setStorage(this, convertedInternalFormat, width, height)); +} + +void Context::renderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat); + + Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); + handleError( + renderbuffer->setStorageMultisample(this, samples, convertedInternalFormat, width, height)); +} + +void Context::getSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +{ + const Sync *syncObject = getSync(sync); + handleError(QuerySynciv(syncObject, pname, bufSize, length, values)); +} + +void Context::getFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + QueryFramebufferParameteriv(framebuffer, pname, params); +} + +void Context::framebufferParameteri(GLenum target, GLenum pname, GLint param) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + SetFramebufferParameteri(framebuffer, pname, param); +} + +Error Context::getScratchBuffer(size_t requstedSizeBytes, + angle::MemoryBuffer **scratchBufferOut) const +{ + if (!mScratchBuffer.get(requstedSizeBytes, scratchBufferOut)) + { + return OutOfMemory() << "Failed to allocate internal buffer."; + } + return NoError(); +} + +Error Context::getZeroFilledBuffer(size_t requstedSizeBytes, + angle::MemoryBuffer **zeroBufferOut) const +{ + if (!mZeroFilledBuffer.getInitialized(requstedSizeBytes, zeroBufferOut, 0)) + { + return OutOfMemory() << "Failed to allocate internal buffer."; + } + return NoError(); +} + +void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) +{ + if (numGroupsX == 0u || numGroupsY == 0u || numGroupsZ == 0u) + { + return; + } + + // TODO(jmadill): Dirty bits for compute. + if (isRobustResourceInitEnabled()) + { + ANGLE_CONTEXT_TRY(mGLState.clearUnclearedActiveTextures(this)); + } + + handleError(mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ)); +} + +void Context::dispatchComputeIndirect(GLintptr indirect) +{ + UNIMPLEMENTED(); +} + +void Context::texStorage2D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height) +{ + Extents size(width, height, 1); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorage(this, target, levels, internalFormat, size)); +} + +void Context::texStorage3D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth) +{ + Extents size(width, height, depth); + Texture *texture = getTargetTexture(target); + handleError(texture->setStorage(this, target, levels, internalFormat, size)); +} + +void Context::memoryBarrier(GLbitfield barriers) +{ + UNIMPLEMENTED(); +} + +void Context::memoryBarrierByRegion(GLbitfield barriers) +{ + UNIMPLEMENTED(); +} + +GLenum Context::checkFramebufferStatus(GLenum target) +{ + Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target); + ASSERT(framebuffer); + + return framebuffer->checkStatus(this); +} + +void Context::compileShader(GLuint shader) +{ + Shader *shaderObject = GetValidShader(this, shader); + if (!shaderObject) + { + return; + } + shaderObject->compile(this); +} + +void Context::deleteBuffers(GLsizei n, const GLuint *buffers) +{ + for (int i = 0; i < n; i++) + { + deleteBuffer(buffers[i]); + } +} + +void Context::deleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + deleteFramebuffer(framebuffers[i]); + } + } +} + +void Context::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) +{ + for (int i = 0; i < n; i++) + { + deleteRenderbuffer(renderbuffers[i]); + } +} + +void Context::deleteTextures(GLsizei n, const GLuint *textures) +{ + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + deleteTexture(textures[i]); + } + } +} + +void Context::detachShader(GLuint program, GLuint shader) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + + programObject->detachShader(this, shaderObject); +} + +void Context::genBuffers(GLsizei n, GLuint *buffers) +{ + for (int i = 0; i < n; i++) + { + buffers[i] = createBuffer(); + } +} + +void Context::genFramebuffers(GLsizei n, GLuint *framebuffers) +{ + for (int i = 0; i < n; i++) + { + framebuffers[i] = createFramebuffer(); + } +} + +void Context::genRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + for (int i = 0; i < n; i++) + { + renderbuffers[i] = createRenderbuffer(); + } +} + +void Context::genTextures(GLsizei n, GLuint *textures) +{ + for (int i = 0; i < n; i++) + { + textures[i] = createTexture(); + } +} + +void Context::getActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getActiveAttribute(index, bufsize, length, size, type, name); +} + +void Context::getActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getActiveUniform(index, bufsize, length, size, type, name); +} + +void Context::getAttachedShaders(GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getAttachedShaders(maxcount, count, shaders); +} + +GLint Context::getAttribLocation(GLuint program, const GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + return programObject->getAttributeLocation(name); +} + +void Context::getBooleanv(GLenum pname, GLboolean *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_BOOL) + { + getBooleanvImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getFloatv(GLenum pname, GLfloat *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_FLOAT) + { + getFloatvImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getIntegerv(GLenum pname, GLint *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_INT) + { + getIntegervImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getProgramiv(GLuint program, GLenum pname, GLint *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + QueryProgramiv(this, programObject, pname, params); +} + +void Context::getProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params) +{ + UNIMPLEMENTED(); +} + +void Context::getProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei *length, GLchar *infolog) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getInfoLog(bufsize, length, infolog); +} + +void Context::getProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + UNIMPLEMENTED(); +} + +void Context::getShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + QueryShaderiv(this, shaderObject, pname, params); +} + +void Context::getShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *infolog) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->getInfoLog(this, bufsize, length, infolog); +} + +void Context::getShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) +{ + // TODO(jmadill): Compute shaders. + + switch (shadertype) + { + case GL_VERTEX_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + mCaps.vertexLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + mCaps.vertexMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + mCaps.vertexHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + mCaps.vertexLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + mCaps.vertexMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + mCaps.vertexHighpInt.get(range, precision); + break; + + default: + UNREACHABLE(); + return; + } + break; + + case GL_FRAGMENT_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + mCaps.fragmentLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + mCaps.fragmentMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + mCaps.fragmentHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + mCaps.fragmentLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + mCaps.fragmentMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + mCaps.fragmentHighpInt.get(range, precision); + break; + + default: + UNREACHABLE(); + return; + } + break; + + default: + UNREACHABLE(); + return; + } +} + +void Context::getShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->getSource(bufsize, length, source); +} + +void Context::getUniformfv(GLuint program, GLint location, GLfloat *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getUniformfv(this, location, params); +} + +void Context::getUniformiv(GLuint program, GLint location, GLint *params) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getUniformiv(this, location, params); +} + +GLint Context::getUniformLocation(GLuint program, const GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + return programObject->getUniformLocation(name); +} + +GLboolean Context::isBuffer(GLuint buffer) +{ + if (buffer == 0) + { + return GL_FALSE; + } + + return (getBuffer(buffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isEnabled(GLenum cap) +{ + return mGLState.getEnableFeature(cap); +} + +GLboolean Context::isFramebuffer(GLuint framebuffer) +{ + if (framebuffer == 0) + { + return GL_FALSE; + } + + return (getFramebuffer(framebuffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isProgram(GLuint program) +{ + if (program == 0) + { + return GL_FALSE; + } + + return (getProgram(program) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isRenderbuffer(GLuint renderbuffer) +{ + if (renderbuffer == 0) + { + return GL_FALSE; + } + + return (getRenderbuffer(renderbuffer) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isShader(GLuint shader) +{ + if (shader == 0) + { + return GL_FALSE; + } + + return (getShader(shader) ? GL_TRUE : GL_FALSE); +} + +GLboolean Context::isTexture(GLuint texture) +{ + if (texture == 0) + { + return GL_FALSE; + } + + return (getTexture(texture) ? GL_TRUE : GL_FALSE); +} + +void Context::linkProgram(GLuint program) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + handleError(programObject->link(this)); + mGLState.onProgramExecutableChange(programObject); +} + +void Context::releaseShaderCompiler() +{ + mCompiler.set(this, nullptr); +} + +void Context::shaderBinary(GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) +{ + // No binary shader formats are supported. + UNIMPLEMENTED(); +} + +void Context::shaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) +{ + Shader *shaderObject = getShader(shader); + ASSERT(shaderObject); + shaderObject->setSource(count, string, length); +} + +void Context::stencilFunc(GLenum func, GLint ref, GLuint mask) +{ + stencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void Context::stencilMask(GLuint mask) +{ + stencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void Context::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + stencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void Context::uniform1f(GLint location, GLfloat x) +{ + Program *program = mGLState.getProgram(); + program->setUniform1fv(location, 1, &x); +} + +void Context::uniform1fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform1fv(location, count, v); +} + +void Context::uniform1i(GLint location, GLint x) +{ + Program *program = mGLState.getProgram(); + if (program->setUniform1iv(location, 1, &x) == Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::uniform1iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + if (program->setUniform1iv(location, count, v) == Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::uniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + Program *program = mGLState.getProgram(); + program->setUniform2fv(location, 1, xy); +} + +void Context::uniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform2fv(location, count, v); +} + +void Context::uniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[2] = {x, y}; + Program *program = mGLState.getProgram(); + program->setUniform2iv(location, 1, xy); +} + +void Context::uniform2iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform2iv(location, count, v); +} + +void Context::uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + Program *program = mGLState.getProgram(); + program->setUniform3fv(location, 1, xyz); +} + +void Context::uniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform3fv(location, count, v); +} + +void Context::uniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + Program *program = mGLState.getProgram(); + program->setUniform3iv(location, 1, xyz); +} + +void Context::uniform3iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform3iv(location, count, v); +} + +void Context::uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + Program *program = mGLState.getProgram(); + program->setUniform4fv(location, 1, xyzw); +} + +void Context::uniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform4fv(location, count, v); +} + +void Context::uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + Program *program = mGLState.getProgram(); + program->setUniform4iv(location, 1, xyzw); +} + +void Context::uniform4iv(GLint location, GLsizei count, const GLint *v) +{ + Program *program = mGLState.getProgram(); + program->setUniform4iv(location, count, v); +} + +void Context::uniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2fv(location, count, transpose, value); +} + +void Context::uniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3fv(location, count, transpose, value); +} + +void Context::uniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4fv(location, count, transpose, value); +} + +void Context::validateProgram(GLuint program) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->validate(mCaps); +} + +void Context::validateProgramPipeline(GLuint pipeline) +{ + UNIMPLEMENTED(); +} + +void Context::getProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + Program *programObject = getProgram(program); + ASSERT(programObject != nullptr); + + handleError(programObject->saveBinary(this, binaryFormat, binary, bufSize, length)); +} + +void Context::programBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) +{ + Program *programObject = getProgram(program); + ASSERT(programObject != nullptr); + + handleError(programObject->loadBinary(this, binaryFormat, binary, length)); +} + +void Context::uniform1ui(GLint location, GLuint v0) +{ + Program *program = mGLState.getProgram(); + program->setUniform1uiv(location, 1, &v0); +} + +void Context::uniform2ui(GLint location, GLuint v0, GLuint v1) +{ + Program *program = mGLState.getProgram(); + const GLuint xy[] = {v0, v1}; + program->setUniform2uiv(location, 1, xy); +} + +void Context::uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + Program *program = mGLState.getProgram(); + const GLuint xyz[] = {v0, v1, v2}; + program->setUniform3uiv(location, 1, xyz); +} + +void Context::uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + Program *program = mGLState.getProgram(); + const GLuint xyzw[] = {v0, v1, v2, v3}; + program->setUniform4uiv(location, 1, xyzw); +} + +void Context::uniform1uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform1uiv(location, count, value); +} +void Context::uniform2uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform2uiv(location, count, value); +} + +void Context::uniform3uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform3uiv(location, count, value); +} + +void Context::uniform4uiv(GLint location, GLsizei count, const GLuint *value) +{ + Program *program = mGLState.getProgram(); + program->setUniform4uiv(location, count, value); +} + +void Context::genQueries(GLsizei n, GLuint *ids) +{ + for (GLsizei i = 0; i < n; i++) + { + GLuint handle = mQueryHandleAllocator.allocate(); + mQueryMap.assign(handle, nullptr); + ids[i] = handle; + } +} + +void Context::deleteQueries(GLsizei n, const GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint query = ids[i]; + + Query *queryObject = nullptr; + if (mQueryMap.erase(query, &queryObject)) + { + mQueryHandleAllocator.release(query); + if (queryObject) + { + queryObject->release(this); + } + } + } +} + +GLboolean Context::isQuery(GLuint id) +{ + return (getQuery(id, false, GL_NONE) != nullptr) ? GL_TRUE : GL_FALSE; +} + +void Context::uniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2x3fv(location, count, transpose, value); +} + +void Context::uniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3x2fv(location, count, transpose, value); +} + +void Context::uniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix2x4fv(location, count, transpose, value); +} + +void Context::uniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4x2fv(location, count, transpose, value); +} + +void Context::uniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix3x4fv(location, count, transpose, value); +} + +void Context::uniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *program = mGLState.getProgram(); + program->setUniformMatrix4x3fv(location, count, transpose, value); +} + +void Context::deleteVertexArrays(GLsizei n, const GLuint *arrays) +{ + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + GLuint vertexArray = arrays[arrayIndex]; + + if (arrays[arrayIndex] != 0) + { + VertexArray *vertexArrayObject = nullptr; + if (mVertexArrayMap.erase(vertexArray, &vertexArrayObject)) + { + if (vertexArrayObject != nullptr) + { + detachVertexArray(vertexArray); + vertexArrayObject->onDestroy(this); + } + + mVertexArrayHandleAllocator.release(vertexArray); + } + } + } +} + +void Context::genVertexArrays(GLsizei n, GLuint *arrays) +{ + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + GLuint vertexArray = mVertexArrayHandleAllocator.allocate(); + mVertexArrayMap.assign(vertexArray, nullptr); + arrays[arrayIndex] = vertexArray; + } +} + +bool Context::isVertexArray(GLuint array) +{ + if (array == 0) + { + return GL_FALSE; + } + + VertexArray *vao = getVertexArray(array); + return (vao != nullptr ? GL_TRUE : GL_FALSE); +} + +void Context::endTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->end(this); +} + +void Context::transformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); +} + +void Context::getTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); +} + +void Context::deleteTransformFeedbacks(GLsizei n, const GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint transformFeedback = ids[i]; + if (transformFeedback == 0) + { + continue; + } + + TransformFeedback *transformFeedbackObject = nullptr; + if (mTransformFeedbackMap.erase(transformFeedback, &transformFeedbackObject)) + { + if (transformFeedbackObject != nullptr) + { + detachTransformFeedback(transformFeedback); + transformFeedbackObject->release(this); + } + + mTransformFeedbackHandleAllocator.release(transformFeedback); + } + } +} + +void Context::genTransformFeedbacks(GLsizei n, GLuint *ids) +{ + for (int i = 0; i < n; i++) + { + GLuint transformFeedback = mTransformFeedbackHandleAllocator.allocate(); + mTransformFeedbackMap.assign(transformFeedback, nullptr); + ids[i] = transformFeedback; + } +} + +bool Context::isTransformFeedback(GLuint id) +{ + 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 = getTransformFeedback(id); + return ((transformFeedback != nullptr) ? GL_TRUE : GL_FALSE); +} + +void Context::pauseTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->pause(); +} + +void Context::resumeTransformFeedback() +{ + TransformFeedback *transformFeedback = mGLState.getCurrentTransformFeedback(); + transformFeedback->resume(); +} + +void Context::getUniformuiv(GLuint program, GLint location, GLuint *params) +{ + const Program *programObject = getProgram(program); + programObject->getUniformuiv(this, location, params); +} + +GLint Context::getFragDataLocation(GLuint program, const GLchar *name) +{ + const Program *programObject = getProgram(program); + return programObject->getFragDataLocation(name); +} + +void Context::getUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) +{ + const Program *programObject = getProgram(program); + if (!programObject->isLinked()) + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = GL_INVALID_INDEX; + } + } + else + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]); + } + } +} + +void Context::getActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) +{ + const Program *programObject = getProgram(program); + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + params[uniformId] = GetUniformResourceProperty(programObject, index, pname); + } +} + +GLuint Context::getUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) +{ + const Program *programObject = getProgram(program); + return programObject->getUniformBlockIndex(uniformBlockName); +} + +void Context::getActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + const Program *programObject = getProgram(program); + QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params); +} + +void Context::getActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) +{ + const Program *programObject = getProgram(program); + programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); +} + +void Context::uniformBlockBinding(GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + Program *programObject = getProgram(program); + programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); +} + +GLsync Context::fenceSync(GLenum condition, GLbitfield flags) +{ + GLuint handle = mState.mSyncs->createSync(mImplementation.get()); + GLsync syncHandle = reinterpret_cast(static_cast(handle)); + + Sync *syncObject = getSync(syncHandle); + Error error = syncObject->set(condition, flags); + if (error.isError()) + { + deleteSync(syncHandle); + handleError(error); + return nullptr; + } + + return syncHandle; +} + +GLboolean Context::isSync(GLsync sync) +{ + return (getSync(sync) != nullptr); +} + +GLenum Context::clientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + Sync *syncObject = getSync(sync); + + GLenum result = GL_WAIT_FAILED; + handleError(syncObject->clientWait(flags, timeout, &result)); + return result; +} + +void Context::waitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + Sync *syncObject = getSync(sync); + handleError(syncObject->serverWait(flags, timeout)); +} + +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + GLenum nativeType = GL_NONE; + unsigned int numParams = 0; + getQueryParameterInfo(pname, &nativeType, &numParams); + + if (nativeType == GL_INT_64_ANGLEX) + { + getInteger64vImpl(pname, params); + } + else + { + CastStateValues(this, nativeType, pname, numParams, params); + } +} + +void Context::getBufferParameteri64v(BufferBinding target, GLenum pname, GLint64 *params) +{ + Buffer *buffer = mGLState.getTargetBuffer(target); + QueryBufferParameteri64v(buffer, pname, params); +} + +void Context::genSamplers(GLsizei count, GLuint *samplers) +{ + for (int i = 0; i < count; i++) + { + samplers[i] = mState.mSamplers->createSampler(); + } +} + +void Context::deleteSamplers(GLsizei count, const GLuint *samplers) +{ + for (int i = 0; i < count; i++) + { + GLuint sampler = samplers[i]; + + if (mState.mSamplers->getSampler(sampler)) + { + detachSampler(sampler); + } + + mState.mSamplers->deleteObject(this, sampler); + } +} + +void Context::getInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) +{ + const TextureCaps &formatCaps = mTextureCaps.get(internalformat); + QueryInternalFormativ(formatCaps, pname, bufSize, params); +} + +void Context::programUniform1i(GLuint program, GLint location, GLint v0) +{ + programUniform1iv(program, location, 1, &v0); +} + +void Context::programUniform2i(GLuint program, GLint location, GLint v0, GLint v1) +{ + GLint xy[2] = {v0, v1}; + programUniform2iv(program, location, 1, xy); +} + +void Context::programUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +{ + GLint xyz[3] = {v0, v1, v2}; + programUniform3iv(program, location, 1, xyz); +} + +void Context::programUniform4i(GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3) +{ + GLint xyzw[4] = {v0, v1, v2, v3}; + programUniform4iv(program, location, 1, xyzw); +} + +void Context::programUniform1ui(GLuint program, GLint location, GLuint v0) +{ + programUniform1uiv(program, location, 1, &v0); +} + +void Context::programUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1) +{ + GLuint xy[2] = {v0, v1}; + programUniform2uiv(program, location, 1, xy); +} + +void Context::programUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + GLuint xyz[3] = {v0, v1, v2}; + programUniform3uiv(program, location, 1, xyz); +} + +void Context::programUniform4ui(GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + GLuint xyzw[4] = {v0, v1, v2, v3}; + programUniform4uiv(program, location, 1, xyzw); +} + +void Context::programUniform1f(GLuint program, GLint location, GLfloat v0) +{ + programUniform1fv(program, location, 1, &v0); +} + +void Context::programUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1) +{ + GLfloat xy[2] = {v0, v1}; + programUniform2fv(program, location, 1, xy); +} + +void Context::programUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + GLfloat xyz[3] = {v0, v1, v2}; + programUniform3fv(program, location, 1, xyz); +} + +void Context::programUniform4f(GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3) +{ + GLfloat xyzw[4] = {v0, v1, v2, v3}; + programUniform4fv(program, location, 1, xyzw); +} + +void Context::programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + if (programObject->setUniform1iv(location, count, value) == + Program::SetUniformResult::SamplerChanged) + { + mGLState.setObjectDirty(GL_PROGRAM); + } +} + +void Context::programUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2iv(location, count, value); +} + +void Context::programUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3iv(location, count, value); +} + +void Context::programUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4iv(location, count, value); +} + +void Context::programUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform1uiv(location, count, value); +} + +void Context::programUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2uiv(location, count, value); +} + +void Context::programUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3uiv(location, count, value); +} + +void Context::programUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4uiv(location, count, value); +} + +void Context::programUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform1fv(location, count, value); +} + +void Context::programUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform2fv(location, count, value); +} + +void Context::programUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform3fv(location, count, value); +} + +void Context::programUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniform4fv(location, count, value); +} + +void Context::programUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2x3fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3x2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix2x4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4x2fv(location, count, transpose, value); +} + +void Context::programUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix3x4fv(location, count, transpose, value); +} + +void Context::programUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + Program *programObject = getProgram(program); + ASSERT(programObject); + programObject->setUniformMatrix4x3fv(location, count, transpose, value); +} + +void Context::onTextureChange(const Texture *texture) +{ + // Conservatively assume all textures are dirty. + // TODO(jmadill): More fine-grained update. + mGLState.setObjectDirty(GL_TEXTURE); +} + +void Context::genProgramPipelines(GLsizei count, GLuint *pipelines) +{ + for (int i = 0; i < count; i++) + { + pipelines[i] = createProgramPipeline(); + } +} + +void Context::deleteProgramPipelines(GLsizei count, const GLuint *pipelines) +{ + for (int i = 0; i < count; i++) + { + if (pipelines[i] != 0) + { + deleteProgramPipeline(pipelines[i]); + } + } +} + +GLboolean Context::isProgramPipeline(GLuint pipeline) +{ + if (pipeline == 0) + { + return GL_FALSE; + } + + return (getProgramPipeline(pipeline) ? GL_TRUE : GL_FALSE); } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Context.h b/src/3rdparty/angle/src/libANGLE/Context.h index 6b82eb7cb9..38c4e7b4d1 100644 --- a/src/3rdparty/angle/src/libANGLE/Context.h +++ b/src/3rdparty/angle/src/libANGLE/Context.h @@ -10,25 +10,28 @@ #ifndef LIBANGLE_CONTEXT_H_ #define LIBANGLE_CONTEXT_H_ +#include +#include + +#include "angle_gl.h" +#include "common/MemoryBuffer.h" #include "common/angleutils.h" -#include "libANGLE/RefCountObject.h" #include "libANGLE/Caps.h" #include "libANGLE/Constants.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Error.h" #include "libANGLE/HandleAllocator.h" +#include "libANGLE/PackedGLEnums.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/ResourceMap.h" #include "libANGLE/VertexAttribute.h" +#include "libANGLE/Workarounds.h" #include "libANGLE/angletypes.h" -#include "angle_gl.h" - -#include -#include -#include - namespace rx { -class Renderer; +class ContextImpl; +class EGLImplFactory; } namespace egl @@ -36,41 +39,44 @@ namespace egl class AttributeMap; class Surface; struct Config; +class Thread; } namespace gl { +class Buffer; class Compiler; -class Shader; -class Program; -class Texture; -class Framebuffer; -class Renderbuffer; class FenceNV; -class FenceSync; +class Sync; +class Framebuffer; +class MemoryProgramCache; +class Program; class Query; -class ResourceManager; -class Buffer; -struct VertexAttribute; -class VertexArray; +class Renderbuffer; class Sampler; +class Shader; +class Texture; class TransformFeedback; +class VertexArray; +struct VertexAttribute; +class ProgramPipeline; class Context final : public ValidationContext { public: - Context(const egl::Config *config, + Context(rx::EGLImplFactory *implFactory, + const egl::Config *config, const Context *shareContext, - rx::Renderer *renderer, - const egl::AttributeMap &attribs); - - virtual ~Context(); + TextureManager *shareTextures, + MemoryProgramCache *memoryProgramCache, + const egl::AttributeMap &attribs, + const egl::DisplayExtensions &displayExtensions); - void makeCurrent(egl::Surface *surface); - void releaseSurface(); + egl::Error onDestroy(const egl::Display *display); + ~Context() override; - virtual void markContextLost(); - bool isContextLost(); + egl::Error makeCurrent(egl::Display *display, egl::Surface *surface); + egl::Error releaseSurface(const egl::Display *display); // These create and destroy methods are merely pass-throughs to // ResourceManager, which owns these object types @@ -79,18 +85,30 @@ class Context final : public ValidationContext GLuint createProgram(); GLuint createTexture(); GLuint createRenderbuffer(); - GLuint createSampler(); - GLuint createTransformFeedback(); - GLsync createFenceSync(); + GLuint createPaths(GLsizei range); + GLuint createProgramPipeline(); + GLuint createShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings); void deleteBuffer(GLuint buffer); void deleteShader(GLuint shader); void deleteProgram(GLuint program); void deleteTexture(GLuint texture); void deleteRenderbuffer(GLuint renderbuffer); - void deleteSampler(GLuint sampler); - void deleteTransformFeedback(GLuint transformFeedback); - void deleteFenceSync(GLsync fenceSync); + void deletePaths(GLuint first, GLsizei range); + void deleteProgramPipeline(GLuint pipeline); + + // CHROMIUM_path_rendering + bool hasPathData(GLuint path) const; + bool hasPath(GLuint path) const; + void setPathCommands(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); + void setPathParameterf(GLuint path, GLenum pname, GLfloat value); + void getPathParameterfv(GLuint path, GLenum pname, GLfloat *value) const; + void setPathStencilFunc(GLenum func, GLint ref, GLuint mask); // Framebuffers are owned by the Context, so these methods do not pass through GLuint createFramebuffer(); @@ -100,54 +118,90 @@ class Context final : public ValidationContext GLuint createFenceNV(); void deleteFenceNV(GLuint fence); - // Queries are owned by the Context; - GLuint createQuery(); - void deleteQuery(GLuint query); - - // Vertex arrays are owned by the Context - GLuint createVertexArray(); - void deleteVertexArray(GLuint vertexArray); - - void bindArrayBuffer(GLuint buffer); - void bindElementArrayBuffer(GLuint buffer); void bindTexture(GLenum target, GLuint handle); void bindReadFramebuffer(GLuint framebufferHandle); void bindDrawFramebuffer(GLuint framebufferHandle); - void bindRenderbuffer(GLuint renderbuffer); - void bindVertexArray(GLuint vertexArray); - void bindSampler(GLuint textureUnit, GLuint sampler); - void bindGenericUniformBuffer(GLuint buffer); - void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); - void bindGenericTransformFeedbackBuffer(GLuint buffer); - void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); - void bindCopyReadBuffer(GLuint buffer); - void bindCopyWriteBuffer(GLuint buffer); - void bindPixelPackBuffer(GLuint buffer); - void bindPixelUnpackBuffer(GLuint buffer); + void bindVertexArray(GLuint vertexArrayHandle); + void bindVertexBuffer(GLuint bindingIndex, + GLuint bufferHandle, + GLintptr offset, + GLsizei stride); + void bindSampler(GLuint textureUnit, GLuint samplerHandle); + void bindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); void useProgram(GLuint program); - void bindTransformFeedback(GLuint transformFeedback); + void useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program); + void bindTransformFeedback(GLenum target, GLuint transformFeedbackHandle); + void bindProgramPipeline(GLuint pipelineHandle); - Error beginQuery(GLenum target, GLuint query); - Error endQuery(GLenum target); - Error queryCounter(GLuint id, GLenum target); + void beginQuery(GLenum target, GLuint query); + void endQuery(GLenum target); + void 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); + void getQueryObjectiv(GLuint id, GLenum pname, GLint *params); + void getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); + void getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params); + void getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params); + + void vertexAttribDivisor(GLuint index, GLuint divisor); + void vertexBindingDivisor(GLuint bindingIndex, GLuint divisor); + + void getBufferParameteriv(BufferBinding target, GLenum pname, GLint *params); + void getFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params); + void getRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params); + + void getTexParameterfv(GLenum target, GLenum pname, GLfloat *params); + void getTexParameteriv(GLenum target, GLenum pname, GLint *params); + void getTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params); + void getTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params); + void texParameterf(GLenum target, GLenum pname, GLfloat param); + void texParameterfv(GLenum target, GLenum pname, const GLfloat *params); + void texParameteri(GLenum target, GLenum pname, GLint param); + void texParameteriv(GLenum target, GLenum pname, const GLint *params); void samplerParameteri(GLuint sampler, GLenum pname, GLint param); + void samplerParameteriv(GLuint sampler, GLenum pname, const GLint *param); void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); - GLint getSamplerParameteri(GLuint sampler, GLenum pname); - GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); + void samplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param); + + void getSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params); + void getSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params); + + void programParameteri(GLuint program, GLenum pname, GLint value); + + GLuint getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name); + void getProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); + GLint getProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name); + void getProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + + void getProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params); Buffer *getBuffer(GLuint handle) const; FenceNV *getFenceNV(GLuint handle); - FenceSync *getFenceSync(GLsync handle) const; - Shader *getShader(GLuint handle) const; - Program *getProgram(GLuint handle) const; + Sync *getSync(GLsync handle) const; Texture *getTexture(GLuint handle) const; Framebuffer *getFramebuffer(GLuint handle) const; Renderbuffer *getRenderbuffer(GLuint handle) const; @@ -156,8 +210,16 @@ class Context final : public ValidationContext 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; + ProgramPipeline *getProgramPipeline(GLuint handle) const; + + void objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); + void objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label); + void getObjectLabel(GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) const; + void getObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) const; Texture *getTargetTexture(GLenum target) const; Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; @@ -170,16 +232,108 @@ class Context final : public ValidationContext bool isTransformFeedbackGenerated(GLuint vertexArray); void getBooleanv(GLenum pname, GLboolean *params); + void getBooleanvImpl(GLenum pname, GLboolean *params); void getFloatv(GLenum pname, GLfloat *params); + void getFloatvImpl(GLenum pname, GLfloat *params); void getIntegerv(GLenum pname, GLint *params); - void getInteger64v(GLenum pname, GLint64 *params); + void getIntegervImpl(GLenum pname, GLint *params); + void getInteger64vImpl(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); - - bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); - bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); + void getBooleani_v(GLenum target, GLuint index, GLboolean *data); + void getIntegeri_v(GLenum target, GLuint index, GLint *data); + void getInteger64i_v(GLenum target, GLuint index, GLint64 *data); + + void activeShaderProgram(GLuint pipeline, GLuint program); + void activeTexture(GLenum texture); + void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void blendEquation(GLenum mode); + void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); + void blendFunc(GLenum sfactor, GLenum dfactor); + void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void clearDepthf(GLfloat depth); + void clearStencil(GLint s); + void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void cullFace(CullFaceMode mode); + void depthFunc(GLenum func); + void depthMask(GLboolean flag); + void depthRangef(GLfloat zNear, GLfloat zFar); + void disable(GLenum cap); + void disableVertexAttribArray(GLuint index); + void enable(GLenum cap); + void enableVertexAttribArray(GLuint index); + void frontFace(GLenum mode); + void hint(GLenum target, GLenum mode); + void lineWidth(GLfloat width); + void pixelStorei(GLenum pname, GLint param); + void polygonOffset(GLfloat factor, GLfloat units); + void sampleCoverage(GLfloat value, GLboolean invert); + void sampleMaski(GLuint maskNumber, GLbitfield mask); + void scissor(GLint x, GLint y, GLsizei width, GLsizei height); + void stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); + void stencilMaskSeparate(GLenum face, GLuint mask); + void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void vertexAttrib1f(GLuint index, GLfloat x); + void vertexAttrib1fv(GLuint index, const GLfloat *values); + void vertexAttrib2f(GLuint index, GLfloat x, GLfloat y); + void vertexAttrib2fv(GLuint index, const GLfloat *values); + void vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z); + void vertexAttrib3fv(GLuint index, const GLfloat *values); + void vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void vertexAttrib4fv(GLuint index, const GLfloat *values); + void vertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeOffset); + void vertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset); + void vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex); + void vertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr); + void vertexAttribIPointer(GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer); + void viewport(GLint x, GLint y, GLsizei width, GLsizei height); + + void vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); + void vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); + void vertexAttribI4iv(GLuint index, const GLint *v); + void vertexAttribI4uiv(GLuint index, const GLuint *v); + void getVertexAttribiv(GLuint index, GLenum pname, GLint *params); + void getVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); + void getVertexAttribIiv(GLuint index, GLenum pname, GLint *params); + void getVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params); + void getVertexAttribPointerv(GLuint index, GLenum pname, void **pointer); + + void debugMessageControl(GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled); + void debugMessageInsert(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf); + void debugMessageCallback(GLDEBUGPROCKHR callback, const void *userParam); + GLuint getDebugMessageLog(GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog); + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message); + void popDebugGroup(); void clear(GLbitfield mask); void clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values); @@ -187,27 +341,23 @@ class Context final : public ValidationContext 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 drawArrays(GLenum mode, GLint first, GLsizei count); + void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); + + void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); + void drawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + void drawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices); + void drawArraysIndirect(GLenum mode, const void *indirect); + void drawElementsIndirect(GLenum mode, GLenum type, const void *indirect); void blitFramebuffer(GLint srcX0, GLint srcY0, @@ -226,7 +376,7 @@ class Context final : public ValidationContext GLsizei height, GLenum format, GLenum type, - GLvoid *pixels); + void *pixels); void copyTexImage2D(GLenum target, GLint level, @@ -272,6 +422,18 @@ class Context final : public ValidationContext GLuint texture, GLint level, GLint layer); + void framebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews); + void framebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets); void drawBuffers(GLsizei n, const GLenum *bufs); void readBuffer(GLenum mode); @@ -286,40 +448,596 @@ class Context final : public ValidationContext GLsizei width, GLsizei height); - Error flush(); - Error finish(); + void texImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); + void texImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels); + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels); + void texSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels); + void compressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data); + void compressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data); + void compressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data); + void compressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data); + void copyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + void copySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + void compressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId); + + void generateMipmap(GLenum target); + + void flush(); + void finish(); + + void getBufferPointerv(BufferBinding target, GLenum pname, void **params); + void *mapBuffer(BufferBinding target, GLenum access); + GLboolean unmapBuffer(BufferBinding target); + void *mapBufferRange(BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); + void flushMappedBufferRange(BufferBinding target, GLintptr offset, GLsizeiptr length); + + void beginTransformFeedback(GLenum primitiveMode); + + bool hasActiveTransformFeedback(GLuint program) const; void insertEventMarker(GLsizei length, const char *marker); void pushGroupMarker(GLsizei length, const char *marker); void popGroupMarker(); - void recordError(const Error &error) override; + void bindUniformLocation(GLuint program, GLint location, const GLchar *name); + void renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void renderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + + void getSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); + + // CHROMIUM_framebuffer_mixed_samples + void setCoverageModulation(GLenum components); + + // CHROMIUM_path_rendering + void loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix); + void loadPathRenderingIdentityMatrix(GLenum matrixMode); + void stencilFillPath(GLuint path, GLenum fillMode, GLuint mask); + void stencilStrokePath(GLuint path, GLint reference, GLuint mask); + void coverFillPath(GLuint path, GLenum coverMode); + void coverStrokePath(GLuint path, GLenum coverMode); + void stencilThenCoverFillPath(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); + void stencilThenCoverStrokePath(GLuint path, GLint reference, GLuint mask, GLenum coverMode); + void coverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void coverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void stencilFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBAse, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + void stencilStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + void stencilThenCoverFillPathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void stencilThenCoverStrokePathInstanced(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + void bindFragmentInputLocation(GLuint program, GLint location, const GLchar *name); + void programPathFragmentInputGen(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + + void bufferData(BufferBinding target, GLsizeiptr size, const void *data, BufferUsage usage); + void bufferSubData(BufferBinding target, GLintptr offset, GLsizeiptr size, const void *data); + void attachShader(GLuint program, GLuint shader); + void bindAttribLocation(GLuint program, GLuint index, const GLchar *name); + void bindBuffer(BufferBinding target, GLuint buffer); + void bindBufferBase(BufferBinding target, GLuint index, GLuint buffer); + void bindBufferRange(BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size); + void bindFramebuffer(GLenum target, GLuint framebuffer); + void bindRenderbuffer(GLenum target, GLuint renderbuffer); + + void texStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); + + void getMultisamplefv(GLenum pname, GLuint index, GLfloat *val); + + void copyBufferSubData(BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size); + + GLenum checkFramebufferStatus(GLenum target); + void compileShader(GLuint shader); + void deleteBuffers(GLsizei n, const GLuint *buffers); + void deleteFramebuffers(GLsizei n, const GLuint *framebuffers); + void deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); + void deleteTextures(GLsizei n, const GLuint *textures); + void detachShader(GLuint program, GLuint shader); + void genBuffers(GLsizei n, GLuint *buffers); + void genFramebuffers(GLsizei n, GLuint *framebuffers); + void genRenderbuffers(GLsizei n, GLuint *renderbuffers); + void genTextures(GLsizei n, GLuint *textures); + void getActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); + void getActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); + void getAttachedShaders(GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders); + GLint getAttribLocation(GLuint program, const GLchar *name); + void getProgramiv(GLuint program, GLenum pname, GLint *params); + void getProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params); + void getProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei *length, GLchar *infolog); + void getProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); + void getShaderiv(GLuint shader, GLenum pname, GLint *params); + void getShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *infolog); + void getShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision); + void getShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); + void getUniformfv(GLuint program, GLint location, GLfloat *params); + void getUniformiv(GLuint program, GLint location, GLint *params); + GLint getUniformLocation(GLuint program, const GLchar *name); + GLboolean isBuffer(GLuint buffer); + GLboolean isEnabled(GLenum cap); + GLboolean isFramebuffer(GLuint framebuffer); + GLboolean isProgram(GLuint program); + GLboolean isRenderbuffer(GLuint renderbuffer); + GLboolean isShader(GLuint shader); + GLboolean isTexture(GLuint texture); + void linkProgram(GLuint program); + void releaseShaderCompiler(); + void shaderBinary(GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length); + void shaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length); + void stencilFunc(GLenum func, GLint ref, GLuint mask); + void stencilMask(GLuint mask); + void stencilOp(GLenum fail, GLenum zfail, GLenum zpass); + void uniform1f(GLint location, GLfloat x); + void uniform1fv(GLint location, GLsizei count, const GLfloat *v); + void uniform1i(GLint location, GLint x); + void uniform1iv(GLint location, GLsizei count, const GLint *v); + void uniform2f(GLint location, GLfloat x, GLfloat y); + void uniform2fv(GLint location, GLsizei count, const GLfloat *v); + void uniform2i(GLint location, GLint x, GLint y); + void uniform2iv(GLint location, GLsizei count, const GLint *v); + void uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z); + void uniform3fv(GLint location, GLsizei count, const GLfloat *v); + void uniform3i(GLint location, GLint x, GLint y, GLint z); + void uniform3iv(GLint location, GLsizei count, const GLint *v); + void uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform4fv(GLint location, GLsizei count, const GLfloat *v); + void uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w); + void uniform4iv(GLint location, GLsizei count, const GLint *v); + void uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void validateProgram(GLuint program); + void validateProgramPipeline(GLuint pipeline); + + void genQueries(GLsizei n, GLuint *ids); + void deleteQueries(GLsizei n, const GLuint *ids); + GLboolean isQuery(GLuint id); + + void uniform1ui(GLint location, GLuint v0); + void uniform2ui(GLint location, GLuint v0, GLuint v1); + void uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); + void uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); + void uniform1uiv(GLint location, GLsizei count, const GLuint *value); + void uniform2uiv(GLint location, GLsizei count, const GLuint *value); + void uniform3uiv(GLint location, GLsizei count, const GLuint *value); + void uniform4uiv(GLint location, GLsizei count, const GLuint *value); + + void uniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + void uniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void deleteVertexArrays(GLsizei n, const GLuint *arrays); + void genVertexArrays(GLsizei n, GLuint *arrays); + bool isVertexArray(GLuint array); + + void endTransformFeedback(); + void transformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode); + void getTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name); + + void deleteTransformFeedbacks(GLsizei n, const GLuint *ids); + void genTransformFeedbacks(GLsizei n, GLuint *ids); + bool isTransformFeedback(GLuint id); + void pauseTransformFeedback(); + void resumeTransformFeedback(); + + void getProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary); + void programBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); + + void getUniformuiv(GLuint program, GLint location, GLuint *params); + GLint getFragDataLocation(GLuint program, const GLchar *name); + void getUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices); + void getActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params); + GLuint getUniformBlockIndex(GLuint program, const GLchar *uniformBlockName); + void getActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); + void getActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName); + void uniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + + GLsync fenceSync(GLenum condition, GLbitfield flags); + GLboolean isSync(GLsync sync); + void deleteSync(GLsync sync); + GLenum clientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); + void waitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); + void getInteger64v(GLenum pname, GLint64 *params); + + void getBufferParameteri64v(BufferBinding target, GLenum pname, GLint64 *params); + void genSamplers(GLsizei count, GLuint *samplers); + void deleteSamplers(GLsizei count, const GLuint *samplers); + void getInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params); + + void programUniform1i(GLuint program, GLint location, GLint v0); + void programUniform2i(GLuint program, GLint location, GLint v0, GLint v1); + void programUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); + void programUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void programUniform1ui(GLuint program, GLint location, GLuint v0); + void programUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1); + void programUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); + void programUniform4ui(GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); + void programUniform1f(GLuint program, GLint location, GLfloat v0); + void programUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1); + void programUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void programUniform4f(GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3); + void programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value); + void programUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); + void programUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + void programUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); + + void programUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void programUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + + void deleteProgramPipelines(GLsizei n, const GLuint *pipelines); + void genProgramPipelines(GLsizei n, GLuint *pipelines); + GLboolean isProgramPipeline(GLuint pipeline); + + // Consumes the error. + void handleError(const Error &error) override; GLenum getError(); + void markContextLost(); + bool isContextLost(); GLenum getResetStatus(); - virtual bool isResetNotificationEnabled(); + bool isResetNotificationEnabled(); const egl::Config *getConfig() const; EGLenum getClientType() const; EGLenum getRenderBuffer() const; - const std::string &getRendererString() const; + const GLubyte *getString(GLenum name) const; + const GLubyte *getStringi(GLenum name, GLuint index) const; - const std::string &getExtensionString() const; - const std::string &getExtensionString(size_t idx) const; size_t getExtensionStringCount() const; - rx::Renderer *getRenderer() { return mRenderer; } + bool isExtensionRequestable(const char *name); + void requestExtension(const char *name); + size_t getRequestableExtensionStringCount() const; - State &getState() { return mState; } + rx::ContextImpl *getImplementation() const { return mImplementation.get(); } + const Workarounds &getWorkarounds() const; - void syncRendererState(); - void syncRendererState(const State::DirtyBits &bitMask); + void getFramebufferParameteriv(GLenum target, GLenum pname, GLint *params); + void framebufferParameteri(GLenum target, GLenum pname, GLint param); + + Error getScratchBuffer(size_t requestedSizeBytes, angle::MemoryBuffer **scratchBufferOut) const; + Error getZeroFilledBuffer(size_t requstedSizeBytes, angle::MemoryBuffer **zeroBufferOut) const; + + void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); + void dispatchComputeIndirect(GLintptr indirect); + + MemoryProgramCache *getMemoryProgramCache() const { return mMemoryProgramCache; } + + template + void gatherParams(ParamsT &&... params); + + void texStorage2D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height); + void texStorage3D(GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth); + + void memoryBarrier(GLbitfield barriers); + void memoryBarrierByRegion(GLbitfield barriers); + + // Notification for a state change in a Texture. + void onTextureChange(const Texture *texture); + + egl::Display *getCurrentDisplay() const { return mCurrentDisplay; } + egl::Surface *getCurrentDrawSurface() const { return mCurrentSurface; } + egl::Surface *getCurrentReadSurface() const { return mCurrentSurface; } + + bool isRobustResourceInitEnabled() const { return mGLState.isRobustResourceInitEnabled(); } private: - void checkVertexArrayAllocation(GLuint vertexArray); - void checkTransformFeedbackAllocation(GLuint transformFeedback); - Framebuffer *checkFramebufferAllocation(GLuint framebufferHandle); + Error prepareForDraw(); + void syncRendererState(); + void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask); + void syncStateForReadPixels(); + void syncStateForTexImage(); + void syncStateForClear(); + void syncStateForBlit(); + VertexArray *checkVertexArrayAllocation(GLuint vertexArrayHandle); + TransformFeedback *checkTransformFeedbackAllocation(GLuint transformFeedback); void detachBuffer(GLuint buffer); void detachTexture(GLuint texture); @@ -328,11 +1046,20 @@ class Context final : public ValidationContext void detachVertexArray(GLuint vertexArray); void detachTransformFeedback(GLuint transformFeedback); void detachSampler(GLuint sampler); + void detachProgramPipeline(GLuint pipeline); void initRendererString(); + void initVersionStrings(); void initExtensionStrings(); - void initCaps(GLuint clientVersion); + void initCaps(const egl::DisplayExtensions &displayExtensions, bool robustResourceInit); + void updateCaps(); + void initWorkarounds(); + + LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const; + LabeledObject *getLabeledObjectFromPtr(const void *ptr) const; + + std::unique_ptr mImplementation; // Caps to use for validation Caps mCaps; @@ -340,42 +1067,35 @@ class Context final : public ValidationContext Extensions mExtensions; Limitations mLimitations; - // Shader compiler - Compiler *mCompiler; - - rx::Renderer *const mRenderer; - State mState; + // Shader compiler. Lazily initialized hence the mutable value. + mutable BindingPointer mCompiler; - int mClientVersion; + State mGLState; const egl::Config *mConfig; EGLenum mClientType; TextureMap mZeroTextures; - typedef std::map FramebufferMap; - FramebufferMap mFramebufferMap; - HandleAllocator mFramebufferHandleAllocator; - - typedef std::map FenceNVMap; - FenceNVMap mFenceNVMap; + ResourceMap mFenceNVMap; HandleAllocator mFenceNVHandleAllocator; - typedef std::map QueryMap; - QueryMap mQueryMap; + ResourceMap mQueryMap; HandleAllocator mQueryHandleAllocator; - typedef std::map VertexArrayMap; - VertexArrayMap mVertexArrayMap; + ResourceMap mVertexArrayMap; HandleAllocator mVertexArrayHandleAllocator; - typedef std::map TransformFeedbackMap; - TransformFeedbackMap mTransformFeedbackMap; - HandleAllocator mTransformFeedbackAllocator; + ResourceMap mTransformFeedbackMap; + HandleAllocator mTransformFeedbackHandleAllocator; - std::string mRendererString; - std::string mExtensionString; - std::vector mExtensionStrings; + const char *mVersionString; + const char *mShadingLanguageString; + const char *mRendererString; + const char *mExtensionString; + std::vector mExtensionStrings; + const char *mRequestableExtensionString; + std::vector mRequestableExtensionStrings; // Recorded errors typedef std::set ErrorSet; @@ -385,13 +1105,50 @@ class Context final : public ValidationContext bool mHasBeenCurrent; bool mContextLost; GLenum mResetStatus; + bool mContextLostForced; GLenum mResetStrategy; bool mRobustAccess; egl::Surface *mCurrentSurface; - - ResourceManager *mResourceManager; + egl::Display *mCurrentDisplay; + Framebuffer *mSurfacelessFramebuffer; + bool mWebGLContext; + MemoryProgramCache *mMemoryProgramCache; + + State::DirtyBits mTexImageDirtyBits; + State::DirtyObjects mTexImageDirtyObjects; + State::DirtyBits mReadPixelsDirtyBits; + State::DirtyObjects mReadPixelsDirtyObjects; + State::DirtyBits mClearDirtyBits; + State::DirtyObjects mClearDirtyObjects; + State::DirtyBits mBlitDirtyBits; + State::DirtyObjects mBlitDirtyObjects; + + Workarounds mWorkarounds; + + // Not really a property of context state. The size and contexts change per-api-call. + mutable angle::ScratchBuffer mScratchBuffer; + mutable angle::ScratchBuffer mZeroFilledBuffer; }; +template +ANGLE_INLINE void Context::gatherParams(ArgsT &&... args) +{ + static_assert(sizeof(EntryPointParamType) <= kParamsBufferSize, + "Params struct too large, please increase kParamsBufferSize."); + + mSavedArgsType = &EntryPointParamType::TypeInfo; + + // Skip doing any work for ParamsBase/Invalid type. + if (!EntryPointParamType::TypeInfo.isValid()) + { + return; + } + + EntryPointParamType *objBuffer = + reinterpret_cast *>(mParamsBuffer.data()); + EntryPointParamType::template Factory(objBuffer, this, std::forward(args)...); +} + } // namespace gl -#endif // LIBANGLE_CONTEXT_H_ +#endif // LIBANGLE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ContextState.cpp b/src/3rdparty/angle/src/libANGLE/ContextState.cpp new file mode 100644 index 0000000000..d109cca76d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ContextState.cpp @@ -0,0 +1,839 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Data.cpp: Container class for all GL relevant state, caps and objects + +#include "libANGLE/ContextState.h" + +#include "libANGLE/Framebuffer.h" +#include "libANGLE/ResourceManager.h" + +namespace gl +{ + +namespace +{ + +template +using ContextStateMember = T *(ContextState::*); + +template +T *AllocateOrGetSharedResourceManager(const ContextState *shareContextState, + ContextStateMember member) +{ + if (shareContextState) + { + T *resourceManager = (*shareContextState).*member; + resourceManager->addRef(); + return resourceManager; + } + else + { + return new T(); + } +} + +TextureManager *AllocateOrGetSharedTextureManager(const ContextState *shareContextState, + TextureManager *shareTextures, + ContextStateMember member) +{ + if (shareContextState) + { + TextureManager *textureManager = (*shareContextState).*member; + ASSERT(shareTextures == nullptr || textureManager == shareTextures); + textureManager->addRef(); + return textureManager; + } + else if (shareTextures) + { + TextureManager *textureManager = shareTextures; + textureManager->addRef(); + return textureManager; + } + else + { + return new TextureManager(); + } +} + +} // anonymous namespace + +ContextState::ContextState(ContextID contextIn, + const ContextState *shareContextState, + TextureManager *shareTextures, + const Version &clientVersion, + State *stateIn, + const Caps &capsIn, + const TextureCapsMap &textureCapsIn, + const Extensions &extensionsIn, + const Limitations &limitationsIn) + : mClientVersion(clientVersion), + mContext(contextIn), + mState(stateIn), + mCaps(capsIn), + mTextureCaps(textureCapsIn), + mExtensions(extensionsIn), + mLimitations(limitationsIn), + mBuffers(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mBuffers)), + mShaderPrograms( + AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mShaderPrograms)), + mTextures(AllocateOrGetSharedTextureManager(shareContextState, + shareTextures, + &ContextState::mTextures)), + mRenderbuffers( + AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mRenderbuffers)), + mSamplers(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mSamplers)), + mSyncs(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mSyncs)), + mPaths(AllocateOrGetSharedResourceManager(shareContextState, &ContextState::mPaths)), + mFramebuffers(new FramebufferManager()), + mPipelines(new ProgramPipelineManager()) +{ +} + +ContextState::~ContextState() +{ + // Handles are released by the Context. +} + +bool ContextState::isWebGL() const +{ + return mExtensions.webglCompatibility; +} + +bool ContextState::isWebGL1() const +{ + return (isWebGL() && mClientVersion.major == 2); +} + +const TextureCaps &ContextState::getTextureCap(GLenum internalFormat) const +{ + return mTextureCaps.get(internalFormat); +} + +ValidationContext::ValidationContext(const ValidationContext *shareContext, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations, + bool skipValidation) + : mState(reinterpret_cast(this), + shareContext ? &shareContext->mState : nullptr, + shareTextures, + clientVersion, + state, + caps, + textureCaps, + extensions, + limitations), + mSkipValidation(skipValidation), + mDisplayTextureShareGroup(shareTextures != nullptr) +{ +} + +ValidationContext::~ValidationContext() +{ +} + +bool ValidationContext::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation + // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due + // to the fact that it is stored internally as a float, and so would require conversion + // if returned from Context::getIntegerv. Since this conversion is already implemented + // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we + // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling + // application. + switch (pname) + { + case GL_COMPRESSED_TEXTURE_FORMATS: + { + *type = GL_INT; + *numParams = static_cast(getCaps().compressedTextureFormats.size()); + return true; + } + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = static_cast(getCaps().shaderBinaryFormats.size()); + return true; + } + + case GL_MAX_VERTEX_ATTRIBS: + case GL_MAX_VERTEX_UNIFORM_VECTORS: + case GL_MAX_VARYING_VECTORS: + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GL_MAX_TEXTURE_IMAGE_UNITS: + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + case GL_MAX_RENDERBUFFER_SIZE: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + case GL_FRAMEBUFFER_BINDING: + case GL_RENDERBUFFER_BINDING: + case GL_CURRENT_PROGRAM: + case GL_PACK_ALIGNMENT: + case GL_UNPACK_ALIGNMENT: + case GL_GENERATE_MIPMAP_HINT: + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + case GL_DEPTH_BITS: + case GL_STENCIL_BITS: + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + case GL_CULL_FACE_MODE: + case GL_FRONT_FACE: + case GL_ACTIVE_TEXTURE: + case GL_STENCIL_FUNC: + case GL_STENCIL_VALUE_MASK: + case GL_STENCIL_REF: + case GL_STENCIL_FAIL: + case GL_STENCIL_PASS_DEPTH_FAIL: + case GL_STENCIL_PASS_DEPTH_PASS: + case GL_STENCIL_BACK_FUNC: + case GL_STENCIL_BACK_VALUE_MASK: + case GL_STENCIL_BACK_REF: + case GL_STENCIL_BACK_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_PASS: + case GL_DEPTH_FUNC: + case GL_BLEND_SRC_RGB: + case GL_BLEND_SRC_ALPHA: + case GL_BLEND_DST_RGB: + case GL_BLEND_DST_ALPHA: + case GL_BLEND_EQUATION_RGB: + case GL_BLEND_EQUATION_ALPHA: + case GL_STENCIL_WRITEMASK: + case GL_STENCIL_BACK_WRITEMASK: + case GL_STENCIL_CLEAR_VALUE: + case GL_SUBPIXEL_BITS: + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + { + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + { + if (!getExtensions().packReverseRowOrder) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + { + if (!getExtensions().textureRectangle) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_MAX_DRAW_BUFFERS_EXT: + case GL_MAX_COLOR_ATTACHMENTS_EXT: + { + if ((getClientMajorVersion() < 3) && !getExtensions().drawBuffers) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_MAX_VIEWPORT_DIMS: + { + *type = GL_INT; + *numParams = 2; + return true; + } + case GL_VIEWPORT: + case GL_SCISSOR_BOX: + { + *type = GL_INT; + *numParams = 4; + return true; + } + case GL_SHADER_COMPILER: + case GL_SAMPLE_COVERAGE_INVERT: + case GL_DEPTH_WRITEMASK: + case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, + case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. + case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as + // bool-natural + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + case GL_COLOR_WRITEMASK: + { + *type = GL_BOOL; + *numParams = 4; + return true; + } + case GL_POLYGON_OFFSET_FACTOR: + case GL_POLYGON_OFFSET_UNITS: + case GL_SAMPLE_COVERAGE_VALUE: + case GL_DEPTH_CLEAR_VALUE: + case GL_LINE_WIDTH: + { + *type = GL_FLOAT; + *numParams = 1; + return true; + } + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + { + *type = GL_FLOAT; + *numParams = 2; + return true; + } + case GL_COLOR_CLEAR_VALUE: + case GL_BLEND_COLOR: + { + *type = GL_FLOAT; + *numParams = 4; + return true; + } + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!getExtensions().textureFilterAnisotropic) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + return true; + case GL_TIMESTAMP_EXT: + if (!getExtensions().disjointTimerQuery) + { + return false; + } + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + case GL_GPU_DISJOINT_EXT: + if (!getExtensions().disjointTimerQuery) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_COVERAGE_MODULATION_CHROMIUM: + if (!getExtensions().framebufferMixedSamples) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + if (!getExtensions().eglStreamConsumerExternal && !getExtensions().eglImageExternal) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getExtensions().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; + } + } + + if (getExtensions().multisampleCompatibility) + { + switch (pname) + { + case GL_MULTISAMPLE_EXT: + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().pathRendering) + { + switch (pname) + { + case GL_PATH_MODELVIEW_MATRIX_CHROMIUM: + case GL_PATH_PROJECTION_MATRIX_CHROMIUM: + *type = GL_FLOAT; + *numParams = 16; + return true; + } + } + + if (getExtensions().bindGeneratesResource) + { + switch (pname) + { + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().clientArrays) + { + switch (pname) + { + case GL_CLIENT_ARRAYS_ANGLE: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().sRGBWriteControl) + { + switch (pname) + { + case GL_FRAMEBUFFER_SRGB_EXT: + *type = GL_BOOL; + *numParams = 1; + return true; + } + } + + if (getExtensions().robustResourceInitialization && + pname == GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE) + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + + if (getExtensions().programCacheControl && pname == GL_PROGRAM_CACHE_ENABLED_ANGLE) + { + *type = GL_BOOL; + *numParams = 1; + return true; + } + + // Check for ES3.0+ parameter names which are also exposed as ES2 extensions + switch (pname) + { + // case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE // equivalent to FRAMEBUFFER_BINDING + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: + if ((getClientMajorVersion() < 3) && !getExtensions().framebufferBlit) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + if ((getClientMajorVersion() < 3) && !getExtensions().getProgramBinary) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_PROGRAM_BINARY_FORMATS_OES: + if ((getClientMajorVersion() < 3) && !getExtensions().getProgramBinary) + { + return false; + } + *type = GL_INT; + *numParams = static_cast(getCaps().programBinaryFormats.size()); + return true; + + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + if ((getClientMajorVersion() < 3) && !getExtensions().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 ((getClientMajorVersion() < 3) && !getExtensions().unpackSubimage) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_VERTEX_ARRAY_BINDING: + if ((getClientMajorVersion() < 3) && !getExtensions().vertexArrayObject) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: + if ((getClientMajorVersion() < 3) && !getExtensions().pixelBufferObject) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + case GL_MAX_SAMPLES: + { + static_assert(GL_MAX_SAMPLES_ANGLE == GL_MAX_SAMPLES, + "GL_MAX_SAMPLES_ANGLE not equal to GL_MAX_SAMPLES"); + if ((getClientMajorVersion() < 3) && !getExtensions().framebufferMultisample) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: + if ((getClientMajorVersion() < 3) && !getExtensions().standardDerivatives) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + } + + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + if ((getClientVersion() < Version(3, 0)) && !getExtensions().drawBuffers) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getExtensions().multiview && pname == GL_MAX_VIEWS_ANGLE) + { + *type = GL_INT; + *numParams = 1; + return true; + } + + if (getClientVersion() < Version(3, 0)) + { + return false; + } + + // Check for ES3.0+ parameter names + switch (pname) + { + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + 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_SAMPLER_BINDING: + case GL_READ_BUFFER: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_ARRAY_TEXTURE_LAYERS: + 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_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: + case GL_MAX_ELEMENTS_INDICES: + case GL_MAX_ELEMENTS_VERTICES: + 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; + return true; + } + + case GL_MAX_ELEMENT_INDEX: + case GL_MAX_UNIFORM_BLOCK_SIZE: + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MAX_SERVER_WAIT_TIMEOUT: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + } + + 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; + } + } + + if (getExtensions().requestExtension) + { + switch (pname) + { + case GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE: + *type = GL_INT; + *numParams = 1; + return true; + } + } + + if (getClientVersion() < Version(3, 1)) + { + return false; + } + + switch (pname) + { + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + case GL_DRAW_INDIRECT_BUFFER_BINDING: + case GL_MAX_FRAMEBUFFER_WIDTH: + case GL_MAX_FRAMEBUFFER_HEIGHT: + case GL_MAX_FRAMEBUFFER_SAMPLES: + case GL_MAX_SAMPLE_MASK_WORDS: + case GL_MAX_COLOR_TEXTURE_SAMPLES: + case GL_MAX_DEPTH_TEXTURE_SAMPLES: + case GL_MAX_INTEGER_SAMPLES: + case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: + case GL_MAX_VERTEX_ATTRIB_BINDINGS: + case GL_MAX_VERTEX_ATTRIB_STRIDE: + case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_VERTEX_ATOMIC_COUNTERS: + case GL_MAX_VERTEX_IMAGE_UNIFORMS: + case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: + case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: + case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: + case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: + case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: + case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: + case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: + case GL_MAX_COMPUTE_UNIFORM_BLOCKS: + case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: + case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: + case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: + case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_COMPUTE_ATOMIC_COUNTERS: + case GL_MAX_COMPUTE_IMAGE_UNIFORMS: + case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: + case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: + case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: + case GL_MAX_UNIFORM_LOCATIONS: + case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: + case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: + case GL_MAX_COMBINED_ATOMIC_COUNTERS: + case GL_MAX_IMAGE_UNITS: + case GL_MAX_COMBINED_IMAGE_UNIFORMS: + case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: + case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: + case GL_SHADER_STORAGE_BUFFER_BINDING: + case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + *type = GL_INT; + *numParams = 1; + return true; + case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + case GL_SAMPLE_MASK: + *type = GL_BOOL; + *numParams = 1; + return true; + } + + return false; +} + +bool ValidationContext::getIndexedQueryParameterInfo(GLenum target, + GLenum *type, + unsigned int *numParams) +{ + if (getClientVersion() < Version(3, 0)) + { + return false; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + case GL_UNIFORM_BUFFER_BINDING: + { + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + } + } + + if (getClientVersion() < Version(3, 1)) + { + return false; + } + + switch (target) + { + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + case GL_SHADER_STORAGE_BUFFER_BINDING: + case GL_VERTEX_BINDING_BUFFER: + case GL_VERTEX_BINDING_DIVISOR: + case GL_VERTEX_BINDING_OFFSET: + case GL_VERTEX_BINDING_STRIDE: + case GL_SAMPLE_MASK_VALUE: + { + *type = GL_INT; + *numParams = 1; + return true; + } + case GL_ATOMIC_COUNTER_BUFFER_START: + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_SHADER_STORAGE_BUFFER_START: + case GL_SHADER_STORAGE_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + return true; + } + } + + return false; +} + +Program *ValidationContext::getProgram(GLuint handle) const +{ + return mState.mShaderPrograms->getProgram(handle); +} + +Shader *ValidationContext::getShader(GLuint handle) const +{ + return mState.mShaderPrograms->getShader(handle); +} + +bool ValidationContext::isTextureGenerated(GLuint texture) const +{ + return mState.mTextures->isHandleGenerated(texture); +} + +bool ValidationContext::isBufferGenerated(GLuint buffer) const +{ + return mState.mBuffers->isHandleGenerated(buffer); +} + +bool ValidationContext::isRenderbufferGenerated(GLuint renderbuffer) const +{ + return mState.mRenderbuffers->isHandleGenerated(renderbuffer); +} + +bool ValidationContext::isFramebufferGenerated(GLuint framebuffer) const +{ + return mState.mFramebuffers->isHandleGenerated(framebuffer); +} + +bool ValidationContext::isProgramPipelineGenerated(GLuint pipeline) const +{ + return mState.mPipelines->isHandleGenerated(pipeline); +} + +bool ValidationContext::usingDisplayTextureShareGroup() const +{ + return mDisplayTextureShareGroup; +} + +GLenum ValidationContext::getConvertedRenderbufferFormat(GLenum internalformat) const +{ + return mState.mExtensions.webglCompatibility && mState.mClientVersion.major == 2 && + internalformat == GL_DEPTH_STENCIL + ? GL_DEPTH24_STENCIL8 + : internalformat; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ContextState.h b/src/3rdparty/angle/src/libANGLE/ContextState.h new file mode 100644 index 0000000000..e6e9f4c6b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ContextState.h @@ -0,0 +1,164 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ContextState: Container class for all GL context state, caps and objects. + +#ifndef LIBANGLE_CONTEXTSTATE_H_ +#define LIBANGLE_CONTEXTSTATE_H_ + +#include "common/MemoryBuffer.h" +#include "common/angleutils.h" +#include "libANGLE/State.h" +#include "libANGLE/Version.h" +#include "libANGLE/params.h" + +namespace gl +{ +class BufferManager; +class ContextState; +class FramebufferManager; +class PathManager; +class ProgramPipelineManager; +class RenderbufferManager; +class SamplerManager; +class ShaderProgramManager; +class SyncManager; +class TextureManager; +class ValidationContext; + +static constexpr Version ES_2_0 = Version(2, 0); +static constexpr Version ES_3_0 = Version(3, 0); +static constexpr Version ES_3_1 = Version(3, 1); + +using ContextID = uintptr_t; + +class ContextState final : angle::NonCopyable +{ + public: + ContextState(ContextID context, + const ContextState *shareContextState, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations); + ~ContextState(); + + ContextID getContextID() const { return mContext; } + GLint getClientMajorVersion() const { return mClientVersion.major; } + GLint getClientMinorVersion() const { return mClientVersion.minor; } + const Version &getClientVersion() const { return mClientVersion; } + const State &getState() const { return *mState; } + const Caps &getCaps() const { return mCaps; } + const TextureCapsMap &getTextureCaps() const { return mTextureCaps; } + const Extensions &getExtensions() const { return mExtensions; } + const Limitations &getLimitations() const { return mLimitations; } + + const TextureCaps &getTextureCap(GLenum internalFormat) const; + + bool usingDisplayTextureShareGroup() const; + + bool isWebGL() const; + bool isWebGL1() const; + + private: + friend class Context; + friend class ValidationContext; + + Version mClientVersion; + ContextID mContext; + State *mState; + const Caps &mCaps; + const TextureCapsMap &mTextureCaps; + const Extensions &mExtensions; + const Limitations &mLimitations; + + BufferManager *mBuffers; + ShaderProgramManager *mShaderPrograms; + TextureManager *mTextures; + RenderbufferManager *mRenderbuffers; + SamplerManager *mSamplers; + SyncManager *mSyncs; + PathManager *mPaths; + FramebufferManager *mFramebuffers; + ProgramPipelineManager *mPipelines; +}; + +class ValidationContext : angle::NonCopyable +{ + public: + ValidationContext(const ValidationContext *shareContext, + TextureManager *shareTextures, + const Version &clientVersion, + State *state, + const Caps &caps, + const TextureCapsMap &textureCaps, + const Extensions &extensions, + const Limitations &limitations, + bool skipValidation); + virtual ~ValidationContext(); + + virtual void handleError(const Error &error) = 0; + + const ContextState &getContextState() const { return mState; } + GLint getClientMajorVersion() const { return mState.getClientMajorVersion(); } + GLint getClientMinorVersion() const { return mState.getClientMinorVersion(); } + const Version &getClientVersion() const { return mState.getClientVersion(); } + const State &getGLState() const { return mState.getState(); } + const Caps &getCaps() const { return mState.getCaps(); } + const TextureCapsMap &getTextureCaps() const { return mState.getTextureCaps(); } + const Extensions &getExtensions() const { return mState.getExtensions(); } + const Limitations &getLimitations() const { return mState.getLimitations(); } + bool skipValidation() const { return mSkipValidation; } + + // Specific methods needed for validation. + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); + + Program *getProgram(GLuint handle) const; + Shader *getShader(GLuint handle) const; + + bool isTextureGenerated(GLuint texture) const; + bool isBufferGenerated(GLuint buffer) const; + bool isRenderbufferGenerated(GLuint renderbuffer) const; + bool isFramebufferGenerated(GLuint framebuffer) const; + bool isProgramPipelineGenerated(GLuint pipeline) const; + + bool usingDisplayTextureShareGroup() const; + + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum getConvertedRenderbufferFormat(GLenum internalformat) const; + + bool isWebGL() const { return mState.isWebGL(); } + bool isWebGL1() const { return mState.isWebGL1(); } + + template + const T &getParams() const; + + protected: + ContextState mState; + bool mSkipValidation; + bool mDisplayTextureShareGroup; + + // Caches entry point parameters and values re-used between layers. + mutable const ParamTypeInfo *mSavedArgsType; + static constexpr size_t kParamsBufferSize = 64u; + mutable std::array mParamsBuffer; +}; + +template +const T &ValidationContext::getParams() const +{ + const T *params = reinterpret_cast(mParamsBuffer.data()); + ASSERT(mSavedArgsType->hasDynamicType(T::TypeInfo)); + return *params; +} + +} // namespace gl + +#endif // LIBANGLE_CONTEXTSTATE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Data.cpp b/src/3rdparty/angle/src/libANGLE/Data.cpp deleted file mode 100644 index 83f04b5a0b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/Data.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Data.cpp: Container class for all GL relevant state, caps and objects - -#include "libANGLE/Data.h" -#include "libANGLE/ResourceManager.h" - -namespace gl -{ - -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), - limitations(&limitationsIn) -{} - -Data::~Data() -{ -} - -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) -{ -} -} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Data.h b/src/3rdparty/angle/src/libANGLE/Data.h deleted file mode 100644 index f7230d74bc..0000000000 --- a/src/3rdparty/angle/src/libANGLE/Data.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Data.h: Container class for all GL relevant state, caps and objects - -#ifndef LIBANGLE_DATA_H_ -#define LIBANGLE_DATA_H_ - -#include "common/angleutils.h" -#include "libANGLE/State.h" - -namespace gl -{ - -struct Data final : public angle::NonCopyable -{ - public: - 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(); - - 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; -}; - -} - -#endif // LIBANGLE_DATA_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Debug.cpp b/src/3rdparty/angle/src/libANGLE/Debug.cpp index 30321f4160..96f30df98c 100644 --- a/src/3rdparty/angle/src/libANGLE/Debug.cpp +++ b/src/3rdparty/angle/src/libANGLE/Debug.cpp @@ -16,6 +16,26 @@ namespace gl { +Debug::Control::Control() +{ +} + +Debug::Control::~Control() +{ +} + +Debug::Control::Control(const Control &other) = default; + +Debug::Group::Group() +{ +} + +Debug::Group::~Group() +{ +} + +Debug::Group::Group(const Group &other) = default; + Debug::Debug() : mOutputEnabled(false), mCallbackFunction(nullptr), @@ -28,6 +48,10 @@ Debug::Debug() pushDefaultGroup(); } +Debug::~Debug() +{ +} + void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages) { mMaxLoggedMessages = maxLoggedMessages; diff --git a/src/3rdparty/angle/src/libANGLE/Debug.h b/src/3rdparty/angle/src/libANGLE/Debug.h index f545b815e4..2c15c25e9a 100644 --- a/src/3rdparty/angle/src/libANGLE/Debug.h +++ b/src/3rdparty/angle/src/libANGLE/Debug.h @@ -31,6 +31,7 @@ class Debug : angle::NonCopyable { public: Debug(); + ~Debug(); void setMaxLoggedMessages(GLuint maxLoggedMessages); @@ -91,6 +92,10 @@ class Debug : angle::NonCopyable struct Control { + Control(); + ~Control(); + Control(const Control &other); + GLenum source; GLenum type; GLenum severity; @@ -100,6 +105,10 @@ class Debug : angle::NonCopyable struct Group { + Group(); + ~Group(); + Group(const Group &other); + GLenum source; GLuint id; std::string message; diff --git a/src/3rdparty/angle/src/libANGLE/Device.cpp b/src/3rdparty/angle/src/libANGLE/Device.cpp index eb30b2023f..3ebf48b919 100644 --- a/src/3rdparty/angle/src/libANGLE/Device.cpp +++ b/src/3rdparty/angle/src/libANGLE/Device.cpp @@ -45,33 +45,28 @@ static DeviceSet *GetDeviceSet() // Static factory methods egl::Error Device::CreateDevice(void *devicePointer, EGLint deviceType, Device **outDevice) { + *outDevice = nullptr; + #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); + std::unique_ptr deviceD3D(new rx::DeviceD3D()); + ANGLE_TRY(deviceD3D->initialize(devicePointer, deviceType, EGL_TRUE)); + *outDevice = new Device(nullptr, deviceD3D.release()); GetDeviceSet()->insert(*outDevice); - return egl::Error(EGL_SUCCESS); + return NoError(); } #endif // Note that creating an EGL device from inputted D3D9 parameters isn't currently supported - *outDevice = nullptr; - return egl::Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } egl::Error Device::CreateDevice(Display *owningDisplay, rx::DeviceImpl *impl, Device **outDevice) { *outDevice = new Device(owningDisplay, impl); GetDeviceSet()->insert(*outDevice); - return egl::Error(EGL_SUCCESS); + return NoError(); } bool Device::IsValidDevice(Device *device) diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp index 486c74abc0..735b472787 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.cpp +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -28,6 +28,8 @@ #include "libANGLE/histogram_macros.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" +#include "libANGLE/Stream.h" +#include "libANGLE/ResourceManager.h" #include "libANGLE/renderer/DisplayImpl.h" #include "libANGLE/renderer/ImageImpl.h" #include "third_party/trace_event/trace_event.h" @@ -43,38 +45,34 @@ # include "libANGLE/renderer/gl/glx/DisplayGLX.h" # elif defined(ANGLE_PLATFORM_APPLE) # include "libANGLE/renderer/gl/cgl/DisplayCGL.h" +# elif defined(ANGLE_USE_OZONE) +# include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h" +# elif defined(ANGLE_PLATFORM_ANDROID) +# include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h" # else # error Unsupported OpenGL platform. # endif #endif -namespace egl -{ +#if defined(ANGLE_ENABLE_NULL) +#include "libANGLE/renderer/null/DisplayNULL.h" +#endif // defined(ANGLE_ENABLE_NULL) -namespace -{ +#if defined(ANGLE_ENABLE_VULKAN) +#if defined(ANGLE_PLATFORM_WINDOWS) +#include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h" +#elif defined(ANGLE_PLATFORM_LINUX) +#include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h" +#else +#error Unsupported Vulkan platform. +#endif +#endif // defined(ANGLE_ENABLE_VULKAN) -class DefaultPlatform : public angle::Platform +namespace egl { -public: - DefaultPlatform() {} - ~DefaultPlatform() override {} -}; -DefaultPlatform *defaultPlatform = nullptr; - -void InitDefaultPlatformImpl() +namespace { - if (ANGLEPlatformCurrent() == nullptr) - { - if (defaultPlatform == nullptr) - { - defaultPlatform = new DefaultPlatform(); - } - - ANGLEPlatformInitialize(defaultPlatform); - } -} typedef std::map WindowSurfaceMap; // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface @@ -99,7 +97,7 @@ static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap() return &displays; } -rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) +rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state) { rx::DisplayImpl *impl = nullptr; @@ -107,7 +105,7 @@ rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) { #if defined(ANGLE_ENABLE_D3D11) case EGL_D3D11_DEVICE_ANGLE: - impl = new rx::DisplayD3D(); + impl = new rx::DisplayD3D(state); break; #endif #if defined(ANGLE_ENABLE_D3D9) @@ -130,86 +128,162 @@ rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice) return impl; } -rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap) +rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap, const DisplayState &state) { rx::DisplayImpl *impl = nullptr; - EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + EGLAttrib displayType = + attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); switch (displayType) { - case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) - // Default to D3D displays - impl = new rx::DisplayD3D(); + // Default to D3D displays + impl = new rx::DisplayD3D(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); #elif defined(ANGLE_PLATFORM_APPLE) - impl = new rx::DisplayCGL(); + impl = new rx::DisplayCGL(state); +#elif defined(ANGLE_USE_OZONE) + impl = new rx::DisplayOzone(state); +#elif defined(ANGLE_PLATFORM_ANDROID) + impl = new rx::DisplayAndroid(state); #else - // No display available - UNREACHABLE(); + // No display available + UNREACHABLE(); #endif - break; + break; - case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) - impl = new rx::DisplayD3D(); + impl = new rx::DisplayD3D(state); #else - // A D3D display was requested on a platform that doesn't support it - UNREACHABLE(); + // A D3D display was requested on a platform that doesn't support it + UNREACHABLE(); #endif - break; + break; - case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: #if defined(ANGLE_ENABLE_OPENGL) #if defined(ANGLE_PLATFORM_WINDOWS) - impl = new rx::DisplayWGL(); + impl = new rx::DisplayWGL(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); #elif defined(ANGLE_PLATFORM_APPLE) - impl = new rx::DisplayCGL(); + impl = new rx::DisplayCGL(state); +#elif defined(ANGLE_USE_OZONE) + // This might work but has never been tried, so disallow for now. + impl = nullptr; +#elif defined(ANGLE_PLATFORM_ANDROID) + // No GL support on this platform, fail display creation. + impl = nullptr; #else #error Unsupported OpenGL platform. #endif #else - UNREACHABLE(); -#endif - break; + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_OPENGL) + break; + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: #if defined(ANGLE_ENABLE_OPENGL) - case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: #if defined(ANGLE_PLATFORM_WINDOWS) - impl = new rx::DisplayWGL(); + impl = new rx::DisplayWGL(state); #elif defined(ANGLE_USE_X11) - impl = new rx::DisplayGLX(); + impl = new rx::DisplayGLX(state); +#elif defined(ANGLE_USE_OZONE) + impl = new rx::DisplayOzone(state); +#elif defined(ANGLE_PLATFORM_ANDROID) + impl = new rx::DisplayAndroid(state); #else - // No GLES support on this platform, fail display creation. - impl = nullptr; + // No GLES support on this platform, fail display creation. + impl = nullptr; #endif - break; +#endif // defined(ANGLE_ENABLE_OPENGL) + break; + + case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: +#if defined(ANGLE_ENABLE_VULKAN) +#if defined(ANGLE_PLATFORM_WINDOWS) + impl = new rx::DisplayVkWin32(state); +#elif defined(ANGLE_PLATFORM_LINUX) + impl = new rx::DisplayVkXcb(state); +#else +#error Unsupported Vulkan platform. #endif +#else + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_VULKAN) + break; - default: - UNREACHABLE(); - break; + case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: +#if defined(ANGLE_ENABLE_NULL) + impl = new rx::DisplayNULL(state); +#else + // No display available + UNREACHABLE(); +#endif // defined(ANGLE_ENABLE_NULL) + break; + + default: + UNREACHABLE(); + break; } return impl; } +void Display_logError(angle::PlatformMethods *platform, const char *errorMessage) +{ + gl::Trace(gl::LOG_ERR, errorMessage); } -Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap) +void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage) { - // Initialize the global platform if not already - InitDefaultPlatformImpl(); + gl::Trace(gl::LOG_WARN, warningMessage); +} - Display *display = nullptr; +void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage) +{ + // Uncomment to get info spam + // gl::Trace(gl::LOG_WARN, infoMessage); +} + +void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display) +{ + angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent(); + if (platformMethods->logError != angle::DefaultLogError) + { + // Don't reset pre-set Platform to Default + return; + } + + ANGLEResetDisplayPlatform(display); + platformMethods->logError = Display_logError; + platformMethods->logWarning = Display_logWarning; + platformMethods->logInfo = Display_logInfo; +} + +} // anonymous namespace - EGLNativeDisplayType displayId = reinterpret_cast(native_display); +DisplayState::DisplayState() +{ +} + +DisplayState::~DisplayState() +{ +} - ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); - ANGLEPlatformDisplayMap::const_iterator iter = displays->find(displayId); +// static +Display *Display::GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap) +{ + Display *display = nullptr; + + ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); + const auto &iter = displays->find(nativeDisplay); if (iter != displays->end()) { display = iter->second; @@ -218,19 +292,19 @@ Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap if (display == nullptr) { // Validate the native display - if (!Display::isValidNativeDisplay(displayId)) + if (!Display::isValidNativeDisplay(nativeDisplay)) { - return NULL; + return nullptr; } - display = new Display(EGL_PLATFORM_ANGLE_ANGLE, displayId, nullptr); - displays->insert(std::make_pair(displayId, display)); + display = new Display(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, nullptr); + displays->insert(std::make_pair(nativeDisplay, display)); } // Apply new attributes if the display is not initialized yet. if (!display->isInitialized()) { - rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap); + rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap, display->getState()); if (impl == nullptr) { // No valid display implementation for these attributes @@ -243,15 +317,12 @@ Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap return display; } -Display *Display::GetDisplayFromDevice(void *native_display) +// static +Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap) { - // Initialize the global platform if not already - InitDefaultPlatformImpl(); - Display *display = nullptr; - Device *eglDevice = reinterpret_cast(native_display); - ASSERT(Device::IsValidDevice(eglDevice)); + ASSERT(Device::IsValidDevice(device)); ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap(); DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap(); @@ -260,7 +331,7 @@ Display *Display::GetDisplayFromDevice(void *native_display) for (auto &displayMapEntry : *anglePlatformDisplays) { egl::Display *iterDisplay = displayMapEntry.second; - if (iterDisplay->getDevice() == eglDevice) + if (iterDisplay->getDevice() == device) { display = iterDisplay; } @@ -269,7 +340,7 @@ Display *Display::GetDisplayFromDevice(void *native_display) 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); + const auto &iter = devicePlatformDisplays->find(device); if (iter != devicePlatformDisplays->end()) { display = iter->second; @@ -279,15 +350,15 @@ Display *Display::GetDisplayFromDevice(void *native_display) if (display == nullptr) { // Otherwise create a new Display - display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, eglDevice); - devicePlatformDisplays->insert(std::make_pair(eglDevice, display)); + display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device); + devicePlatformDisplays->insert(std::make_pair(device, display)); } // Apply new attributes if the display is not initialized yet. if (!display->isInitialized()) { - rx::DisplayImpl *impl = CreateDisplayFromDevice(eglDevice); - display->setAttributes(impl, egl::AttributeMap()); + rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState()); + display->setAttributes(impl, attribMap); } return display; @@ -299,19 +370,26 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe mAttributeMap(), mConfigSet(), mContextSet(), + mStreamSet(), mInitialized(false), + mDeviceLost(false), mCaps(), mDisplayExtensions(), mDisplayExtensionString(), mVendorString(), mDevice(eglDevice), - mPlatform(platform) + mPlatform(platform), + mTextureManager(nullptr), + mMemoryProgramCache(gl::kDefaultMaxProgramCacheMemoryBytes), + mGlobalTextureShareGroupUsers(0), + mProxyContext(this) { } Display::~Display() { - terminate(); + // TODO(jmadill): When is this called? + // terminate(); if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE) { @@ -336,6 +414,8 @@ Display::~Display() UNREACHABLE(); } + mProxyContext.reset(nullptr); + SafeDelete(mDevice); SafeDelete(mImplementation); } @@ -353,8 +433,20 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap Error Display::initialize() { - // Re-initialize default platform if it's needed - InitDefaultPlatformImpl(); + // TODO(jmadill): Store Platform in Display and init here. + const angle::PlatformMethods *platformMethods = + reinterpret_cast( + mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0)); + if (platformMethods != nullptr) + { + *ANGLEPlatformCurrent() = *platformMethods; + } + else + { + ANGLESetDefaultDisplayPlatform(this); + } + + gl::InitializeDebugAnnotations(&mAnnotator); SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS"); TRACE_EVENT0("gpu.angle", "egl::Display::initialize"); @@ -363,17 +455,14 @@ Error Display::initialize() if (isInitialized()) { - return Error(EGL_SUCCESS); + return NoError(); } 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()); + ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage(); return error; } @@ -383,7 +472,7 @@ Error Display::initialize() if (mConfigSet.size() == 0) { mImplementation->terminate(); - return Error(EGL_NOT_INITIALIZED); + return EglNotInitialized(); } initDisplayExtensions(); @@ -395,17 +484,8 @@ Error Display::initialize() 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; - } + ANGLE_TRY(mImplementation->getDevice(&impl)); + ANGLE_TRY(Device::CreateDevice(this, impl, &mDevice)); } else { @@ -419,28 +499,45 @@ Error Display::initialize() ASSERT(mDevice != nullptr); } + mProxyContext.reset(nullptr); + gl::Context *proxyContext = new gl::Context(mImplementation, nullptr, nullptr, nullptr, nullptr, + egl::AttributeMap(), mDisplayExtensions); + mProxyContext.reset(proxyContext); + mInitialized = true; - return Error(EGL_SUCCESS); + return NoError(); } -void Display::terminate() +Error Display::terminate() { - makeCurrent(nullptr, nullptr, nullptr); + ANGLE_TRY(makeCurrent(nullptr, nullptr, nullptr)); + + mMemoryProgramCache.clear(); + + mProxyContext.reset(nullptr); while (!mContextSet.empty()) { - destroyContext(*mContextSet.begin()); + ANGLE_TRY(destroyContext(*mContextSet.begin())); } + // The global texture manager should be deleted with the last context that uses it. + ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr); + while (!mImageSet.empty()) { destroyImage(*mImageSet.begin()); } - while (!mImplementation->getSurfaceSet().empty()) + while (!mStreamSet.empty()) { - destroySurface(*mImplementation->getSurfaceSet().begin()); + destroyStream(*mStreamSet.begin()); + } + + while (!mState.surfaceSet.empty()) + { + ANGLE_TRY(destroySurface(*mState.surfaceSet.begin())); } mConfigSet.clear(); @@ -454,9 +551,16 @@ void Display::terminate() mImplementation->terminate(); + mDeviceLost = false; + mInitialized = false; - // Never de-init default platform.. terminate is not that final. + gl::UninitializeDebugAnnotations(); + + // TODO(jmadill): Store Platform in Display and deinit here. + ANGLEResetDisplayPlatform(this); + + return NoError(); } std::vector Display::getConfigs(const egl::AttributeMap &attribs) const @@ -464,189 +568,100 @@ std::vector Display::getConfigs(const egl::AttributeMap &attribs) return mConfigSet.filter(attribs); } -bool Display::getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value) -{ - switch (attribute) - { - case EGL_BUFFER_SIZE: *value = configuration->bufferSize; break; - case EGL_ALPHA_SIZE: *value = configuration->alphaSize; break; - case EGL_BLUE_SIZE: *value = configuration->blueSize; break; - case EGL_GREEN_SIZE: *value = configuration->greenSize; break; - case EGL_RED_SIZE: *value = configuration->redSize; break; - case EGL_DEPTH_SIZE: *value = configuration->depthSize; break; - case EGL_STENCIL_SIZE: *value = configuration->stencilSize; break; - case EGL_CONFIG_CAVEAT: *value = configuration->configCaveat; break; - 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; - case EGL_SURFACE_TYPE: *value = configuration->surfaceType; break; - case EGL_TRANSPARENT_TYPE: *value = configuration->transparentType; break; - case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->transparentBlueValue; break; - case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->transparentGreenValue; break; - case EGL_TRANSPARENT_RED_VALUE: *value = configuration->transparentRedValue; break; - case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->bindToTextureRGB; break; - case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->bindToTextureRGBA; break; - case EGL_MIN_SWAP_INTERVAL: *value = configuration->minSwapInterval; break; - case EGL_MAX_SWAP_INTERVAL: *value = configuration->maxSwapInterval; break; - case EGL_LUMINANCE_SIZE: *value = configuration->luminanceSize; break; - case EGL_ALPHA_MASK_SIZE: *value = configuration->alphaMaskSize; break; - case EGL_COLOR_BUFFER_TYPE: *value = configuration->colorBufferType; break; - case EGL_RENDERABLE_TYPE: *value = configuration->renderableType; break; - case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; - case EGL_CONFORMANT: *value = configuration->conformant; break; - 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; - } - - return true; -} - -Error Display::createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, +Error Display::createWindowSurface(const Config *configuration, + EGLNativeWindowType window, + const AttributeMap &attribs, Surface **outSurface) { if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(restoreLostDevice()); } - rx::SurfaceImpl *surfaceImpl = mImplementation->createWindowSurface(configuration, window, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; - } + SurfacePointer surface(new WindowSurface(mImplementation, configuration, window, attribs), + this); + ANGLE_TRY(surface->initialize(this)); - Surface *surface = new Surface(surfaceImpl, EGL_WINDOW_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + ASSERT(outSurface != nullptr); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end()); - windowSurfaces->insert(std::make_pair(window, surface)); + windowSurfaces->insert(std::make_pair(window, *outSurface)); - ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + return NoError(); } -Error Display::createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface) +Error Display::createPbufferSurface(const Config *configuration, + const AttributeMap &attribs, + Surface **outSurface) { ASSERT(isInitialized()); if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - rx::SurfaceImpl *surfaceImpl = mImplementation->createPbufferSurface(configuration, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; + ANGLE_TRY(restoreLostDevice()); } - Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface(new PbufferSurface(mImplementation, configuration, attribs), this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, - const AttributeMap &attribs, Surface **outSurface) +Error Display::createPbufferFromClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs, + Surface **outSurface) { ASSERT(isInitialized()); if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - rx::SurfaceImpl *surfaceImpl = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; + ANGLE_TRY(restoreLostDevice()); } - Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface( + new PbufferSurface(mImplementation, configuration, buftype, clientBuffer, attribs), this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, +Error Display::createPixmapSurface(const Config *configuration, + NativePixmapType nativePixmap, + const AttributeMap &attribs, Surface **outSurface) { ASSERT(isInitialized()); if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(restoreLostDevice()); } - rx::SurfaceImpl *surfaceImpl = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs); - ASSERT(surfaceImpl != nullptr); - - Error error = surfaceImpl->initialize(); - if (error.isError()) - { - SafeDelete(surfaceImpl); - return error; - } - - Surface *surface = new Surface(surfaceImpl, EGL_PIXMAP_BIT, configuration, attribs); - mImplementation->getSurfaceSet().insert(surface); + SurfacePointer surface(new PixmapSurface(mImplementation, configuration, nativePixmap, attribs), + this); + ANGLE_TRY(surface->initialize(this)); ASSERT(outSurface != nullptr); - *outSurface = surface; - return Error(EGL_SUCCESS); + *outSurface = surface.release(); + mState.surfaceSet.insert(*outSurface); + + return NoError(); } -Error Display::createImage(gl::Context *context, +Error Display::createImage(const gl::Context *context, EGLenum target, EGLClientBuffer buffer, const AttributeMap &attribs, @@ -656,11 +671,7 @@ Error Display::createImage(gl::Context *context, if (mImplementation->testDeviceLost()) { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(restoreLostDevice()); } egl::ImageSibling *sibling = nullptr; @@ -678,16 +689,11 @@ Error Display::createImage(gl::Context *context, } ASSERT(sibling != nullptr); - rx::ImageImpl *imageImpl = mImplementation->createImage(target, sibling, attribs); - ASSERT(imageImpl != nullptr); + angle::UniqueObjectPointer imagePtr( + new Image(mImplementation, target, sibling, attribs), context); + ANGLE_TRY(imagePtr->initialize()); - Error error = imageImpl->initialize(); - if (error.isError()) - { - return error; - } - - Image *image = new Image(imageImpl, target, sibling, attribs); + Image *image = imagePtr.release(); ASSERT(outImage != nullptr); *outImage = image; @@ -696,49 +702,92 @@ Error Display::createImage(gl::Context *context, image->addRef(); mImageSet.insert(image); - return Error(EGL_SUCCESS); + return NoError(); +} + +Error Display::createStream(const AttributeMap &attribs, Stream **outStream) +{ + ASSERT(isInitialized()); + + Stream *stream = new Stream(this, attribs); + + ASSERT(stream != nullptr); + mStreamSet.insert(stream); + + ASSERT(outStream != nullptr); + *outStream = stream; + + return NoError(); } -Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, +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()) + ANGLE_TRY(restoreLostDevice()); + } + + // This display texture sharing will allow the first context to create the texture share group. + bool usingDisplayTextureShareGroup = + attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE; + gl::TextureManager *shareTextures = nullptr; + + if (usingDisplayTextureShareGroup) + { + ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0)); + if (mTextureManager == nullptr) { - return error; + mTextureManager = new gl::TextureManager(); } + + mGlobalTextureShareGroupUsers++; + shareTextures = mTextureManager; } - gl::Context *context = *outContext = - mImplementation->createContext(configuration, shareContext, attribs); + gl::MemoryProgramCache *cachePointer = &mMemoryProgramCache; + + // Check context creation attributes to see if we should enable the cache. + if (mAttributeMap.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, EGL_TRUE) == EGL_FALSE) + { + cachePointer = nullptr; + } + + // A program cache size of zero indicates it should be disabled. + if (mMemoryProgramCache.maxSize() == 0) + { + cachePointer = nullptr; + } + + gl::Context *context = + new gl::Context(mImplementation, configuration, shareContext, shareTextures, cachePointer, + attribs, mDisplayExtensions); ASSERT(context != nullptr); mContextSet.insert(context); ASSERT(outContext != nullptr); *outContext = context; - return Error(EGL_SUCCESS); + return NoError(); } -Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +Error Display::makeCurrent(egl::Surface *drawSurface, + egl::Surface *readSurface, + gl::Context *context) { - Error error = mImplementation->makeCurrent(drawSurface, readSurface, context); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImplementation->makeCurrent(drawSurface, readSurface, context)); - if (context != nullptr && drawSurface != nullptr) + if (context != nullptr) { ASSERT(readSurface == drawSurface); - context->makeCurrent(drawSurface); + ANGLE_TRY(context->makeCurrent(this, drawSurface)); } - return egl::Error(EGL_SUCCESS); + return NoError(); } Error Display::restoreLostDevice() @@ -748,14 +797,14 @@ Error Display::restoreLostDevice() if ((*ctx)->isResetNotificationEnabled()) { // If reset notifications have been requested, application must delete all contexts first - return Error(EGL_CONTEXT_LOST); + return EglContextLost(); } } - return mImplementation->restoreLostDevice(); + return mImplementation->restoreLostDevice(this); } -void Display::destroySurface(Surface *surface) +Error Display::destroySurface(Surface *surface) { if (surface->getType() == EGL_WINDOW_BIT) { @@ -774,54 +823,89 @@ void Display::destroySurface(Surface *surface) } ASSERT(surfaceRemoved); - UNUSED_ASSERTION_VARIABLE(surfaceRemoved); } - mImplementation->destroySurface(surface); + mState.surfaceSet.erase(surface); + ANGLE_TRY(surface->onDestroy(this)); + return NoError(); } void Display::destroyImage(egl::Image *image) { auto iter = mImageSet.find(image); ASSERT(iter != mImageSet.end()); - (*iter)->release(); + (*iter)->release(mProxyContext.get()); mImageSet.erase(iter); } -void Display::destroyContext(gl::Context *context) +void Display::destroyStream(egl::Stream *stream) { + mStreamSet.erase(stream); + SafeDelete(stream); +} + +Error Display::destroyContext(gl::Context *context) +{ + if (context->usingDisplayTextureShareGroup()) + { + ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr); + if (mGlobalTextureShareGroupUsers == 1) + { + // If this is the last context using the global share group, destroy the global texture + // manager so that the textures can be destroyed while a context still exists + mTextureManager->release(context); + mTextureManager = nullptr; + } + mGlobalTextureShareGroupUsers--; + } + + ANGLE_TRY(context->onDestroy(this)); mContextSet.erase(context); SafeDelete(context); + return NoError(); } bool Display::isDeviceLost() const { ASSERT(isInitialized()); - return mImplementation->isDeviceLost(); + return mDeviceLost; } bool Display::testDeviceLost() { ASSERT(isInitialized()); - return mImplementation->testDeviceLost(); + + if (!mDeviceLost && mImplementation->testDeviceLost()) + { + notifyDeviceLost(); + } + + return mDeviceLost; } void Display::notifyDeviceLost() { + if (mDeviceLost) + { + return; + } + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) { (*context)->markContextLost(); } + + mDeviceLost = true; } -Error Display::waitClient() const +Error Display::waitClient(const gl::Context *context) const { - return mImplementation->waitClient(); + return mImplementation->waitClient(context); } -Error Display::waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const +Error Display::waitNative(const gl::Context *context, EGLint engine) const { - return mImplementation->waitNative(engine, drawSurface, readSurface); + return mImplementation->waitNative(context, engine); } const Caps &Display::getCaps() const @@ -839,14 +923,14 @@ bool Display::isValidConfig(const Config *config) const return mConfigSet.contains(config); } -bool Display::isValidContext(gl::Context *context) const +bool Display::isValidContext(const gl::Context *context) const { - return mContextSet.find(context) != mContextSet.end(); + return mContextSet.find(const_cast(context)) != mContextSet.end(); } -bool Display::isValidSurface(Surface *surface) const +bool Display::isValidSurface(const Surface *surface) const { - return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end(); + return mState.surfaceSet.find(const_cast(surface)) != mState.surfaceSet.end(); } bool Display::isValidImage(const Image *image) const @@ -854,6 +938,11 @@ bool Display::isValidImage(const Image *image) const return mImageSet.find(const_cast(image)) != mImageSet.end(); } +bool Display::isValidStream(const Stream *stream) const +{ + return mStreamSet.find(const_cast(stream)) != mStreamSet.end(); +} + bool Display::hasExistingWindowSurface(EGLNativeWindowType window) { WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); @@ -879,12 +968,20 @@ static ClientExtensions GenerateClientExtensions() extensions.platformANGLEOpenGL = true; #endif +#if defined(ANGLE_ENABLE_NULL) + extensions.platformANGLENULL = true; +#endif + #if defined(ANGLE_ENABLE_D3D11) extensions.deviceCreation = true; extensions.deviceCreationD3D11 = true; extensions.experimentalPresentPath = true; #endif +#if defined(ANGLE_ENABLE_VULKAN) + extensions.platformANGLEVulkan = true; +#endif + #if defined(ANGLE_USE_X11) extensions.x11Visual = true; #endif @@ -904,15 +1001,18 @@ static std::string GenerateExtensionsString(const T &extensions) return stream.str(); } -const ClientExtensions &Display::getClientExtensions() +// static +const ClientExtensions &Display::GetClientExtensions() { static const ClientExtensions clientExtensions = GenerateClientExtensions(); return clientExtensions; } -const std::string &Display::getClientExtensionString() +// static +const std::string &Display::GetClientExtensionString() { - static const std::string clientExtensionsString = GenerateExtensionsString(getClientExtensions()); + static const std::string clientExtensionsString = + GenerateExtensionsString(GetClientExtensions()); return clientExtensionsString; } @@ -920,9 +1020,20 @@ void Display::initDisplayExtensions() { mDisplayExtensions = mImplementation->getExtensions(); + // Some extensions are always available because they are implemented in the EGL layer. + mDisplayExtensions.createContext = true; + mDisplayExtensions.createContextNoError = true; + mDisplayExtensions.createContextWebGLCompatibility = true; + mDisplayExtensions.createContextBindGeneratesResource = true; + mDisplayExtensions.createContextClientArrays = true; + mDisplayExtensions.pixelFormatFloat = true; + // Force EGL_KHR_get_all_proc_addresses on. mDisplayExtensions.getAllProcAddresses = true; + // Enable program cache control since it is not back-end dependent. + mDisplayExtensions.programCacheControl = true; + mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions); } @@ -931,6 +1042,14 @@ bool Display::isValidNativeWindow(EGLNativeWindowType window) const return mImplementation->isValidNativeWindow(window); } +Error Display::validateClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs) +{ + return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs); +} + bool Display::isValidDisplay(const egl::Display *display) { const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap(); @@ -969,7 +1088,7 @@ bool Display::isValidNativeDisplay(EGLNativeDisplayType display) { return true; } - return (WindowFromDC(display) != NULL); + return (WindowFromDC(display) != nullptr); #else return true; #endif @@ -1000,4 +1119,105 @@ Device *Display::getDevice() const return mDevice; } +gl::Version Display::getMaxSupportedESVersion() const +{ + return mImplementation->getMaxSupportedESVersion(); } + +EGLint Display::programCacheGetAttrib(EGLenum attrib) const +{ + switch (attrib) + { + case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE: + return static_cast(gl::kProgramHashLength); + + case EGL_PROGRAM_CACHE_SIZE_ANGLE: + return static_cast(mMemoryProgramCache.entryCount()); + + default: + UNREACHABLE(); + return 0; + } +} + +Error Display::programCacheQuery(EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + ASSERT(index >= 0 && index < static_cast(mMemoryProgramCache.entryCount())); + + const angle::MemoryBuffer *programBinary = nullptr; + gl::ProgramHash programHash; + // TODO(jmadill): Make this thread-safe. + bool result = + mMemoryProgramCache.getAt(static_cast(index), &programHash, &programBinary); + if (!result) + { + return EglBadAccess() << "Program binary not accessible."; + } + + ASSERT(keysize && binarysize); + + if (key) + { + ASSERT(*keysize == static_cast(gl::kProgramHashLength)); + memcpy(key, programHash.data(), gl::kProgramHashLength); + } + + if (binary) + { + // Note: we check the size here instead of in the validation code, since we need to + // access the cache as atomically as possible. It's possible that the cache contents + // could change between the validation size check and the retrieval. + if (programBinary->size() > static_cast(*binarysize)) + { + return EglBadAccess() << "Program binary too large or changed during access."; + } + + memcpy(binary, programBinary->data(), programBinary->size()); + } + + *binarysize = static_cast(programBinary->size()); + *keysize = static_cast(gl::kProgramHashLength); + + return NoError(); +} + +Error Display::programCachePopulate(const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + ASSERT(keysize == static_cast(gl::kProgramHashLength)); + + gl::ProgramHash programHash; + memcpy(programHash.data(), key, gl::kProgramHashLength); + + mMemoryProgramCache.putBinary(programHash, reinterpret_cast(binary), + static_cast(binarysize)); + return NoError(); +} + +EGLint Display::programCacheResize(EGLint limit, EGLenum mode) +{ + switch (mode) + { + case EGL_PROGRAM_CACHE_RESIZE_ANGLE: + { + size_t initialSize = mMemoryProgramCache.size(); + mMemoryProgramCache.resize(static_cast(limit)); + return static_cast(initialSize); + } + + case EGL_PROGRAM_CACHE_TRIM_ANGLE: + return static_cast(mMemoryProgramCache.trim(static_cast(limit))); + + default: + UNREACHABLE(); + return 0; + } +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h index f80e308347..aa1d1c3b37 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.h +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -14,15 +14,18 @@ #include #include -#include "libANGLE/Error.h" +#include "libANGLE/AttributeMap.h" #include "libANGLE/Caps.h" #include "libANGLE/Config.h" -#include "libANGLE/AttributeMap.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/Error.h" +#include "libANGLE/LoggingAnnotator.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/Version.h" namespace gl { class Context; +class TextureManager; } namespace rx @@ -35,6 +38,21 @@ namespace egl class Device; class Image; class Surface; +class Stream; +class Thread; + +using SurfaceSet = std::set; + +struct DisplayState final : private angle::NonCopyable +{ + DisplayState(); + ~DisplayState(); + + SurfaceSet surfaceSet; +}; + +// Constant coded here as a sanity limit. +constexpr EGLAttrib kProgramCacheSizeAbsoluteMax = 0x4000000; class Display final : angle::NonCopyable { @@ -42,48 +60,68 @@ class Display final : angle::NonCopyable ~Display(); Error initialize(); - void terminate(); + Error terminate(); - static egl::Display *GetDisplayFromDevice(void *native_display); - static egl::Display *GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap); + static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); + static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap); - static const ClientExtensions &getClientExtensions(); - static const std::string &getClientExtensionString(); + static const ClientExtensions &GetClientExtensions(); + static const std::string &GetClientExtensionString(); - std::vector getConfigs(const egl::AttributeMap &attribs) const; - bool getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value); + std::vector getConfigs(const AttributeMap &attribs) const; - Error createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + Error createWindowSurface(const Config *configuration, + EGLNativeWindowType window, + const AttributeMap &attribs, Surface **outSurface); - Error createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface); - Error createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, const AttributeMap &attribs, + Error createPbufferSurface(const Config *configuration, + const AttributeMap &attribs, + Surface **outSurface); + Error createPbufferFromClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs, Surface **outSurface); - Error createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Error createPixmapSurface(const Config *configuration, + NativePixmapType nativePixmap, + const AttributeMap &attribs, Surface **outSurface); - Error createImage(gl::Context *context, + Error createImage(const gl::Context *context, EGLenum target, EGLClientBuffer buffer, const AttributeMap &attribs, Image **outImage); - Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + Error createStream(const AttributeMap &attribs, Stream **outStream); + + 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); + Error makeCurrent(Surface *drawSurface, Surface *readSurface, gl::Context *context); - void destroySurface(egl::Surface *surface); - void destroyImage(egl::Image *image); - void destroyContext(gl::Context *context); + Error destroySurface(Surface *surface); + void destroyImage(Image *image); + void destroyStream(Stream *stream); + Error 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 isValidContext(const gl::Context *context) const; + bool isValidSurface(const Surface *surface) const; bool isValidImage(const Image *image) const; + bool isValidStream(const Stream *stream) const; bool isValidNativeWindow(EGLNativeWindowType window) const; - static bool isValidDisplay(const egl::Display *display); + Error validateClientBuffer(const Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs); + + static bool isValidDisplay(const Display *display); static bool isValidNativeDisplay(EGLNativeDisplayType display); static bool hasExistingWindowSurface(EGLNativeWindowType window); @@ -91,8 +129,8 @@ class Display final : angle::NonCopyable bool testDeviceLost(); void notifyDeviceLost(); - Error waitClient() const; - Error waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const; + Error waitClient(const gl::Context *context) const; + Error waitNative(const gl::Context *context, EGLint engine) const; const Caps &getCaps() const; @@ -100,13 +138,31 @@ class Display final : angle::NonCopyable const std::string &getExtensionString() const; const std::string &getVendorString() const; + EGLint programCacheGetAttrib(EGLenum attrib) const; + Error programCacheQuery(EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize); + Error programCachePopulate(const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize); + EGLint programCacheResize(EGLint limit, EGLenum mode); + const AttributeMap &getAttributeMap() const { return mAttributeMap; } EGLNativeDisplayType getNativeDisplayId() const { return mDisplayId; } - rx::DisplayImpl *getImplementation() { return mImplementation; } + rx::DisplayImpl *getImplementation() const { return mImplementation; } Device *getDevice() const; EGLenum getPlatform() const { return mPlatform; } + gl::Version getMaxSupportedESVersion() const; + + const DisplayState &getState() const { return mState; } + + gl::Context *getProxyContext() const { return mProxyContext.get(); } + private: Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice); @@ -117,6 +173,7 @@ class Display final : angle::NonCopyable void initDisplayExtensions(); void initVendorString(); + DisplayState mState; rx::DisplayImpl *mImplementation; EGLNativeDisplayType mDisplayId; @@ -130,7 +187,11 @@ class Display final : angle::NonCopyable typedef std::set ImageSet; ImageSet mImageSet; + typedef std::set StreamSet; + StreamSet mStreamSet; + bool mInitialized; + bool mDeviceLost; Caps mCaps; @@ -141,8 +202,17 @@ class Display final : angle::NonCopyable Device *mDevice; EGLenum mPlatform; + angle::LoggingAnnotator mAnnotator; + + gl::TextureManager *mTextureManager; + gl::MemoryProgramCache mMemoryProgramCache; + size_t mGlobalTextureShareGroupUsers; + + // This gl::Context is a simple proxy to the Display for the GL back-end entry points + // that need access to implementation-specific data, like a Renderer object. + angle::UniqueObjectPointer mProxyContext; }; -} +} // namespace egl #endif // LIBANGLE_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.cpp b/src/3rdparty/angle/src/libANGLE/Error.cpp index fed1594972..388f0259fa 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.cpp +++ b/src/3rdparty/angle/src/libANGLE/Error.cpp @@ -10,35 +10,38 @@ #include "libANGLE/Error.h" #include "common/angleutils.h" +#include "common/debug.h" +#include "common/utilities.h" #include +namespace +{ +std::unique_ptr EmplaceErrorString(std::string &&message) +{ + return message.empty() ? std::unique_ptr() + : std::unique_ptr(new std::string(std::move(message))); +} +} // anonymous namespace + namespace gl { -Error::Error(GLenum errorCode, const char *msg, ...) : mCode(errorCode), mID(errorCode) +Error::Error(GLenum errorCode, std::string &&message) + : mCode(errorCode), mID(errorCode), mMessage(EmplaceErrorString(std::move(message))) { - 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) +Error::Error(GLenum errorCode, GLuint id, std::string &&message) + : mCode(errorCode), mID(id), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } void Error::createMessageString() const { if (!mMessage) { - mMessage.reset(new std::string); + mMessage.reset(new std::string(GetGenericErrorMessage(mCode))); } } @@ -64,34 +67,32 @@ bool Error::operator!=(const Error &other) const { return !(*this == other); } + +std::ostream &operator<<(std::ostream &os, const Error &err) +{ + return gl::FmtHexShort(os, err.getCode()); } +} // namespace gl + namespace egl { -Error::Error(EGLint errorCode, const char *msg, ...) : mCode(errorCode), mID(0) +Error::Error(EGLint errorCode, std::string &&message) + : mCode(errorCode), mID(errorCode), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } -Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) : mCode(errorCode), mID(id) +Error::Error(EGLint errorCode, EGLint id, std::string &&message) + : mCode(errorCode), mID(id), mMessage(EmplaceErrorString(std::move(message))) { - va_list vararg; - va_start(vararg, msg); - createMessageString(); - *mMessage = FormatString(msg, vararg); - va_end(vararg); } void Error::createMessageString() const { if (!mMessage) { - mMessage.reset(new std::string); + mMessage.reset(new std::string(GetGenericErrorMessage(mCode))); } } @@ -101,4 +102,9 @@ const std::string &Error::getMessage() const return *mMessage; } +std::ostream &operator<<(std::ostream &os, const Error &err) +{ + return gl::FmtHexShort(os, err.getCode()); } + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h index a5f760956a..1d57bb8707 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.h +++ b/src/3rdparty/angle/src/libANGLE/Error.h @@ -9,23 +9,89 @@ #ifndef LIBANGLE_ERROR_H_ #define LIBANGLE_ERROR_H_ -#include "angle_gl.h" #include +#include +#include "angle_gl.h" +#include "common/angleutils.h" +#include "common/debug.h" -#include #include +#include +#include + +namespace angle +{ +template +class ANGLE_NO_DISCARD ErrorOrResultBase +{ + public: + ErrorOrResultBase(const ErrorT &error) : mError(error) {} + ErrorOrResultBase(ErrorT &&error) : mError(std::move(error)) {} + + ErrorOrResultBase(ResultT &&result) : mError(NoErrorVal), mResult(std::forward(result)) + { + } + + ErrorOrResultBase(const ResultT &result) : mError(NoErrorVal), mResult(result) {} + + bool isError() const { return mError.isError(); } + const ErrorT &getError() const { return mError; } + ResultT &&getResult() { return std::move(mResult); } + + private: + ErrorT mError; + ResultT mResult; +}; + +template +class ErrorStreamBase : angle::NonCopyable +{ + public: + ErrorStreamBase() : mID(EnumT) {} + ErrorStreamBase(GLuint id) : mID(id) {} + + template + ErrorStreamBase &operator<<(T value) + { + mErrorStream << value; + return *this; + } + + operator ErrorT() { return ErrorT(EnumT, mID, mErrorStream.str()); } + + template + operator ErrorOrResultBase() + { + return static_cast(*this); + } + + private: + GLuint mID; + std::ostringstream mErrorStream; +}; +} // namespace angle + +namespace egl +{ +class Error; +} // namespace egl namespace gl { -class Error final +class ANGLE_NO_DISCARD Error final { public: explicit inline Error(GLenum errorCode); - Error(GLenum errorCode, const char *msg, ...); - Error(GLenum errorCode, GLuint id, const char *msg, ...); + Error(GLenum errorCode, std::string &&message); + Error(GLenum errorCode, GLuint id, std::string &&message); inline Error(const Error &other); inline Error(Error &&other); + inline ~Error() = default; + + // automatic error type conversion + inline Error(egl::Error &&eglErr); + inline Error(egl::Error eglErr); inline Error &operator=(const Error &other); inline Error &operator=(Error &&other); @@ -43,40 +109,60 @@ class Error final private: void createMessageString() const; + friend std::ostream &operator<<(std::ostream &os, const Error &err); + friend class egl::Error; + GLenum mCode; GLuint mID; mutable std::unique_ptr mMessage; }; -template -class ErrorOrResult +template +using ErrorOrResult = angle::ErrorOrResultBase; + +namespace priv { - 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); } +template +using ErrorStream = angle::ErrorStreamBase; - private: - Error mError; - T mResult; -}; +} // namespace priv + +using InternalError = priv::ErrorStream; + +using InvalidEnum = priv::ErrorStream; +using InvalidValue = priv::ErrorStream; +using InvalidOperation = priv::ErrorStream; +using StackOverflow = priv::ErrorStream; +using StackUnderflow = priv::ErrorStream; +using OutOfMemory = priv::ErrorStream; +using InvalidFramebufferOperation = priv::ErrorStream; + +inline Error NoError() +{ + return Error(GL_NO_ERROR); +} + +using LinkResult = ErrorOrResult; } // namespace gl namespace egl { -class Error final +class ANGLE_NO_DISCARD Error final { public: explicit inline Error(EGLint errorCode); - Error(EGLint errorCode, const char *msg, ...); - Error(EGLint errorCode, EGLint id, const char *msg, ...); + Error(EGLint errorCode, std::string &&message); + Error(EGLint errorCode, EGLint id, std::string &&message); inline Error(const Error &other); inline Error(Error &&other); + inline ~Error() = default; + + // automatic error type conversion + inline Error(gl::Error &&glErr); + inline Error(gl::Error glErr); inline Error &operator=(const Error &other); inline Error &operator=(Error &&other); @@ -90,13 +176,92 @@ class Error final private: void createMessageString() const; + friend std::ostream &operator<<(std::ostream &os, const Error &err); + friend class gl::Error; + EGLint mCode; EGLint mID; mutable std::unique_ptr mMessage; }; +template +using ErrorOrResult = angle::ErrorOrResultBase; + +namespace priv +{ + +template +using ErrorStream = angle::ErrorStreamBase; + +} // namespace priv + +using EglNotInitialized = priv::ErrorStream; +using EglBadAccess = priv::ErrorStream; +using EglBadAlloc = priv::ErrorStream; +using EglBadAttribute = priv::ErrorStream; +using EglBadConfig = priv::ErrorStream; +using EglBadContext = priv::ErrorStream; +using EglBadCurrentSurface = priv::ErrorStream; +using EglBadDisplay = priv::ErrorStream; +using EglBadMatch = priv::ErrorStream; +using EglBadNativeWindow = priv::ErrorStream; +using EglBadParameter = priv::ErrorStream; +using EglBadSurface = priv::ErrorStream; +using EglContextLost = priv::ErrorStream; +using EglBadStream = priv::ErrorStream; +using EglBadState = priv::ErrorStream; +using EglBadDevice = priv::ErrorStream; + +inline Error NoError() +{ + return Error(EGL_SUCCESS); +} + } // namespace egl +#define ANGLE_CONCAT1(x, y) x##y +#define ANGLE_CONCAT2(x, y) ANGLE_CONCAT1(x, y) +#define ANGLE_LOCAL_VAR ANGLE_CONCAT2(_localVar, __LINE__) + +#define ANGLE_TRY_TEMPLATE(EXPR, FUNC) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + FUNC(ANGLE_LOCAL_VAR); \ + } \ + } \ + ANGLE_EMPTY_STATEMENT + +#define ANGLE_RETURN(X) return X; +#define ANGLE_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_RETURN); + +#define ANGLE_TRY_RESULT(EXPR, RESULT) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + return ANGLE_LOCAL_VAR.getError(); \ + } \ + RESULT = ANGLE_LOCAL_VAR.getResult(); \ + } \ + ANGLE_EMPTY_STATEMENT + +// TODO(jmadill): Introduce way to store errors to a const Context. +#define ANGLE_SWALLOW_ERR(EXPR) \ + { \ + auto ANGLE_LOCAL_VAR = EXPR; \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + ERR() << "Unhandled internal error: " << ANGLE_LOCAL_VAR; \ + } \ + } \ + ANGLE_EMPTY_STATEMENT + +#undef ANGLE_LOCAL_VAR +#undef ANGLE_CONCAT2 +#undef ANGLE_CONCAT1 + #include "Error.inl" #endif // LIBANGLE_ERROR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.inl b/src/3rdparty/angle/src/libANGLE/Error.inl index 900fc5fd03..4632830ce0 100644 --- a/src/3rdparty/angle/src/libANGLE/Error.inl +++ b/src/3rdparty/angle/src/libANGLE/Error.inl @@ -37,6 +37,21 @@ Error::Error(Error &&other) { } +// automatic error type conversion +Error::Error(egl::Error &&eglErr) + : mCode(GL_INVALID_OPERATION), + mID(0), + mMessage(std::move(eglErr.mMessage)) +{ +} + +Error::Error(egl::Error eglErr) + : mCode(GL_INVALID_OPERATION), + mID(0), + mMessage(std::move(eglErr.mMessage)) +{ +} + Error &Error::operator=(const Error &other) { mCode = other.mCode; @@ -82,7 +97,7 @@ bool Error::isError() const return (mCode != GL_NO_ERROR); } -} +} // namespace gl namespace egl { @@ -111,6 +126,21 @@ Error::Error(Error &&other) { } +// automatic error type conversion +Error::Error(gl::Error &&glErr) + : mCode(EGL_BAD_ACCESS), + mID(0), + mMessage(std::move(glErr.mMessage)) +{ +} + +Error::Error(gl::Error glErr) + : mCode(EGL_BAD_ACCESS), + mID(0), + mMessage(std::move(glErr.mMessage)) +{ +} + Error &Error::operator=(const Error &other) { mCode = other.mCode; diff --git a/src/3rdparty/angle/src/libANGLE/ErrorStrings.h b/src/3rdparty/angle/src/libANGLE/ErrorStrings.h new file mode 100644 index 0000000000..93d64482d9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ErrorStrings.h @@ -0,0 +1,173 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ErrorStrings.h: Contains mapping of commonly used error messages + +#ifndef LIBANGLE_ERRORSTRINGS_H_ +#define LIBANGLE_ERRORSTRINGS_H_ + +#define ERRMSG(name, message) \ + static const constexpr char *kError##name = static_cast(message); +#define ANGLE_VALIDATION_ERR(context, error, errorName) \ + context->handleError(error << kError##errorName) + +namespace gl +{ +ERRMSG(BufferNotBound, "A buffer must be bound."); +ERRMSG(CompressedTextureDimensionsMustMatchData, + "Compressed texture dimensions must exactly match the dimensions of the data passed in."); +ERRMSG(CompressedTexturesNotAttachable, "Compressed textures cannot be attached to a framebuffer."); +ERRMSG(CubemapFacesEqualDimensions, "Each cubemap face must have equal width and height."); +ERRMSG(CubemapIncomplete, + "Texture is not cubemap complete. All cubemaps faces must be defined and be the same size."); +ERRMSG(DefaultFramebufferInvalidAttachment, + "Invalid attachment when the default framebuffer is bound."); +ERRMSG(DefaultFramebufferTarget, "It is invalid to change default FBO's attachments"); +ERRMSG(EnumNotSupported, "Enum is not currently supported."); +ERRMSG(EnumRequiresGLES31, "Enum requires GLES 3.1"); +ERRMSG(ES31Required, "OpenGL ES 3.1 Required"); +ERRMSG(ES3Required, "OpenGL ES 3.0 Required."); +ERRMSG(ExceedsMaxElement, "Element value exceeds maximum element index."); +ERRMSG(ExpectedProgramName, "Expected a program name, but found a shader name."); +ERRMSG(ExpectedShaderName, "Expected a shader name, but found a program name."); +ERRMSG(ExtensionNotEnabled, "Extension is not enabled."); +ERRMSG(FeedbackLoop, "Feedback loop formed between Framebuffer and active Texture."); +ERRMSG(FramebufferIncompleteAttachment, + "Attachment type must be compatible with attachment object."); +ERRMSG(GenerateMipmapNotAllowed, "Texture format does not support mipmap generation."); +ERRMSG(IndexExceedsMaxActiveUniform, "Index exceeds program active uniform count."); +ERRMSG(IndexExceedsMaxDrawBuffer, "Index exceeds MAX_DRAW_BUFFERS."); +ERRMSG(IndexExceedsMaxVertexAttribute, "Index exceeds MAX_VERTEX_ATTRIBS."); +ERRMSG(InsufficientBufferSize, "Insufficient buffer size."); +ERRMSG(InsufficientVertexBufferSize, "Vertex buffer is not big enough for the draw call"); +ERRMSG(IntegerOverflow, "Integer overflow."); +ERRMSG(InvalidAttachment, "Invalid Attachment Type."); +ERRMSG(InvalidBlendEquation, "Invalid blend equation."); +ERRMSG(InvalidBlendFunction, "Invalid blend function."); +ERRMSG(InvalidBorder, "Border must be 0."); +ERRMSG(InvalidBufferTypes, "Invalid buffer target enum."); +ERRMSG(InvalidBufferUsage, "Invalid buffer usage enum."); +ERRMSG(InvalidClearMask, "Invalid mask bits."); +ERRMSG(InvalidConstantColor, + "CONSTANT_COLOR (or ONE_MINUS_CONSTANT_COLOR) and CONSTANT_ALPHA (or " + "ONE_MINUS_CONSTANT_ALPHA) cannot be used together as source and destination factors in the " + "blend function."); +ERRMSG(InvalidCoverMode, "Invalid cover mode."); +ERRMSG(InvalidCullMode, "Cull mode not recognized."); +ERRMSG(InvalidDebugSeverity, "Invalid debug severity."); +ERRMSG(InvalidDebugSource, "Invalid debug source."); +ERRMSG(InvalidDebugType, "Invalid debug type."); +ERRMSG(InvalidDepthRange, "Near value cannot be greater than far."); +ERRMSG(InvalidDrawMode, "Invalid draw mode."); +ERRMSG(InvalidDrawModeTransformFeedback, + "Draw mode must match current transform feedback object's draw mode."); +ERRMSG(InvalidFillMode, "Invalid fill mode."); +ERRMSG(InvalidFilterTexture, "Texture only supports NEAREST and LINEAR filtering."); +ERRMSG(InvalidFormat, "Invalid format."); +ERRMSG(InvalidFramebufferTarget, "Invalid framebuffer target."); +ERRMSG(InvalidFramebufferTextureLevel, "Mipmap level must be 0 when attaching a texture."); +ERRMSG(InvalidFramebufferAttachmentParameter, "Invalid parameter name for framebuffer attachment."); +ERRMSG(InvalidInternalFormat, "Invalid internal format."); +ERRMSG(InvalidMatrixMode, "Invalid matrix mode."); +ERRMSG(InvalidMipLevel, "Level of detail outside of range."); +ERRMSG(InvalidName, "Invalid name."); +ERRMSG(InvalidNameCharacters, "Name contains invalid characters."); +ERRMSG(InvalidPname, "Invalid pname."); +ERRMSG(InvalidPrecision, "Invalid or unsupported precision type."); +ERRMSG(InvalidProgramName, "Program object expected."); +ERRMSG(InvalidQueryId, "Invalid query Id."); +ERRMSG(InvalidQueryTarget, "Invalid query target."); +ERRMSG(InvalidQueryType, "Invalid query type."); +ERRMSG(InvalidRange, "Invalid range."); +ERRMSG(InvalidRenderbufferInternalFormat, "Invalid renderbuffer internalformat."); +ERRMSG(InvalidRenderbufferTarget, "Invalid renderbuffer target."); +ERRMSG(InvalidRenderbufferTextureParameter, "Invalid parameter name for renderbuffer attachment."); +ERRMSG(InvalidRenderbufferWidthHeight, + "Renderbuffer width and height cannot be negative and cannot exceed maximum texture size."); +ERRMSG(InvalidSampleMaskNumber, + "MaskNumber cannot be greater than or equal to the value of MAX_SAMPLE_MASK_WORDS."); +ERRMSG(InvalidSampler, "Sampler is not valid"); +ERRMSG(InvalidShaderName, "Shader object expected."); +ERRMSG(InvalidShaderType, "Invalid shader type."); +ERRMSG(InvalidStencil, "Invalid stencil."); +ERRMSG(InvalidStencilBitMask, "Invalid stencil bit mask."); +ERRMSG(InvalidTarget, "Invalid target."); +ERRMSG(InvalidTextureFilterParam, "Texture filter not recognized."); +ERRMSG(InvalidTextureRange, "Cannot be less than 0 or greater than maximum number of textures."); +ERRMSG(InvalidTextureTarget, "Invalid or unsupported texture target."); +ERRMSG(InvalidTextureWrap, "Texture wrap mode not recognized."); +ERRMSG(InvalidType, "Invalid type."); +ERRMSG(InvalidTypePureInt, "Invalid type, should be integer"); +ERRMSG(InvalidUnpackAlignment, "Unpack alignment must be 1, 2, 4, or 8."); +ERRMSG(InvalidVertexAttrSize, "Vertex attribute size must be 1, 2, 3, or 4."); +ERRMSG(InvalidWidth, "Invalid width."); +ERRMSG(InvalidWrapModeTexture, "Invalid wrap mode for texture type."); +ERRMSG(LevelNotZero, "Texture level must be zero."); +ERRMSG(MismatchedByteCountType, "Buffer size does not align with data type."); +ERRMSG(MismatchedFormat, "Format must match internal format."); +ERRMSG(MismatchedTargetAndFormat, "Invalid texture target and format combination."); +ERRMSG(MismatchedTypeAndFormat, "Invalid format and type combination."); +ERRMSG(MismatchedVariableProgram, "Variable is not part of the current program."); +ERRMSG(MissingReadAttachment, "Missing read attachment."); +ERRMSG(MustHaveElementArrayBinding, "Must have element array buffer binding."); +ERRMSG(NameBeginsWithGL, "Attributes that begin with 'gl_' are not allowed."); +ERRMSG(NegativeAttachments, "Negative number of attachments."); +ERRMSG(NegativeBufferSize, "Negative buffer size."); +ERRMSG(NegativeCount, "Negative count."); +ERRMSG(NegativeLength, "Negative length."); +ERRMSG(NegativeMaxCount, "Negative maxcount."); +ERRMSG(NegativeOffset, "Negative offset."); +ERRMSG(NegativePrimcount, "Primcount must be greater than or equal to zero."); +ERRMSG(NegativeSize, "Cannot have negative height or width."); +ERRMSG(NegativeStart, "Cannot have negative start."); +ERRMSG(NegativeStride, "Cannot have negative stride."); +ERRMSG(NoSuchPath, "No such path object."); +ERRMSG(NoTransformFeedbackOutputVariables, + "The active program has specified no output variables to record."); +ERRMSG(NoZeroDivisor, "At least one enabled attribute must have a divisor of zero."); +ERRMSG(ObjectNotGenerated, "Object cannot be used because it has not been generated."); +ERRMSG(OffsetMustBeMultipleOfType, "Offset must be a multiple of the passed in datatype."); +ERRMSG(OutsideOfBounds, "Parameter outside of bounds."); +ERRMSG(ParamOverflow, "The provided parameters overflow with the provided buffer."); +ERRMSG(PixelDataNotNull, "Pixel data must be null."); +ERRMSG(PixelDataNull, "Pixel data cannot be null."); +ERRMSG(ProgramDoesNotExist, "Program doesn't exist."); +ERRMSG(ProgramNotBound, "A program must be bound."); +ERRMSG(ProgramNotLinked, "Program not linked."); +ERRMSG(QueryActive, "Query is active."); +ERRMSG(QueryExtensionNotEnabled, "Query extension not enabled."); +ERRMSG(ReadBufferNone, "Read buffer is GL_NONE."); +ERRMSG(RenderbufferNotBound, "A renderbuffer must be bound."); +ERRMSG(ResourceMaxTextureSize, "Desired resource size is greater than max texture size."); +ERRMSG(ShaderAttachmentHasShader, "Shader attachment already has a shader."); +ERRMSG(ShaderSourceInvalidCharacters, "Shader source contains invalid characters."); +ERRMSG(ShaderToDetachMustBeAttached, + "Shader to be detached must be currently attached to the program."); +ERRMSG(SourceTextureTooSmall, "The specified dimensions are outside of the bounds of the texture."); +ERRMSG(StencilReferenceMaskOrMismatch, + "Stencil reference and mask values must be the same for front facing and back facing " + "triangles."); +ERRMSG(StrideMustBeMultipleOfType, "Stride must be a multiple of the passed in datatype."); +ERRMSG(TextureNotBound, "A texture must be bound."); +ERRMSG(TextureNotPow2, "The texture is a non-power-of-two texture."); +ERRMSG(TransformFeedbackDoesNotExist, "Transform feedback object that does not exist."); +ERRMSG(TypeMismatch, + "Passed in texture target and format must match the one originally used to define the " + "texture."); +ERRMSG(TypeNotUnsignedShortByte, "Only UNSIGNED_SHORT and UNSIGNED_BYTE types are supported."); +ERRMSG(UniformSizeMismatch, "Uniform size does not match uniform method."); +ERRMSG(UnknownParameter, "Unknown parameter value."); +ERRMSG(VertexArrayNoBuffer, "An enabled vertex array has no buffer."); +ERRMSG(VertexArrayNoBufferPointer, "An enabled vertex array has no buffer and no pointer."); +ERRMSG(ViewportNegativeSize, "Viewport size cannot be negative."); +ERRMSG(Webgl2NameLengthLimitExceeded, "Location lengths must not be greater than 1024 characters."); +ERRMSG(WebglBindAttribLocationReservedPrefix, + "Attributes that begin with 'webgl_', or '_webgl_' are not allowed."); +ERRMSG(WebglNameLengthLimitExceeded, + "Location name lengths must not be greater than 256 characters."); +} +#undef ERRMSG +#endif // LIBANGLE_ERRORSTRINGS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Fence.cpp b/src/3rdparty/angle/src/libANGLE/Fence.cpp index ff32f4bbe9..9c4d381673 100644 --- a/src/3rdparty/angle/src/libANGLE/Fence.cpp +++ b/src/3rdparty/angle/src/libANGLE/Fence.cpp @@ -4,18 +4,17 @@ // found in the LICENSE file. // -// Fence.cpp: Implements the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// Fence.cpp: Implements the gl::FenceNV and gl::Sync classes, which support the GL_NV_fence // extension and GLES3 sync objects. #include "libANGLE/Fence.h" -#include "libANGLE/renderer/FenceNVImpl.h" -#include "libANGLE/renderer/FenceSyncImpl.h" -#include "libANGLE/renderer/Renderer.h" -#include "common/utilities.h" - #include "angle_gl.h" +#include "common/utilities.h" +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/SyncImpl.h" + namespace gl { @@ -44,7 +43,7 @@ Error FenceNV::set(GLenum condition) mStatus = GL_FALSE; mIsSet = true; - return Error(GL_NO_ERROR); + return NoError(); } Error FenceNV::test(GLboolean *outResult) @@ -57,7 +56,7 @@ Error FenceNV::test(GLboolean *outResult) } *outResult = mStatus; - return Error(GL_NO_ERROR); + return NoError(); } Error FenceNV::finish() @@ -72,30 +71,39 @@ Error FenceNV::finish() mStatus = GL_TRUE; - return Error(GL_NO_ERROR); + return NoError(); } -FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) - : RefCountObject(id), mFence(impl), mLabel(), mCondition(GL_NONE), mFlags(0) +Sync::Sync(rx::SyncImpl *impl, GLuint id) + : RefCountObject(id), + mFence(impl), + mLabel(), + mCondition(GL_SYNC_GPU_COMMANDS_COMPLETE), + mFlags(0) { } -FenceSync::~FenceSync() +Error Sync::onDestroy(const Context *context) +{ + return NoError(); +} + +Sync::~Sync() { SafeDelete(mFence); } -void FenceSync::setLabel(const std::string &label) +void Sync::setLabel(const std::string &label) { mLabel = label; } -const std::string &FenceSync::getLabel() const +const std::string &Sync::getLabel() const { return mLabel; } -Error FenceSync::set(GLenum condition, GLbitfield flags) +Error Sync::set(GLenum condition, GLbitfield flags) { Error error = mFence->set(condition, flags); if (error.isError()) @@ -105,23 +113,23 @@ Error FenceSync::set(GLenum condition, GLbitfield flags) mCondition = condition; mFlags = flags; - return Error(GL_NO_ERROR); + return NoError(); } -Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +Error Sync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) { ASSERT(mCondition != GL_NONE); return mFence->clientWait(flags, timeout, outResult); } -Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) +Error Sync::serverWait(GLbitfield flags, GLuint64 timeout) { return mFence->serverWait(flags, timeout); } -Error FenceSync::getStatus(GLint *outResult) const +Error Sync::getStatus(GLint *outResult) const { return mFence->getStatus(outResult); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Fence.h b/src/3rdparty/angle/src/libANGLE/Fence.h index b2daed6f0e..24bc689ca3 100644 --- a/src/3rdparty/angle/src/libANGLE/Fence.h +++ b/src/3rdparty/angle/src/libANGLE/Fence.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // -// Fence.h: Defines the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// Fence.h: Defines the gl::FenceNV and gl::Sync classes, which support the GL_NV_fence // extension and GLES3 sync objects. #ifndef LIBANGLE_FENCE_H_ @@ -19,7 +19,7 @@ namespace rx { class FenceNVImpl; -class FenceSyncImpl; +class SyncImpl; } namespace gl @@ -48,11 +48,13 @@ class FenceNV final : angle::NonCopyable GLenum mCondition; }; -class FenceSync final : public RefCountObject, public LabeledObject +class Sync final : public RefCountObject, public LabeledObject { public: - FenceSync(rx::FenceSyncImpl *impl, GLuint id); - virtual ~FenceSync(); + Sync(rx::SyncImpl *impl, GLuint id); + ~Sync() override; + + Error onDestroy(const Context *context) override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -66,7 +68,7 @@ class FenceSync final : public RefCountObject, public LabeledObject GLbitfield getFlags() const { return mFlags; } private: - rx::FenceSyncImpl *mFence; + rx::SyncImpl *mFence; std::string mLabel; @@ -74,6 +76,6 @@ class FenceSync final : public RefCountObject, public LabeledObject GLbitfield mFlags; }; -} +} // namespace gl #endif // LIBANGLE_FENCE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp index 3def57b87e..48e71685b3 100644 --- a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp @@ -10,72 +10,349 @@ #include "libANGLE/Framebuffer.h" #include "common/Optional.h" +#include "common/bitset_utils.h" #include "common/utilities.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" +#include "libANGLE/Display.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/FramebufferImpl.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/RenderbufferImpl.h" #include "libANGLE/renderer/SurfaceImpl.h" +using namespace angle; + namespace gl { namespace { -void DetachMatchingAttachment(FramebufferAttachment *attachment, GLenum matchType, GLuint matchId) + +void BindResourceChannel(OnAttachmentDirtyBinding *binding, FramebufferAttachmentObject *resource) +{ + binding->bind(resource ? resource->getDirtyChannel() : nullptr); +} + +bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firstAttachment, + const FramebufferAttachment *secondAttachment) +{ + ASSERT(firstAttachment && secondAttachment); + ASSERT(firstAttachment->isAttached() && secondAttachment->isAttached()); + + if (firstAttachment->getNumViews() != secondAttachment->getNumViews()) + { + return false; + } + if (firstAttachment->getBaseViewIndex() != secondAttachment->getBaseViewIndex()) + { + return false; + } + if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout()) + { + return false; + } + if (firstAttachment->getMultiviewViewportOffsets() != + secondAttachment->getMultiviewViewportOffsets()) + { + return false; + } + return true; +} + +bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttachment &attachment) +{ + ASSERT(attachment.isAttached()); + + const Extents &size = attachment.getSize(); + if (size.width == 0 || size.height == 0) + { + return false; + } + + const InternalFormat &format = *attachment.getFormat().info; + if (!format.renderSupport(context->getClientVersion(), context->getExtensions())) + { + return false; + } + + if (attachment.type() == GL_TEXTURE) + { + if (attachment.layer() >= size.depth) + { + return false; + } + + // 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 = attachment.getTexture(); + ASSERT(texture); + if (texture->getTarget() == GL_TEXTURE_CUBE_MAP && + !texture->getTextureState().isCubeComplete()) + { + return false; + } + + if (!texture->getImmutableFormat()) + { + GLuint attachmentMipLevel = static_cast(attachment.mipLevel()); + + // From the ES 3.0 spec, pg 213: + // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of + // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture, + // then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL must be in the + // range[levelbase, q], where levelbase is the value of TEXTURE_BASE_LEVEL and q is + // the effective maximum texture level defined in the Mipmapping discussion of + // section 3.8.10.4. + if (attachmentMipLevel < texture->getBaseLevel() || + attachmentMipLevel > texture->getMipmapMaxLevel()) + { + return false; + } + + // Form the ES 3.0 spec, pg 213/214: + // If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the value of + // FRAMEBUFFER_ATTACHMENT_OBJECT_NAME does not name an immutable-format texture and + // the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is not levelbase, then the + // texture must be mipmap complete, and if FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names + // a cubemap texture, the texture must also be cube complete. + if (attachmentMipLevel != texture->getBaseLevel() && !texture->isMipmapComplete()) + { + return false; + } + } + } + + return true; +}; + +bool CheckAttachmentSampleCompleteness(const Context *context, + const FramebufferAttachment &attachment, + bool colorAttachment, + Optional *samples, + Optional *fixedSampleLocations) +{ + ASSERT(attachment.isAttached()); + + if (attachment.type() == GL_TEXTURE) + { + const Texture *texture = attachment.getTexture(); + ASSERT(texture); + + const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex(); + + // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be + // the same for all attached textures. + bool fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type, + attachmentImageIndex.mipIndex); + if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value()) + { + return false; + } + else + { + *fixedSampleLocations = fixedSampleloc; + } + } + + if (samples->valid()) + { + if (attachment.getSamples() != samples->value()) + { + if (colorAttachment) + { + // 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. + return false; + } + else + { + // CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete + // when its depth or stencil samples are a multiple of the number of color samples. + if (!context->getExtensions().framebufferMixedSamples) + { + return false; + } + + if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0) + { + return false; + } + } + } + } + else + { + *samples = attachment.getSamples(); + } + + return true; +} + +// Needed to index into the attachment arrays/bitsets. +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) == + gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX, + "Framebuffer Dirty bit mismatch"); +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) == + gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT, + "Framebuffer Dirty bit mismatch"); +static_assert(static_cast(IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 1) == + gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT, + "Framebuffer Dirty bit mismatch"); + +Error InitAttachment(const Context *context, FramebufferAttachment *attachment) { - if (attachment->isAttached() && - attachment->type() == matchType && - attachment->id() == matchId) + ASSERT(attachment->isAttached()); + if (attachment->initState() == InitState::MayNeedInit) { - attachment->detach(); + ANGLE_TRY(attachment->initializeContents(context)); } + return NoError(); +} + +bool IsColorMaskedOut(const BlendState &blend) +{ + return (!blend.colorMaskRed && !blend.colorMaskGreen && !blend.colorMaskBlue && + !blend.colorMaskAlpha); +} + +bool IsDepthMaskedOut(const DepthStencilState &depthStencil) +{ + return !depthStencil.depthMask; +} + +bool IsStencilMaskedOut(const DepthStencilState &depthStencil) +{ + return ((depthStencil.stencilMask & depthStencil.stencilWritemask) == 0); } + +bool IsClearBufferMaskedOut(const Context *context, GLenum buffer) +{ + switch (buffer) + { + case GL_COLOR: + return IsColorMaskedOut(context->getGLState().getBlendState()); + case GL_DEPTH: + return IsDepthMaskedOut(context->getGLState().getDepthStencilState()); + case GL_STENCIL: + return IsStencilMaskedOut(context->getGLState().getDepthStencilState()); + case GL_DEPTH_STENCIL: + return IsDepthMaskedOut(context->getGLState().getDepthStencilState()) && + IsStencilMaskedOut(context->getGLState().getDepthStencilState()); + default: + UNREACHABLE(); + return true; + } } -Framebuffer::Data::Data() +} // anonymous namespace + +// This constructor is only used for default framebuffers. +FramebufferState::FramebufferState() : mLabel(), mColorAttachments(1), - mDrawBufferStates(1, GL_NONE), - mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) + mDrawBufferStates(1, GL_BACK), + mReadBufferState(GL_BACK), + mDefaultWidth(0), + mDefaultHeight(0), + mDefaultSamples(0), + mDefaultFixedSampleLocations(GL_FALSE), + mWebGLDepthStencilConsistent(true) { - mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; + ASSERT(mDrawBufferStates.size() > 0); + mEnabledDrawBuffers.set(0); } -Framebuffer::Data::Data(const Caps &caps) +FramebufferState::FramebufferState(const Caps &caps) : mLabel(), mColorAttachments(caps.maxColorAttachments), mDrawBufferStates(caps.maxDrawBuffers, GL_NONE), - mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) + mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), + mDefaultWidth(0), + mDefaultHeight(0), + mDefaultSamples(0), + mDefaultFixedSampleLocations(GL_FALSE), + mWebGLDepthStencilConsistent(true) { ASSERT(mDrawBufferStates.size() > 0); mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; } -Framebuffer::Data::~Data() +FramebufferState::~FramebufferState() { } -const std::string &Framebuffer::Data::getLabel() +const std::string &FramebufferState::getLabel() { return mLabel; } -const FramebufferAttachment *Framebuffer::Data::getReadAttachment() const +const FramebufferAttachment *FramebufferState::getAttachment(GLenum attachment) const +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) + { + return getColorAttachment(attachment - GL_COLOR_ATTACHMENT0); + } + + switch (attachment) + { + case GL_COLOR: + case GL_BACK: + return getColorAttachment(0); + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + return getDepthAttachment(); + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + return getStencilAttachment(); + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + return getDepthStencilAttachment(); + default: + UNREACHABLE(); + return nullptr; + } +} + +size_t FramebufferState::getReadIndex() 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(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 readIndex; +} + +const FramebufferAttachment *FramebufferState::getReadAttachment() const +{ + if (mReadBufferState == GL_NONE) + { + return nullptr; + } + size_t readIndex = getReadIndex(); return mColorAttachments[readIndex].isAttached() ? &mColorAttachments[readIndex] : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const +const FramebufferAttachment *FramebufferState::getFirstNonNullAttachment() const +{ + auto *colorAttachment = getFirstColorAttachment(); + if (colorAttachment) + { + return colorAttachment; + } + return getDepthOrStencilAttachment(); +} + +const FramebufferAttachment *FramebufferState::getFirstColorAttachment() const { for (const FramebufferAttachment &colorAttachment : mColorAttachments) { @@ -88,7 +365,7 @@ const FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const return nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const +const FramebufferAttachment *FramebufferState::getDepthOrStencilAttachment() const { if (mDepthAttachment.isAttached()) { @@ -101,31 +378,38 @@ const FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() co return nullptr; } -const FramebufferAttachment *Framebuffer::Data::getColorAttachment(size_t colorAttachment) const +const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const +{ + if (mStencilAttachment.isAttached()) + { + return &mStencilAttachment; + } + return getDepthStencilAttachment(); +} + +const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const { ASSERT(colorAttachment < mColorAttachments.size()); - return mColorAttachments[colorAttachment].isAttached() ? - &mColorAttachments[colorAttachment] : - nullptr; + return mColorAttachments[colorAttachment].isAttached() ? &mColorAttachments[colorAttachment] + : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthAttachment() const +const FramebufferAttachment *FramebufferState::getDepthAttachment() const { return mDepthAttachment.isAttached() ? &mDepthAttachment : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getStencilAttachment() const +const FramebufferAttachment *FramebufferState::getStencilAttachment() const { return mStencilAttachment.isAttached() ? &mStencilAttachment : nullptr; } -const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() const +const FramebufferAttachment *FramebufferState::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()) + mDepthAttachment == mStencilAttachment) { return &mDepthAttachment; } @@ -133,12 +417,11 @@ const FramebufferAttachment *Framebuffer::Data::getDepthStencilAttachment() cons return nullptr; } -bool Framebuffer::Data::attachmentsHaveSameDimensions() const +bool FramebufferState::attachmentsHaveSameDimensions() const { Optional attachmentSize; - auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) - { + auto hasMismatchedSize = [&attachmentSize](const FramebufferAttachment &attachment) { if (!attachment.isAttached()) { return false; @@ -150,7 +433,9 @@ bool Framebuffer::Data::attachmentsHaveSameDimensions() const return false; } - return (attachment.getSize() != attachmentSize.value()); + const auto &prevSize = attachmentSize.value(); + const auto &curSize = attachment.getSize(); + return (curSize.width != prevSize.width || curSize.height != prevSize.height); }; for (const auto &attachment : mColorAttachments) @@ -169,210 +454,414 @@ bool Framebuffer::Data::attachmentsHaveSameDimensions() const return !hasMismatchedSize(mStencilAttachment); } -Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id) - : mData(caps), mImpl(factory->createFramebuffer(mData)), mId(id) +const gl::FramebufferAttachment *FramebufferState::getDrawBuffer(size_t drawBufferIdx) const { - ASSERT(mId != 0); - ASSERT(mImpl != nullptr); + ASSERT(drawBufferIdx < mDrawBufferStates.size()); + if (mDrawBufferStates[drawBufferIdx] != 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(mDrawBufferStates[drawBufferIdx] == GL_COLOR_ATTACHMENT0 + drawBufferIdx || + (drawBufferIdx == 0 && mDrawBufferStates[drawBufferIdx] == GL_BACK)); + return getAttachment(mDrawBufferStates[drawBufferIdx]); + } + else + { + return nullptr; + } } -Framebuffer::Framebuffer(rx::SurfaceImpl *surface) - : mData(), mImpl(surface->createDefaultFramebuffer(mData)), mId(0) +size_t FramebufferState::getDrawBufferCount() const { - ASSERT(mImpl != nullptr); + return mDrawBufferStates.size(); } -Framebuffer::~Framebuffer() +bool FramebufferState::colorAttachmentsAreUniqueImages() const { - SafeDelete(mImpl); + for (size_t firstAttachmentIdx = 0; firstAttachmentIdx < mColorAttachments.size(); + firstAttachmentIdx++) + { + const gl::FramebufferAttachment &firstAttachment = mColorAttachments[firstAttachmentIdx]; + if (!firstAttachment.isAttached()) + { + continue; + } + + for (size_t secondAttachmentIdx = firstAttachmentIdx + 1; + secondAttachmentIdx < mColorAttachments.size(); secondAttachmentIdx++) + { + const gl::FramebufferAttachment &secondAttachment = + mColorAttachments[secondAttachmentIdx]; + if (!secondAttachment.isAttached()) + { + continue; + } + + if (firstAttachment == secondAttachment) + { + return false; + } + } + } + + return true; } -void Framebuffer::setLabel(const std::string &label) +bool FramebufferState::hasDepth() const { - mData.mLabel = label; + return (mDepthAttachment.isAttached() && mDepthAttachment.getDepthSize() > 0); } -const std::string &Framebuffer::getLabel() const +bool FramebufferState::hasStencil() const { - return mData.mLabel; + return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0); } -void Framebuffer::detachTexture(GLuint textureId) +GLsizei FramebufferState::getNumViews() const { - detachResourceById(GL_TEXTURE, textureId); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return FramebufferAttachment::kDefaultNumViews; + } + return attachment->getNumViews(); } -void Framebuffer::detachRenderbuffer(GLuint renderbufferId) +const std::vector *FramebufferState::getViewportOffsets() const { - detachResourceById(GL_RENDERBUFFER, renderbufferId); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return nullptr; + } + return &attachment->getMultiviewViewportOffsets(); } -void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) +GLenum FramebufferState::getMultiviewLayout() const { - for (auto &colorAttachment : mData.mColorAttachments) + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) { - DetachMatchingAttachment(&colorAttachment, resourceType, resourceId); + return GL_NONE; } - - DetachMatchingAttachment(&mData.mDepthAttachment, resourceType, resourceId); - DetachMatchingAttachment(&mData.mStencilAttachment, resourceType, resourceId); + return attachment->getMultiviewLayout(); } -const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const +int FramebufferState::getBaseViewIndex() const { - return mData.getColorAttachment(colorAttachment); + const FramebufferAttachment *attachment = getFirstNonNullAttachment(); + if (attachment == nullptr) + { + return GL_NONE; + } + return attachment->getBaseViewIndex(); } -const FramebufferAttachment *Framebuffer::getDepthbuffer() const +Box FramebufferState::getDimensions() const { - return mData.getDepthAttachment(); + ASSERT(attachmentsHaveSameDimensions()); + ASSERT(getFirstNonNullAttachment() != nullptr); + Extents extents = getFirstNonNullAttachment()->getSize(); + return Box(0, 0, 0, extents.width, extents.height, extents.depth); } -const FramebufferAttachment *Framebuffer::getStencilbuffer() const +Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id) + : mState(caps), + mImpl(factory->createFramebuffer(mState)), + mId(id), + mCachedStatus(), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getStencilAttachment(); + ASSERT(mId != 0); + ASSERT(mImpl != nullptr); + ASSERT(mState.mColorAttachments.size() == static_cast(caps.maxColorAttachments)); + + for (uint32_t colorIndex = 0; + colorIndex < static_cast(mState.mColorAttachments.size()); ++colorIndex) + { + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex); + } } -const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const +Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface) + : mState(), + mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)), + mId(0), + mCachedStatus(GL_FRAMEBUFFER_COMPLETE), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getDepthStencilAttachment(); + ASSERT(mImpl != nullptr); + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0); + + const Context *proxyContext = display->getProxyContext(); + + setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), + surface, FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + + if (surface->getConfig()->depthSize > 0) + { + setAttachmentImpl( + proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), surface, + FramebufferAttachment::kDefaultNumViews, FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + } + + if (surface->getConfig()->stencilSize > 0) + { + setAttachmentImpl(proxyContext, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, + gl::ImageIndex::MakeInvalid(), surface, + FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); + } } -const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const +Framebuffer::Framebuffer(rx::GLImplFactory *factory) + : mState(), + mImpl(factory->createFramebuffer(mState)), + mId(0), + mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES), + mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT), + mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT) { - return mData.getDepthOrStencilAttachment(); + mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0); } -const FramebufferAttachment *Framebuffer::getReadColorbuffer() const +Framebuffer::~Framebuffer() { - return mData.getReadAttachment(); + SafeDelete(mImpl); } -GLenum Framebuffer::getReadColorbufferType() const +void Framebuffer::onDestroy(const Context *context) { - const FramebufferAttachment *readAttachment = mData.getReadAttachment(); - return (readAttachment != nullptr ? readAttachment->type() : GL_NONE); + for (auto &attachment : mState.mColorAttachments) + { + attachment.detach(context); + } + mState.mDepthAttachment.detach(context); + mState.mStencilAttachment.detach(context); + mState.mWebGLDepthAttachment.detach(context); + mState.mWebGLStencilAttachment.detach(context); + mState.mWebGLDepthStencilAttachment.detach(context); + + mImpl->destroy(context); } -const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +void Framebuffer::destroyDefault(const egl::Display *display) { - return mData.getFirstColorAttachment(); + mImpl->destroyDefault(display); } -const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +void Framebuffer::setLabel(const std::string &label) { - if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) - { - return mData.getColorAttachment(attachment - GL_COLOR_ATTACHMENT0); - } - else - { - switch (attachment) - { - case GL_COLOR: - case GL_BACK: - return mData.getColorAttachment(0); - case GL_DEPTH: - case GL_DEPTH_ATTACHMENT: - return mData.getDepthAttachment(); - case GL_STENCIL: - case GL_STENCIL_ATTACHMENT: - return mData.getStencilAttachment(); - case GL_DEPTH_STENCIL: - case GL_DEPTH_STENCIL_ATTACHMENT: - return getDepthStencilBuffer(); - default: - UNREACHABLE(); - return nullptr; - } - } + mState.mLabel = label; } -size_t Framebuffer::getDrawbufferStateCount() const +const std::string &Framebuffer::getLabel() const { - return mData.mDrawBufferStates.size(); + return mState.mLabel; } -GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const +bool Framebuffer::detachTexture(const Context *context, GLuint textureId) { - ASSERT(drawBuffer < mData.mDrawBufferStates.size()); - return mData.mDrawBufferStates[drawBuffer]; + return detachResourceById(context, GL_TEXTURE, textureId); } -void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +bool Framebuffer::detachRenderbuffer(const Context *context, GLuint renderbufferId) { - auto &drawStates = mData.mDrawBufferStates; - - ASSERT(count <= drawStates.size()); - std::copy(buffers, buffers + count, drawStates.begin()); - std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); - mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS); + return detachResourceById(context, GL_RENDERBUFFER, renderbufferId); } -const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const +bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId) { - ASSERT(drawBuffer < mData.mDrawBufferStates.size()); - if (mData.mDrawBufferStates[drawBuffer] != GL_NONE) + bool found = false; + + for (size_t colorIndex = 0; colorIndex < mState.mColorAttachments.size(); ++colorIndex) { - // 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]); + if (detachMatchingAttachment(context, &mState.mColorAttachments[colorIndex], resourceType, + resourceId, DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex)) + { + found = true; + } + } + + if (context->isWebGL1()) + { + const std::array attachments = { + {&mState.mWebGLDepthStencilAttachment, &mState.mWebGLDepthAttachment, + &mState.mWebGLStencilAttachment}}; + for (FramebufferAttachment *attachment : attachments) + { + if (attachment->isAttached() && attachment->type() == resourceType && + attachment->id() == resourceId) + { + resetAttachment(context, attachment->getBinding()); + found = true; + } + } } else { - return nullptr; + if (detachMatchingAttachment(context, &mState.mDepthAttachment, resourceType, resourceId, + DIRTY_BIT_DEPTH_ATTACHMENT)) + { + found = true; + } + if (detachMatchingAttachment(context, &mState.mStencilAttachment, resourceType, resourceId, + DIRTY_BIT_STENCIL_ATTACHMENT)) + { + found = true; + } } + + return found; } -bool Framebuffer::hasEnabledDrawBuffer() const +bool Framebuffer::detachMatchingAttachment(const Context *context, + FramebufferAttachment *attachment, + GLenum matchType, + GLuint matchId, + size_t dirtyBit) { - for (size_t drawbufferIdx = 0; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx) + if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId) { - if (getDrawBuffer(drawbufferIdx) != nullptr) - { - return true; - } + attachment->detach(context); + mDirtyBits.set(dirtyBit); + mState.mResourceNeedsInit.set(dirtyBit, false); + return true; } return false; } -GLenum Framebuffer::getReadBufferState() const +const FramebufferAttachment *Framebuffer::getColorbuffer(size_t colorAttachment) const { - return mData.mReadBufferState; + return mState.getColorAttachment(colorAttachment); } -void Framebuffer::setReadBuffer(GLenum buffer) +const FramebufferAttachment *Framebuffer::getDepthbuffer() const { - ASSERT(buffer == GL_BACK || buffer == GL_NONE || - (buffer >= GL_COLOR_ATTACHMENT0 && - (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size())); - mData.mReadBufferState = buffer; - mDirtyBits.set(DIRTY_BIT_READ_BUFFER); + return mState.getDepthAttachment(); } -size_t Framebuffer::getNumColorBuffers() const +const FramebufferAttachment *Framebuffer::getStencilbuffer() const { - return mData.mColorAttachments.size(); + return mState.getStencilAttachment(); } -bool Framebuffer::hasDepth() const +const FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const { - return (mData.mDepthAttachment.isAttached() && mData.mDepthAttachment.getDepthSize() > 0); + return mState.getDepthStencilAttachment(); } -bool Framebuffer::hasStencil() const +const FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const { - return (mData.mStencilAttachment.isAttached() && mData.mStencilAttachment.getStencilSize() > 0); + return mState.getDepthOrStencilAttachment(); } -bool Framebuffer::usingExtendedDrawBuffers() const +const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const { - for (size_t drawbufferIdx = 1; drawbufferIdx < mData.mDrawBufferStates.size(); ++drawbufferIdx) - { - if (getDrawBuffer(drawbufferIdx) != nullptr) + return mState.getStencilOrDepthStencilAttachment(); +} + +const FramebufferAttachment *Framebuffer::getReadColorbuffer() const +{ + return mState.getReadAttachment(); +} + +GLenum Framebuffer::getReadColorbufferType() const +{ + const FramebufferAttachment *readAttachment = mState.getReadAttachment(); + return (readAttachment != nullptr ? readAttachment->type() : GL_NONE); +} + +const FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +{ + return mState.getFirstColorAttachment(); +} + +const FramebufferAttachment *Framebuffer::getFirstNonNullAttachment() const +{ + return mState.getFirstNonNullAttachment(); +} + +const FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +{ + return mState.getAttachment(attachment); +} + +size_t Framebuffer::getDrawbufferStateCount() const +{ + return mState.mDrawBufferStates.size(); +} + +GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const +{ + ASSERT(drawBuffer < mState.mDrawBufferStates.size()); + return mState.mDrawBufferStates[drawBuffer]; +} + +const std::vector &Framebuffer::getDrawBufferStates() const +{ + return mState.getDrawBufferStates(); +} + +void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +{ + auto &drawStates = mState.mDrawBufferStates; + + ASSERT(count <= drawStates.size()); + std::copy(buffers, buffers + count, drawStates.begin()); + std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); + mDirtyBits.set(DIRTY_BIT_DRAW_BUFFERS); + + mState.mEnabledDrawBuffers.reset(); + for (size_t index = 0; index < count; ++index) + { + if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached()) + { + mState.mEnabledDrawBuffers.set(index); + } + } +} + +const FramebufferAttachment *Framebuffer::getDrawBuffer(size_t drawBuffer) const +{ + return mState.getDrawBuffer(drawBuffer); +} + +GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const +{ + const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer); + if (attachment == nullptr) + { + return GL_NONE; + } + + GLenum componentType = attachment->getFormat().info->componentType; + switch (componentType) + { + case GL_INT: + case GL_UNSIGNED_INT: + return componentType; + + default: + return GL_FLOAT; + } +} + +bool Framebuffer::hasEnabledDrawBuffer() const +{ + for (size_t drawbufferIdx = 0; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx) + { + if (getDrawBuffer(drawbufferIdx) != nullptr) { return true; } @@ -381,210 +870,276 @@ bool Framebuffer::usingExtendedDrawBuffers() const return false; } -GLenum Framebuffer::checkStatus(const gl::Data &data) const +GLenum Framebuffer::getReadBufferState() const +{ + return mState.mReadBufferState; +} + +void Framebuffer::setReadBuffer(GLenum buffer) +{ + ASSERT(buffer == GL_BACK || buffer == GL_NONE || + (buffer >= GL_COLOR_ATTACHMENT0 && + (buffer - GL_COLOR_ATTACHMENT0) < mState.mColorAttachments.size())); + mState.mReadBufferState = buffer; + mDirtyBits.set(DIRTY_BIT_READ_BUFFER); +} + +size_t Framebuffer::getNumColorBuffers() const +{ + return mState.mColorAttachments.size(); +} + +bool Framebuffer::hasDepth() const +{ + return mState.hasDepth(); +} + +bool Framebuffer::hasStencil() const +{ + return mState.hasStencil(); +} + +bool Framebuffer::usingExtendedDrawBuffers() const +{ + for (size_t drawbufferIdx = 1; drawbufferIdx < mState.mDrawBufferStates.size(); ++drawbufferIdx) + { + if (getDrawBuffer(drawbufferIdx) != nullptr) + { + return true; + } + } + + return false; +} + +void Framebuffer::invalidateCompletenessCache() +{ + if (mId != 0) + { + mCachedStatus.reset(); + } +} + +GLenum Framebuffer::checkStatus(const Context *context) { - // The default framebuffer *must* always be complete, though it may not be - // subject to the same rules as application FBOs. ie, it could have 0x0 size. + // The default framebuffer is always complete except when it is surfaceless in which + // case it is always unsupported. We return early because the default framebuffer may + // not be subject to the same rules as application FBOs. ie, it could have 0x0 size. if (mId == 0) { - return GL_FRAMEBUFFER_COMPLETE; + ASSERT(mCachedStatus.valid()); + ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE || + mCachedStatus.value() == GL_FRAMEBUFFER_UNDEFINED_OES); + return mCachedStatus.value(); } - unsigned int colorbufferSize = 0; - int samples = -1; - bool missingAttachment = true; + if (hasAnyDirtyBit() || !mCachedStatus.valid()) + { + mCachedStatus = checkStatusImpl(context); + } + + return mCachedStatus.value(); +} + +GLenum Framebuffer::checkStatusImpl(const Context *context) +{ + const ContextState &state = context->getContextState(); + + ASSERT(mId != 0); + + bool hasAttachments = false; + Optional colorbufferSize; + Optional samples; + Optional fixedSampleLocations; + bool hasRenderbuffer = false; + + const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment(); - for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments) + for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments) { if (colorAttachment.isAttached()) { - const Extents &size = colorAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!CheckAttachmentCompleteness(context, colorAttachment)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - GLenum internalformat = colorAttachment.getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (colorAttachment.type() == GL_TEXTURE) + const InternalFormat &format = *colorAttachment.getFormat().info; + if (format.depthBits > 0 || format.stencilBits > 0) { - if (!formatCaps.renderable) - { - 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; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - else if (colorAttachment.type() == GL_RENDERBUFFER) + + if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples, + &fixedSampleLocations)) { - if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; } - if (!missingAttachment) + // in GLES 2.0, all color attachments attachments must have the same number of bitplanes + // in GLES 3.0, there is no such restriction + if (state.getClientMajorVersion() < 3) { - // 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) - { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; - } - - // in GLES 2.0, all color attachments attachments must have the same number of bitplanes - // in GLES 3.0, there is no such restriction - if (data.clientVersion < 3) + if (colorbufferSize.valid()) { - if (formatInfo.pixelBytes != colorbufferSize) + if (format.pixelBytes != colorbufferSize.value()) { return GL_FRAMEBUFFER_UNSUPPORTED; } } + else + { + colorbufferSize = format.pixelBytes; + } } - else + + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment)) { - samples = colorAttachment.getSamples(); - colorbufferSize = formatInfo.pixelBytes; - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } + + hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; } } - const FramebufferAttachment &depthAttachment = mData.mDepthAttachment; + const FramebufferAttachment &depthAttachment = mState.mDepthAttachment; if (depthAttachment.isAttached()) { - const Extents &size = depthAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!CheckAttachmentCompleteness(context, depthAttachment)) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - GLenum internalformat = depthAttachment.getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (depthAttachment.type() == GL_TEXTURE) + const InternalFormat &format = *depthAttachment.getFormat().info; + if (format.depthBits == 0) { - // depth texture attachments require OES/ANGLE_depth_texture - if (!data.extensions->depthTextures) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples, + &fixedSampleLocations)) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + } - if (formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment)) + { + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } - else if (depthAttachment.type() == GL_RENDERBUFFER) + + hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; + } + + const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment; + if (stencilAttachment.isAttached()) + { + if (!CheckAttachmentCompleteness(context, stencilAttachment)) { - if (!formatCaps.renderable || formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + const InternalFormat &format = *stencilAttachment.getFormat().info; + if (format.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (missingAttachment) + if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples, + &fixedSampleLocations)) { - samples = depthAttachment.getSamples(); - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; } - else if (samples != depthAttachment.getSamples()) + + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment)) { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } + + hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER); + hasAttachments = true; } - const FramebufferAttachment &stencilAttachment = mData.mStencilAttachment; - if (stencilAttachment.isAttached()) + // Starting from ES 3.0 stencil and depth, if present, should be the same image + if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() && + stencilAttachment.isAttached() && stencilAttachment != depthAttachment) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL. + if (state.isWebGL1()) { - const Extents &size = stencilAttachment.getSize(); - if (size.width == 0 || size.height == 0) + if (!mState.mWebGLDepthStencilConsistent) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_UNSUPPORTED; } - GLenum internalformat = stencilAttachment.getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (stencilAttachment.type() == GL_TEXTURE) + if (mState.mWebGLDepthStencilAttachment.isAttached()) { - // texture stencil attachments come along as part - // of OES_packed_depth_stencil + OES/ANGLE_depth_texture - if (!data.extensions->depthTextures) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - if (!formatCaps.renderable) + if (mState.mWebGLDepthStencilAttachment.getDepthSize() == 0 || + mState.mWebGLDepthStencilAttachment.getStencilSize() == 0) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - if (formatInfo.stencilBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else if (stencilAttachment.type() == GL_RENDERBUFFER) - { - if (!formatCaps.renderable || formatInfo.stencilBits == 0) + if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, + &mState.mWebGLDepthStencilAttachment)) { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE; } } - - if (missingAttachment) + else if (mState.mStencilAttachment.isAttached() && + mState.mStencilAttachment.getDepthSize() > 0) { - samples = stencilAttachment.getSamples(); - missingAttachment = false; + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } - else if (samples != stencilAttachment.getSamples()) + else if (mState.mDepthAttachment.isAttached() && + mState.mDepthAttachment.getStencilSize() > 0) { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } } - // we need to have at least one attachment to be complete - if (missingAttachment) + // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the + // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters + // is zero, the framebuffer is considered incomplete. + GLint defaultWidth = mState.getDefaultWidth(); + GLint defaultHeight = mState.getDefaultHeight(); + if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0)) { return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } - // In ES 2.0, all color attachments must have the same width and height. + // In ES 2.0 and WebGL, 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()) + if ((state.getClientMajorVersion() < 3 || state.getExtensions().webglCompatibility) && + !mState.attachmentsHaveSameDimensions()) { return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } - syncState(); - if (!mImpl->checkStatus()) + // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and + // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures. + if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + } + + // The WebGL conformance tests implicitly define that all framebuffer + // attachments must be unique. For example, the same level of a texture can + // not be attached to two different color attachments. + if (state.getExtensions().webglCompatibility) + { + if (!mState.colorAttachmentsAreUniqueImages()) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + + syncState(context); + if (!mImpl->checkStatus(context)) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -592,216 +1147,1036 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const return GL_FRAMEBUFFER_COMPLETE; } -Error Framebuffer::discard(size_t count, const GLenum *attachments) +Error Framebuffer::discard(const Context *context, size_t count, const GLenum *attachments) +{ + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL. + + return mImpl->discard(context, count, attachments); +} + +Error Framebuffer::invalidate(const Context *context, size_t count, const GLenum *attachments) { - return mImpl->discard(count, attachments); + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): WebGL behaviour, and robust resource init behaviour without WebGL. + + return mImpl->invalidate(context, count, attachments); } -Error Framebuffer::invalidate(size_t count, const GLenum *attachments) +bool Framebuffer::partialClearNeedsInit(const Context *context, + bool color, + bool depth, + bool stencil) { - return mImpl->invalidate(count, attachments); + const auto &glState = context->getGLState(); + + if (!glState.isRobustResourceInitEnabled()) + { + return false; + } + + // Scissors can affect clearing. + // TODO(jmadill): Check for complete scissor overlap. + if (glState.isScissorTestEnabled()) + { + return true; + } + + // If colors masked, we must clear before we clear. Do a simple check. + // TODO(jmadill): Filter out unused color channels from the test. + if (color) + { + const auto &blend = glState.getBlendState(); + if (!(blend.colorMaskRed && blend.colorMaskGreen && blend.colorMaskBlue && + blend.colorMaskAlpha)) + { + return true; + } + } + + const auto &depthStencil = glState.getDepthStencilState(); + ASSERT(depthStencil.stencilBackMask == depthStencil.stencilMask); + if (stencil && depthStencil.stencilMask != depthStencil.stencilWritemask) + { + return true; + } + + return false; } -Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) +Error Framebuffer::invalidateSub(const Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) { - return mImpl->invalidateSub(count, attachments, area); + // Back-ends might make the contents of the FBO undefined. In WebGL 2.0, invalidate operations + // can be no-ops, so we should probably do that to ensure consistency. + // TODO(jmadill): Make a invalidate no-op in WebGL 2.0. + + return mImpl->invalidateSub(context, count, attachments, area); } -Error Framebuffer::clear(const gl::Data &data, GLbitfield mask) +Error Framebuffer::clear(const gl::Context *context, GLbitfield mask) { - if (data.state->isRasterizerDiscardEnabled()) + const auto &glState = context->getGLState(); + if (glState.isRasterizerDiscardEnabled()) + { + return NoError(); + } + + const auto &blend = glState.getBlendState(); + const auto &depthStencil = glState.getDepthStencilState(); + + bool color = (mask & GL_COLOR_BUFFER_BIT) != 0 && !IsColorMaskedOut(blend); + bool depth = (mask & GL_DEPTH_BUFFER_BIT) != 0 && !IsDepthMaskedOut(depthStencil); + bool stencil = (mask & GL_STENCIL_BUFFER_BIT) != 0 && !IsStencilMaskedOut(depthStencil); + + if (partialClearNeedsInit(context, color, depth, stencil)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureDrawAttachmentsInitialized(context)); } - return mImpl->clear(data, mask); + ANGLE_TRY(mImpl->clear(context, mask)); + + if (glState.isRobustResourceInitEnabled()) + { + markDrawAttachmentsInitialized(color, depth, stencil); + } + + return NoError(); } -Error Framebuffer::clearBufferfv(const gl::Data &data, +Error Framebuffer::clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - return mImpl->clearBufferfv(data, buffer, drawbuffer, values); + if (partialBufferClearNeedsInit(context, buffer)) + { + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); + } + + ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferuiv(const gl::Data &data, +Error Framebuffer::clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) + { + return NoError(); + } + + if (partialBufferClearNeedsInit(context, buffer)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); } - return mImpl->clearBufferuiv(data, buffer, drawbuffer, values); + ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferiv(const gl::Data &data, +Error Framebuffer::clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) { - return gl::Error(GL_NO_ERROR); + return NoError(); } - return mImpl->clearBufferiv(data, buffer, drawbuffer, values); + if (partialBufferClearNeedsInit(context, buffer)) + { + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); + } + + ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -Error Framebuffer::clearBufferfi(const gl::Data &data, +Error Framebuffer::clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - if (data.state->isRasterizerDiscardEnabled()) + if (context->getGLState().isRasterizerDiscardEnabled() || + IsClearBufferMaskedOut(context, buffer)) + { + return NoError(); + } + + if (partialBufferClearNeedsInit(context, buffer)) { - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureBufferInitialized(context, buffer, drawbuffer)); } - return mImpl->clearBufferfi(data, buffer, drawbuffer, depth, stencil); + ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil)); + + if (context->isRobustResourceInitEnabled()) + { + markBufferInitialized(buffer, drawbuffer); + } + return NoError(); } -GLenum Framebuffer::getImplementationColorReadFormat() const +GLenum Framebuffer::getImplementationColorReadFormat(const Context *context) const { - return mImpl->getImplementationColorReadFormat(); + return mImpl->getImplementationColorReadFormat(context); } -GLenum Framebuffer::getImplementationColorReadType() const +GLenum Framebuffer::getImplementationColorReadType(const Context *context) const { - return mImpl->getImplementationColorReadType(); + return mImpl->getImplementationColorReadType(context); } -Error Framebuffer::readPixels(const State &state, +Error Framebuffer::readPixels(const gl::Context *context, const Rectangle &area, GLenum format, GLenum type, - GLvoid *pixels) const + void *pixels) { - Error error = mImpl->readPixels(state, area, format, type, pixels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); + ANGLE_TRY(mImpl->readPixels(context, area, format, type, pixels)); - Buffer *unpackBuffer = state.getUnpackState().pixelBuffer.get(); + Buffer *unpackBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); if (unpackBuffer) { unpackBuffer->onPixelUnpack(); } - return Error(GL_NO_ERROR); + return NoError(); } -Error Framebuffer::blit(const State &state, +Error Framebuffer::blit(const gl::Context *context, const Rectangle &sourceArea, const Rectangle &destArea, GLbitfield mask, - GLenum filter, - const Framebuffer *sourceFramebuffer) + GLenum filter) { - return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer); -} + GLbitfield blitMask = mask; -int Framebuffer::getSamples(const gl::Data &data) const -{ - if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + // Note that blitting is called against draw framebuffer. + // See the code in gl::Context::blitFramebuffer. + if ((mask & GL_COLOR_BUFFER_BIT) && !hasEnabledDrawBuffer()) { - // for a complete framebuffer, all attachments must have the same sample count - // in this case return the first nonzero sample size - for (const FramebufferAttachment &colorAttachment : mData.mColorAttachments) - { - if (colorAttachment.isAttached()) - { - return colorAttachment.getSamples(); - } - } + blitMask &= ~GL_COLOR_BUFFER_BIT; + } + + if ((mask & GL_STENCIL_BUFFER_BIT) && mState.getStencilAttachment() == nullptr) + { + blitMask &= ~GL_STENCIL_BUFFER_BIT; + } + + if ((mask & GL_DEPTH_BUFFER_BIT) && mState.getDepthAttachment() == nullptr) + { + blitMask &= ~GL_DEPTH_BUFFER_BIT; + } + + if (!blitMask) + { + return NoError(); + } + + auto *sourceFBO = context->getGLState().getReadFramebuffer(); + ANGLE_TRY(sourceFBO->ensureReadAttachmentInitialized(context, blitMask)); + + // TODO(jmadill): Only clear if not the full FBO dimensions, and only specified bitmask. + ANGLE_TRY(ensureDrawAttachmentsInitialized(context)); + + return mImpl->blit(context, sourceArea, destArea, blitMask, filter); +} + +int Framebuffer::getSamples(const Context *context) +{ + if (complete(context)) + { + return getCachedSamples(context); } return 0; } +int Framebuffer::getCachedSamples(const Context *context) +{ + // For a complete framebuffer, all attachments must have the same sample count. + // In this case return the first nonzero sample size. + const auto *firstNonNullAttachment = mState.getFirstNonNullAttachment(); + if (firstNonNullAttachment) + { + ASSERT(firstNonNullAttachment->isAttached()); + return firstNonNullAttachment->getSamples(); + } + + // No attachments found. + return 0; +} + +Error Framebuffer::getSamplePosition(size_t index, GLfloat *xy) const +{ + ANGLE_TRY(mImpl->getSamplePosition(index, xy)); + return NoError(); +} + bool Framebuffer::hasValidDepthStencil() const { - return mData.getDepthStencilAttachment() != nullptr; + return mState.getDepthStencilAttachment() != nullptr; } -void Framebuffer::setAttachment(GLenum type, +void Framebuffer::setAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource) { - if (binding == GL_DEPTH_STENCIL || binding == GL_DEPTH_STENCIL_ATTACHMENT) + setAttachment(context, type, binding, textureIndex, resource, + FramebufferAttachment::kDefaultNumViews, + FramebufferAttachment::kDefaultBaseViewIndex, + FramebufferAttachment::kDefaultMultiviewLayout, + FramebufferAttachment::kDefaultViewportOffsets); +} + +void Framebuffer::setAttachment(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + // Context may be null in unit tests. + if (!context || !context->isWebGL1()) + { + setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + return; + } + + switch (binding) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex, + resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + break; + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + break; + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + break; + default: + setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, + baseViewIndex, multiviewLayout, viewportOffsets); + return; + } + + commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); +} + +void Framebuffer::setAttachmentMultiviewLayered(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLint baseViewIndex) +{ + setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, + FramebufferAttachment::kDefaultViewportOffsets); +} + +void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + const GLint *viewportOffsets) +{ + setAttachment(context, type, binding, textureIndex, resource, numViews, + FramebufferAttachment::kDefaultBaseViewIndex, + GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets); +} + +void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + int count = 0; + + std::array attachments = {{&mState.mWebGLDepthStencilAttachment, + &mState.mWebGLDepthAttachment, + &mState.mWebGLStencilAttachment}}; + for (FramebufferAttachment *attachment : attachments) { - // ensure this is a legitimate depth+stencil format - FramebufferAttachmentObject *attachmentObj = resource; - if (resource) + if (attachment->isAttached()) { - FramebufferAttachment::Target target(binding, textureIndex); - GLenum internalFormat = resource->getAttachmentInternalFormat(target); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat); - if (formatInfo.depthBits == 0 || formatInfo.stencilBits == 0) - { - // Attaching nullptr detaches the current attachment. - attachmentObj = nullptr; - } + count++; + } + } + + mState.mWebGLDepthStencilConsistent = (count <= 1); + if (!mState.mWebGLDepthStencilConsistent) + { + // Inconsistent. + return; + } + + auto getImageIndexIfTextureAttachment = [](const FramebufferAttachment &attachment) { + if (attachment.type() == GL_TEXTURE) + { + return attachment.getTextureImageIndex(); + } + else + { + return ImageIndex::MakeInvalid(); } + }; - 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); + if (mState.mWebGLDepthAttachment.isAttached()) + { + const auto &depth = mState.mWebGLDepthAttachment; + setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT, + getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews, + baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), + nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } + else if (mState.mWebGLStencilAttachment.isAttached()) + { + const auto &stencil = mState.mWebGLStencilAttachment; + setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT, + getImageIndexIfTextureAttachment(stencil), stencil.getResource(), + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } + else if (mState.mWebGLDepthStencilAttachment.isAttached()) + { + const auto &depthStencil = mState.mWebGLDepthStencilAttachment; + setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT, + getImageIndexIfTextureAttachment(depthStencil), + depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT, + getImageIndexIfTextureAttachment(depthStencil), + depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout, + viewportOffsets); } else { - switch (binding) + setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex::MakeInvalid(), nullptr, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex::MakeInvalid(), + nullptr, numViews, baseViewIndex, multiviewLayout, viewportOffsets); + } +} + +void Framebuffer::setAttachmentImpl(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + switch (binding) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: { - case GL_DEPTH: - case GL_DEPTH_ATTACHMENT: - mData.mDepthAttachment.attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_DEPTH_ATTACHMENT); + // ensure this is a legitimate depth+stencil format + FramebufferAttachmentObject *attachmentObj = resource; + if (resource) + { + const Format &format = resource->getAttachmentFormat(binding, textureIndex); + if (format.info->depthBits == 0 || format.info->stencilBits == 0) + { + // Attaching nullptr detaches the current attachment. + attachmentObj = nullptr; + } + } + + updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT, + &mDirtyDepthAttachmentBinding, type, binding, textureIndex, + attachmentObj, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT, + &mDirtyStencilAttachmentBinding, type, binding, textureIndex, + attachmentObj, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); break; - case GL_STENCIL: - case GL_STENCIL_ATTACHMENT: - mData.mStencilAttachment.attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_STENCIL_ATTACHMENT); + } + + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT, + &mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); break; - case GL_BACK: - mData.mColorAttachments[0].attach(type, binding, textureIndex, resource); - mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0); + + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT, + &mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, viewportOffsets); + break; + + case GL_BACK: + mState.mColorAttachments[0].attach(context, type, binding, textureIndex, resource, + numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + mDirtyBits.set(DIRTY_BIT_COLOR_ATTACHMENT_0); + // No need for a resource binding for the default FBO, it's always complete. break; + + default: + { + size_t colorIndex = binding - GL_COLOR_ATTACHMENT0; + ASSERT(colorIndex < mState.mColorAttachments.size()); + size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex; + updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit, + &mDirtyColorAttachmentBindings[colorIndex], type, binding, + textureIndex, resource, numViews, baseViewIndex, multiviewLayout, + viewportOffsets); + + // TODO(jmadill): ASSERT instead of checking the attachment exists in + // formsRenderingFeedbackLoopWith + bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE); + mState.mEnabledDrawBuffers.set(colorIndex, enabled); + } + break; + } + + mAttachedTextures.reset(); +} + +void Framebuffer::updateAttachment(const Context *context, + FramebufferAttachment *attachment, + size_t dirtyBit, + OnAttachmentDirtyBinding *onDirtyBinding, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) +{ + attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex, + multiviewLayout, viewportOffsets); + mDirtyBits.set(dirtyBit); + mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit); + BindResourceChannel(onDirtyBinding, resource); +} + +void Framebuffer::resetAttachment(const Context *context, GLenum binding) +{ + setAttachment(context, GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr); +} + +void Framebuffer::syncState(const Context *context) +{ + if (mDirtyBits.any()) + { + mImpl->syncState(context, mDirtyBits); + mDirtyBits.reset(); + if (mId != 0) + { + mCachedStatus.reset(); + } + } +} + +void Framebuffer::signal(size_t dirtyBit, InitState state) +{ + // TOOD(jmadill): Make this only update individual attachments to do less work. + mCachedStatus.reset(); + + // Mark the appropriate init flag. + mState.mResourceNeedsInit.set(dirtyBit, state == InitState::MayNeedInit); +} + +bool Framebuffer::complete(const Context *context) +{ + return (checkStatus(context) == GL_FRAMEBUFFER_COMPLETE); +} + +bool Framebuffer::cachedComplete() const +{ + return (mCachedStatus.valid() && mCachedStatus == GL_FRAMEBUFFER_COMPLETE); +} + +bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const +{ + const Program *program = state.getProgram(); + + // TODO(jmadill): Default framebuffer feedback loops. + if (mId == 0) + { + return false; + } + + // The bitset will skip inactive draw buffers. + for (size_t drawIndex : mState.mEnabledDrawBuffers) + { + const FramebufferAttachment &attachment = mState.mColorAttachments[drawIndex]; + ASSERT(attachment.isAttached()); + if (attachment.type() == GL_TEXTURE) + { + // Validate the feedback loop. + if (program->samplesFromTexture(state, attachment.id())) + { + return true; + } + } + } + + // Validate depth-stencil feedback loop. + const auto &dsState = state.getDepthStencilState(); + + // We can skip the feedback loop checks if depth/stencil is masked out or disabled. + const FramebufferAttachment *depth = getDepthbuffer(); + if (depth && depth->type() == GL_TEXTURE && dsState.depthTest && dsState.depthMask) + { + if (program->samplesFromTexture(state, depth->id())) + { + return true; + } + } + + // Note: we assume the front and back masks are the same for WebGL. + const FramebufferAttachment *stencil = getStencilbuffer(); + ASSERT(dsState.stencilBackWritemask == dsState.stencilWritemask); + if (stencil && stencil->type() == GL_TEXTURE && dsState.stencilTest && + dsState.stencilWritemask != 0) + { + // Skip the feedback loop check if depth/stencil point to the same resource. + if (!depth || *stencil != *depth) + { + if (program->samplesFromTexture(state, stencil->id())) + { + return true; + } + } + } + + return false; +} + +bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, + GLint copyTextureLevel, + GLint copyTextureLayer) const +{ + if (mId == 0) + { + // It seems impossible to form a texture copying feedback loop with the default FBO. + return false; + } + + const FramebufferAttachment *readAttachment = getReadColorbuffer(); + ASSERT(readAttachment); + + if (readAttachment->isTextureWithId(copyTextureID)) + { + const auto &imageIndex = readAttachment->getTextureImageIndex(); + if (imageIndex.mipIndex == copyTextureLevel) + { + // Check 3D/Array texture layers. + return imageIndex.layerIndex == ImageIndex::ENTIRE_LEVEL || + copyTextureLayer == ImageIndex::ENTIRE_LEVEL || + imageIndex.layerIndex == copyTextureLayer; + } + } + return false; +} + +GLint Framebuffer::getDefaultWidth() const +{ + return mState.getDefaultWidth(); +} + +GLint Framebuffer::getDefaultHeight() const +{ + return mState.getDefaultHeight(); +} + +GLint Framebuffer::getDefaultSamples() const +{ + return mState.getDefaultSamples(); +} + +bool Framebuffer::getDefaultFixedSampleLocations() const +{ + return mState.getDefaultFixedSampleLocations(); +} + +void Framebuffer::setDefaultWidth(GLint defaultWidth) +{ + mState.mDefaultWidth = defaultWidth; + mDirtyBits.set(DIRTY_BIT_DEFAULT_WIDTH); +} + +void Framebuffer::setDefaultHeight(GLint defaultHeight) +{ + mState.mDefaultHeight = defaultHeight; + mDirtyBits.set(DIRTY_BIT_DEFAULT_HEIGHT); +} + +void Framebuffer::setDefaultSamples(GLint defaultSamples) +{ + mState.mDefaultSamples = defaultSamples; + mDirtyBits.set(DIRTY_BIT_DEFAULT_SAMPLES); +} + +void Framebuffer::setDefaultFixedSampleLocations(bool defaultFixedSampleLocations) +{ + mState.mDefaultFixedSampleLocations = defaultFixedSampleLocations; + mDirtyBits.set(DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS); +} + +// TODO(jmadill): Remove this kludge. +GLenum Framebuffer::checkStatus(const ValidationContext *context) +{ + return checkStatus(static_cast(context)); +} + +int Framebuffer::getSamples(const ValidationContext *context) +{ + return getSamples(static_cast(context)); +} + +GLsizei Framebuffer::getNumViews() const +{ + return mState.getNumViews(); +} + +GLint Framebuffer::getBaseViewIndex() const +{ + return mState.getBaseViewIndex(); +} + +const std::vector *Framebuffer::getViewportOffsets() const +{ + return mState.getViewportOffsets(); +} + +GLenum Framebuffer::getMultiviewLayout() const +{ + return mState.getMultiviewLayout(); +} + +Error Framebuffer::ensureDrawAttachmentsInitialized(const Context *context) +{ + if (!context->isRobustResourceInitEnabled()) + { + return NoError(); + } + + // Note: we don't actually filter by the draw attachment enum. Just init everything. + for (size_t bit : mState.mResourceNeedsInit) + { + switch (bit) + { + case DIRTY_BIT_DEPTH_ATTACHMENT: + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + break; + case DIRTY_BIT_STENCIL_ATTACHMENT: + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + break; default: + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bit])); + break; + } + } + + mState.mResourceNeedsInit.reset(); + return NoError(); +} + +Error Framebuffer::ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask) +{ + if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none()) + { + return NoError(); + } + + if ((blitMask & GL_COLOR_BUFFER_BIT) != 0 && mState.mReadBufferState != GL_NONE) + { + size_t readIndex = mState.getReadIndex(); + if (mState.mResourceNeedsInit[readIndex]) + { + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[readIndex])); + mState.mResourceNeedsInit.reset(readIndex); + } + } + + if ((blitMask & GL_DEPTH_BUFFER_BIT) != 0 && hasDepth()) + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + } + + if ((blitMask & GL_STENCIL_BUFFER_BIT) != 0 && hasStencil()) + { + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + } + + return NoError(); +} + +void Framebuffer::markDrawAttachmentsInitialized(bool color, bool depth, bool stencil) +{ + // Mark attachments as initialized. + if (color) + { + for (auto colorIndex : mState.mEnabledDrawBuffers) + { + auto &colorAttachment = mState.mColorAttachments[colorIndex]; + ASSERT(colorAttachment.isAttached()); + colorAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(colorIndex); + } + } + + if (depth && mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + + if (stencil && mState.mStencilAttachment.isAttached()) + { + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } +} + +void Framebuffer::markBufferInitialized(GLenum bufferType, GLint bufferIndex) +{ + switch (bufferType) + { + case GL_COLOR: + { + ASSERT(bufferIndex < static_cast(mState.mColorAttachments.size())); + if (mState.mColorAttachments[bufferIndex].isAttached()) + { + mState.mColorAttachments[bufferIndex].setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(bufferIndex); + } + break; + } + case GL_DEPTH: + { + if (mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + break; + } + case GL_STENCIL: + { + if (mState.mStencilAttachment.isAttached()) + { + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + case GL_DEPTH_STENCIL: + { + if (mState.mDepthAttachment.isAttached()) + { + mState.mDepthAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + if (mState.mStencilAttachment.isAttached()) { - 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); + mState.mStencilAttachment.setInitState(InitState::Initialized); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); } break; } + default: + UNREACHABLE(); + break; } } -void Framebuffer::resetAttachment(GLenum binding) +Box Framebuffer::getDimensions() const { - setAttachment(GL_NONE, binding, ImageIndex::MakeInvalid(), nullptr); + return mState.getDimensions(); } -void Framebuffer::syncState() const +Error Framebuffer::ensureBufferInitialized(const Context *context, + GLenum bufferType, + GLint bufferIndex) { - if (mDirtyBits.any()) + ASSERT(context->isRobustResourceInitEnabled()); + + if (mState.mResourceNeedsInit.none()) { - mImpl->syncState(mDirtyBits); - mDirtyBits.reset(); + return NoError(); } + + switch (bufferType) + { + case GL_COLOR: + { + ASSERT(bufferIndex < static_cast(mState.mColorAttachments.size())); + if (mState.mResourceNeedsInit[bufferIndex]) + { + ANGLE_TRY(InitAttachment(context, &mState.mColorAttachments[bufferIndex])); + mState.mResourceNeedsInit.reset(bufferIndex); + } + break; + } + case GL_DEPTH: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + break; + } + case GL_STENCIL: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + case GL_DEPTH_STENCIL: + { + if (mState.mResourceNeedsInit[DIRTY_BIT_DEPTH_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mDepthAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_DEPTH_ATTACHMENT); + } + if (mState.mResourceNeedsInit[DIRTY_BIT_STENCIL_ATTACHMENT]) + { + ANGLE_TRY(InitAttachment(context, &mState.mStencilAttachment)); + mState.mResourceNeedsInit.reset(DIRTY_BIT_STENCIL_ATTACHMENT); + } + break; + } + default: + UNREACHABLE(); + break; + } + + return NoError(); +} + +bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum bufferType) +{ + if (!context->isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none()) + { + return false; + } + + switch (bufferType) + { + case GL_COLOR: + return partialClearNeedsInit(context, true, false, false); + case GL_DEPTH: + return partialClearNeedsInit(context, false, true, false); + case GL_STENCIL: + return partialClearNeedsInit(context, false, false, true); + case GL_DEPTH_STENCIL: + return partialClearNeedsInit(context, false, true, true); + default: + UNREACHABLE(); + return false; + } +} + +bool Framebuffer::hasTextureAttachment(const Texture *texture) const +{ + if (!mAttachedTextures.valid()) + { + std::set attachedTextures; + + for (const auto &colorAttachment : mState.mColorAttachments) + { + if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(colorAttachment.getResource()); + } + } + + if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(mState.mDepthAttachment.getResource()); + } + + if (mState.mStencilAttachment.isAttached() && + mState.mStencilAttachment.type() == GL_TEXTURE) + { + attachedTextures.insert(mState.mStencilAttachment.getResource()); + } + + mAttachedTextures = std::move(attachedTextures); + } + + return (mAttachedTextures.value().count(texture) > 0); } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.h b/src/3rdparty/angle/src/libANGLE/Framebuffer.h index b07b59ac90..70223f0bc7 100644 --- a/src/3rdparty/angle/src/libANGLE/Framebuffer.h +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.h @@ -12,16 +12,18 @@ #include +#include "common/Optional.h" #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/signal_utils.h" namespace rx { -class ImplFactory; +class GLImplFactory; class FramebufferImpl; class RenderbufferImpl; class SurfaceImpl; @@ -29,98 +31,171 @@ class SurfaceImpl; namespace egl { +class Display; class Surface; } namespace gl { class Context; +class ContextState; +class Framebuffer; class Renderbuffer; class State; class Texture; class TextureCapsMap; +class ValidationContext; struct Caps; -struct Data; struct Extensions; struct ImageIndex; struct Rectangle; -class Framebuffer final : public LabeledObject +class FramebufferState final : angle::NonCopyable { public: + FramebufferState(); + explicit FramebufferState(const Caps &caps); + ~FramebufferState(); - class Data final : angle::NonCopyable + const std::string &getLabel(); + size_t getReadIndex() const; + + const FramebufferAttachment *getAttachment(GLenum attachment) const; + const FramebufferAttachment *getReadAttachment() const; + const FramebufferAttachment *getFirstNonNullAttachment() const; + const FramebufferAttachment *getFirstColorAttachment() const; + const FramebufferAttachment *getDepthOrStencilAttachment() const; + const FramebufferAttachment *getStencilOrDepthStencilAttachment() 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; } + DrawBufferMask getEnabledDrawBuffers() const { return mEnabledDrawBuffers; } + GLenum getReadBufferState() const { return mReadBufferState; } + const std::vector &getColorAttachments() const { - public: - explicit Data(); - explicit Data(const Caps &caps); - ~Data(); + return mColorAttachments; + } - const std::string &getLabel(); + bool attachmentsHaveSameDimensions() const; + bool colorAttachmentsAreUniqueImages() const; + Box getDimensions() const; - 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 FramebufferAttachment *getDrawBuffer(size_t drawBufferIdx) const; + size_t getDrawBufferCount() const; - const std::vector &getDrawBufferStates() const { return mDrawBufferStates; } - GLenum getReadBufferState() const { return mReadBufferState; } - const std::vector &getColorAttachments() const { return mColorAttachments; } + GLint getDefaultWidth() const { return mDefaultWidth; }; + GLint getDefaultHeight() const { return mDefaultHeight; }; + GLint getDefaultSamples() const { return mDefaultSamples; }; + bool getDefaultFixedSampleLocations() const { return mDefaultFixedSampleLocations; }; - bool attachmentsHaveSameDimensions() const; + bool hasDepth() const; + bool hasStencil() const; - private: - friend class Framebuffer; + GLenum getMultiviewLayout() const; + GLsizei getNumViews() const; + const std::vector *getViewportOffsets() const; + GLint getBaseViewIndex() const; - std::string mLabel; + private: + friend class Framebuffer; - std::vector mColorAttachments; - FramebufferAttachment mDepthAttachment; - FramebufferAttachment mStencilAttachment; + std::string mLabel; - std::vector mDrawBufferStates; - GLenum mReadBufferState; - }; + std::vector mColorAttachments; + FramebufferAttachment mDepthAttachment; + FramebufferAttachment mStencilAttachment; - Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id); - Framebuffer(rx::SurfaceImpl *surface); - virtual ~Framebuffer(); + std::vector mDrawBufferStates; + GLenum mReadBufferState; + DrawBufferMask mEnabledDrawBuffers; + + GLint mDefaultWidth; + GLint mDefaultHeight; + GLint mDefaultSamples; + bool mDefaultFixedSampleLocations; + + // It's necessary to store all this extra state so we can restore attachments + // when DEPTH_STENCIL/DEPTH/STENCIL is unbound in WebGL 1. + FramebufferAttachment mWebGLDepthStencilAttachment; + FramebufferAttachment mWebGLDepthAttachment; + FramebufferAttachment mWebGLStencilAttachment; + bool mWebGLDepthStencilConsistent; + + // Tracks if we need to initialize the resources for each attachment. + angle::BitSet mResourceNeedsInit; +}; + +class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver +{ + public: + // Constructor to build application-defined framebuffers + Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id); + // Constructor to build default framebuffers for a surface + Framebuffer(const egl::Display *display, egl::Surface *surface); + // Constructor to build a fake default framebuffer when surfaceless + Framebuffer(rx::GLImplFactory *factory); + + ~Framebuffer() override; + void onDestroy(const Context *context); + void destroyDefault(const egl::Display *display); 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; } + rx::FramebufferImpl *getImplementation() const { return mImpl; } GLuint id() const { return mId; } - void setAttachment(GLenum type, + void setAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource); - void resetAttachment(GLenum binding); - - void detachTexture(GLuint texture); - void detachRenderbuffer(GLuint renderbuffer); + void setAttachmentMultiviewLayered(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLint baseViewIndex); + void setAttachmentMultiviewSideBySide(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + const GLint *viewportOffsets); + void resetAttachment(const Context *context, GLenum binding); + + bool detachTexture(const Context *context, GLuint texture); + bool detachRenderbuffer(const Context *context, GLuint renderbuffer); 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 *getStencilOrDepthStencilAttachment() const; const FramebufferAttachment *getReadColorbuffer() const; GLenum getReadColorbufferType() const; const FramebufferAttachment *getFirstColorbuffer() const; + const FramebufferAttachment *getFirstNonNullAttachment() const; const FramebufferAttachment *getAttachment(GLenum attachment) const; + GLenum getMultiviewLayout() const; + GLsizei getNumViews() const; + GLint getBaseViewIndex() const; + const std::vector *getViewportOffsets() const; size_t getDrawbufferStateCount() const; GLenum getDrawBufferState(size_t drawBuffer) const; + const std::vector &getDrawBufferStates() const; void setDrawBuffers(size_t count, const GLenum *buffers); const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const; + GLenum getDrawbufferWriteType(size_t drawBuffer) const; bool hasEnabledDrawBuffer() const; GLenum getReadBufferState() const; @@ -129,48 +204,81 @@ class Framebuffer final : public LabeledObject size_t getNumColorBuffers() const; bool hasDepth() const; bool hasStencil() const; - int getSamples(const gl::Data &data) const; + bool usingExtendedDrawBuffers() const; - GLenum checkStatus(const gl::Data &data) const; + // This method calls checkStatus. + int getSamples(const Context *context); + + Error getSamplePosition(size_t index, GLfloat *xy) const; + + GLint getDefaultWidth() const; + GLint getDefaultHeight() const; + GLint getDefaultSamples() const; + bool getDefaultFixedSampleLocations() const; + void setDefaultWidth(GLint defaultWidth); + void setDefaultHeight(GLint defaultHeight); + void setDefaultSamples(GLint defaultSamples); + void setDefaultFixedSampleLocations(bool defaultFixedSampleLocations); + + void invalidateCompletenessCache(); + + GLenum checkStatus(const Context *context); + + // TODO(jmadill): Remove this kludge. + GLenum checkStatus(const ValidationContext *context); + int getSamples(const ValidationContext *context); + + // For when we don't want to check completeness in getSamples(). + int getCachedSamples(const Context *context); + + // Helper for checkStatus == GL_FRAMEBUFFER_COMPLETE. + bool complete(const Context *context); + bool cachedComplete() 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 discard(const Context *context, size_t count, const GLenum *attachments); + Error invalidate(const Context *context, size_t count, const GLenum *attachments); + Error invalidateSub(const Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area); - Error clear(const gl::Data &data, GLbitfield mask); - Error clearBufferfv(const gl::Data &data, + Error clear(const gl::Context *context, GLbitfield mask); + Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values); - Error clearBufferuiv(const gl::Data &data, + Error clearBufferuiv(const gl::Context *context, 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, + Error clearBufferiv(const gl::Context *context, + GLenum buffer, + GLint drawbuffer, + const GLint *values); + Error clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); - GLenum getImplementationColorReadFormat() const; - GLenum getImplementationColorReadType() const; - Error readPixels(const gl::State &state, + GLenum getImplementationColorReadFormat(const Context *context) const; + GLenum getImplementationColorReadType(const Context *context) const; + Error readPixels(const gl::Context *context, const gl::Rectangle &area, GLenum format, GLenum type, - GLvoid *pixels) const; + void *pixels); - Error blit(const State &state, + Error blit(const gl::Context *context, const Rectangle &sourceArea, const Rectangle &destArea, GLbitfield mask, - GLenum filter, - const Framebuffer *sourceFramebuffer); + GLenum filter); - enum DirtyBitType + enum DirtyBitType : size_t { DIRTY_BIT_COLOR_ATTACHMENT_0, DIRTY_BIT_COLOR_ATTACHMENT_MAX = @@ -179,26 +287,103 @@ class Framebuffer final : public LabeledObject DIRTY_BIT_STENCIL_ATTACHMENT, DIRTY_BIT_DRAW_BUFFERS, DIRTY_BIT_READ_BUFFER, + DIRTY_BIT_DEFAULT_WIDTH, + DIRTY_BIT_DEFAULT_HEIGHT, + DIRTY_BIT_DEFAULT_SAMPLES, + DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS, DIRTY_BIT_UNKNOWN, - DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, + DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN }; - typedef std::bitset DirtyBits; + typedef angle::BitSet DirtyBits; bool hasAnyDirtyBit() const { return mDirtyBits.any(); } - void syncState() const; + void syncState(const Context *context); - protected: - void detachResourceById(GLenum resourceType, GLuint resourceId); + // OnAttachmentChangedReceiver implementation + void signal(size_t dirtyBit, InitState state) override; - Data mData; + bool formsRenderingFeedbackLoopWith(const State &state) const; + bool formsCopyingFeedbackLoopWith(GLuint copyTextureID, + GLint copyTextureLevel, + GLint copyTextureLayer) const; + + Error ensureDrawAttachmentsInitialized(const Context *context); + Error ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask); + Box getDimensions() const; + + bool hasTextureAttachment(const Texture *texture) const; + + private: + bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId); + bool detachMatchingAttachment(const Context *context, + FramebufferAttachment *attachment, + GLenum matchType, + GLuint matchId, + size_t dirtyBit); + GLenum checkStatusImpl(const Context *context); + void setAttachment(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void commitWebGL1DepthStencilIfConsistent(const Context *context, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void setAttachmentImpl(const Context *context, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + void updateAttachment(const Context *context, + FramebufferAttachment *attachment, + size_t dirtyBit, + OnAttachmentDirtyBinding *onDirtyBinding, + GLenum type, + GLenum binding, + const ImageIndex &textureIndex, + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); + + void markDrawAttachmentsInitialized(bool color, bool depth, bool stencil); + void markBufferInitialized(GLenum bufferType, GLint bufferIndex); + Error ensureBufferInitialized(const Context *context, GLenum bufferType, GLint bufferIndex); + + // Checks that we have a partially masked clear: + // * some color channels are masked out + // * some stencil values are masked out + // * scissor test partially overlaps the framebuffer + bool partialClearNeedsInit(const Context *context, bool color, bool depth, bool stencil); + bool partialBufferClearNeedsInit(const Context *context, GLenum bufferType); + + FramebufferState mState; rx::FramebufferImpl *mImpl; GLuint mId; - // TODO(jmadill): See if we can make this non-mutable. - mutable DirtyBits mDirtyBits; + Optional mCachedStatus; + std::vector mDirtyColorAttachmentBindings; + OnAttachmentDirtyBinding mDirtyDepthAttachmentBinding; + OnAttachmentDirtyBinding mDirtyStencilAttachmentBinding; + + DirtyBits mDirtyBits; + + // A cache of attached textures for quick validation of feedback loops. + mutable Optional> mAttachedTextures; }; -} +} // namespace gl -#endif // LIBANGLE_FRAMEBUFFER_H_ +#endif // LIBANGLE_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp index 352a326c23..cf6bd9c264 100644 --- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp @@ -11,17 +11,48 @@ #include "common/utilities.h" #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" #include "libANGLE/renderer/FramebufferImpl.h" namespace gl { +namespace +{ + +std::vector TransformViewportOffsetArrayToVectorOfOffsets(const GLint *viewportOffsets, + GLsizei numViews) +{ + const size_t numViewsAsSizeT = static_cast(numViews); + std::vector offsetVector; + offsetVector.reserve(numViewsAsSizeT); + for (size_t i = 0u; i < numViewsAsSizeT; ++i) + { + offsetVector.emplace_back(Offset(viewportOffsets[i * 2u], viewportOffsets[i * 2u + 1u], 0)); + } + return offsetVector; +} + +} // namespace + ////// FramebufferAttachment::Target Implementation ////// +const GLsizei FramebufferAttachment::kDefaultNumViews = 1; +const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE; +const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0; +const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0}; + +std::vector FramebufferAttachment::GetDefaultViewportOffsetVector() +{ + return TransformViewportOffsetArrayToVectorOfOffsets( + FramebufferAttachment::kDefaultViewportOffsets, FramebufferAttachment::kDefaultNumViews); +} + FramebufferAttachment::Target::Target() : mBinding(GL_NONE), mTextureIndex(ImageIndex::MakeInvalid()) @@ -50,106 +81,143 @@ FramebufferAttachment::Target &FramebufferAttachment::Target::operator=(const Ta ////// FramebufferAttachment Implementation ////// FramebufferAttachment::FramebufferAttachment() - : mType(GL_NONE), mResource(nullptr) + : mType(GL_NONE), + mResource(nullptr), + mNumViews(kDefaultNumViews), + mMultiviewLayout(kDefaultMultiviewLayout), + mBaseViewIndex(kDefaultBaseViewIndex), + mViewportOffsets(GetDefaultViewportOffsetVector()) { } -FramebufferAttachment::FramebufferAttachment(GLenum type, +FramebufferAttachment::FramebufferAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource) : mResource(nullptr) { - attach(type, binding, textureIndex, resource); + attach(context, type, binding, textureIndex, resource, kDefaultNumViews, kDefaultBaseViewIndex, + kDefaultMultiviewLayout, kDefaultViewportOffsets); } -FramebufferAttachment::FramebufferAttachment(const FramebufferAttachment &other) - : mResource(nullptr) +FramebufferAttachment::FramebufferAttachment(FramebufferAttachment &&other) + : FramebufferAttachment() { - attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource); + *this = std::move(other); } -FramebufferAttachment &FramebufferAttachment::operator=(const FramebufferAttachment &other) +FramebufferAttachment &FramebufferAttachment::operator=(FramebufferAttachment &&other) { - attach(other.mType, other.mTarget.binding(), other.mTarget.textureIndex(), other.mResource); + std::swap(mType, other.mType); + std::swap(mTarget, other.mTarget); + std::swap(mResource, other.mResource); + std::swap(mNumViews, other.mNumViews); + std::swap(mMultiviewLayout, other.mMultiviewLayout); + std::swap(mBaseViewIndex, other.mBaseViewIndex); + std::swap(mViewportOffsets, other.mViewportOffsets); return *this; } FramebufferAttachment::~FramebufferAttachment() { - detach(); + ASSERT(!isAttached()); } -void FramebufferAttachment::detach() +void FramebufferAttachment::detach(const Context *context) { mType = GL_NONE; if (mResource != nullptr) { - mResource->onDetach(); + mResource->onDetach(context); mResource = nullptr; } + mNumViews = kDefaultNumViews; + mMultiviewLayout = kDefaultMultiviewLayout; + mBaseViewIndex = kDefaultBaseViewIndex; + mViewportOffsets = GetDefaultViewportOffsetVector(); // not technically necessary, could omit for performance mTarget = Target(); } -void FramebufferAttachment::attach(GLenum type, +void FramebufferAttachment::attach(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, - FramebufferAttachmentObject *resource) + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets) { + if (resource == nullptr) + { + detach(context); + return; + } + mType = type; mTarget = Target(binding, textureIndex); - - if (resource) + mNumViews = numViews; + mBaseViewIndex = baseViewIndex; + mMultiviewLayout = multiviewLayout; + if (multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE) { - resource->onAttach(); + mViewportOffsets = TransformViewportOffsetArrayToVectorOfOffsets(viewportOffsets, numViews); } + else + { + mViewportOffsets = GetDefaultViewportOffsetVector(); + } + resource->onAttach(context); + if (mResource != nullptr) { - mResource->onDetach(); + mResource->onDetach(context); } + mResource = resource; } GLuint FramebufferAttachment::getRedSize() const { - return GetInternalFormatInfo(getInternalFormat()).redBits; + return getFormat().info->redBits; } GLuint FramebufferAttachment::getGreenSize() const { - return GetInternalFormatInfo(getInternalFormat()).greenBits; + return getFormat().info->greenBits; } GLuint FramebufferAttachment::getBlueSize() const { - return GetInternalFormatInfo(getInternalFormat()).blueBits; + return getFormat().info->blueBits; } GLuint FramebufferAttachment::getAlphaSize() const { - return GetInternalFormatInfo(getInternalFormat()).alphaBits; + return getFormat().info->alphaBits; } GLuint FramebufferAttachment::getDepthSize() const { - return GetInternalFormatInfo(getInternalFormat()).depthBits; + return getFormat().info->depthBits; } GLuint FramebufferAttachment::getStencilSize() const { - return GetInternalFormatInfo(getInternalFormat()).stencilBits; + return getFormat().info->stencilBits; } GLenum FramebufferAttachment::getComponentType() const { - return GetInternalFormatInfo(getInternalFormat()).componentType; + return getFormat().info->componentType; } GLenum FramebufferAttachment::getColorEncoding() const { - return GetInternalFormatInfo(getInternalFormat()).colorEncoding; + return getFormat().info->colorEncoding; } GLuint FramebufferAttachment::id() const @@ -190,6 +258,26 @@ GLint FramebufferAttachment::layer() const return 0; } +GLsizei FramebufferAttachment::getNumViews() const +{ + return mNumViews; +} + +GLenum FramebufferAttachment::getMultiviewLayout() const +{ + return mMultiviewLayout; +} + +GLint FramebufferAttachment::getBaseViewIndex() const +{ + return mBaseViewIndex; +} + +const std::vector &FramebufferAttachment::getMultiviewViewportOffsets() const +{ + return mViewportOffsets; +} + Texture *FramebufferAttachment::getTexture() const { return rx::GetAs(mResource); @@ -205,4 +293,93 @@ const egl::Surface *FramebufferAttachment::getSurface() const return rx::GetAs(mResource); } +FramebufferAttachmentObject *FramebufferAttachment::getResource() const +{ + return mResource; } + +bool FramebufferAttachment::operator==(const FramebufferAttachment &other) const +{ + if (mResource != other.mResource || mType != other.mType || mNumViews != other.mNumViews || + mMultiviewLayout != other.mMultiviewLayout || mBaseViewIndex != other.mBaseViewIndex || + mViewportOffsets != other.mViewportOffsets) + { + return false; + } + + if (mType == GL_TEXTURE && getTextureImageIndex() != other.getTextureImageIndex()) + { + return false; + } + + return true; +} + +bool FramebufferAttachment::operator!=(const FramebufferAttachment &other) const +{ + return !(*this == other); +} + +InitState FramebufferAttachment::initState() const +{ + return mResource ? mResource->initState(mTarget.textureIndex()) : InitState::Initialized; +} + +Error FramebufferAttachment::initializeContents(const Context *context) +{ + ASSERT(mResource); + ANGLE_TRY(mResource->initializeContents(context, mTarget.textureIndex())); + setInitState(InitState::Initialized); + return NoError(); +} + +void FramebufferAttachment::setInitState(InitState initState) const +{ + ASSERT(mResource); + mResource->setInitState(mTarget.textureIndex(), initState); +} + +////// FramebufferAttachmentObject Implementation ////// + +FramebufferAttachmentObject::FramebufferAttachmentObject() +{ +} + +FramebufferAttachmentObject::~FramebufferAttachmentObject() +{ +} + +Error FramebufferAttachmentObject::getAttachmentRenderTarget( + const Context *context, + GLenum binding, + const ImageIndex &imageIndex, + rx::FramebufferAttachmentRenderTarget **rtOut) const +{ + return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut); +} + +OnAttachmentDirtyChannel *FramebufferAttachmentObject::getDirtyChannel() +{ + return &mDirtyChannel; +} + +Error FramebufferAttachmentObject::initializeContents(const Context *context, + const ImageIndex &imageIndex) +{ + ASSERT(context->isRobustResourceInitEnabled()); + + // Because gl::Texture cannot support tracking individual layer dirtiness, we only handle + // initializing entire mip levels for 2D array textures. + if (imageIndex.type == GL_TEXTURE_2D_ARRAY && imageIndex.hasLayer()) + { + ImageIndex fullMipIndex = imageIndex; + fullMipIndex.layerIndex = ImageIndex::ENTIRE_LEVEL; + return getAttachmentImpl()->initializeContents(context, fullMipIndex); + } + else + { + return getAttachmentImpl()->initializeContents(context, imageIndex); + } +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h index 33196f5c61..5c0553a1d4 100644 --- a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h @@ -15,6 +15,7 @@ #include "libANGLE/angletypes.h" #include "libANGLE/Error.h" #include "libANGLE/ImageIndex.h" +#include "libANGLE/signal_utils.h" namespace egl { @@ -38,9 +39,20 @@ class FramebufferAttachmentObjectImpl; namespace gl { class FramebufferAttachmentObject; +struct Format; class Renderbuffer; class Texture; +enum class InitState +{ + MayNeedInit, + Initialized, +}; + +using OnAttachmentDirtyBinding = angle::ChannelBinding; +using OnAttachmentDirtyChannel = angle::BroadcastChannel; +using OnAttachmentDirtyReceiver = angle::SignalReceiver; + // FramebufferAttachment implements a GL framebuffer attachment. // Attachments are "light" containers, which store pointers to ref-counted GL objects. // We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. @@ -52,43 +64,27 @@ class FramebufferAttachment final public: FramebufferAttachment(); - FramebufferAttachment(GLenum type, + FramebufferAttachment(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, FramebufferAttachmentObject *resource); - FramebufferAttachment(const FramebufferAttachment &other); - FramebufferAttachment &operator=(const FramebufferAttachment &other); + FramebufferAttachment(FramebufferAttachment &&other); + FramebufferAttachment &operator=(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, + void detach(const Context *context); + void attach(const Context *context, + GLenum type, GLenum binding, const ImageIndex &textureIndex, - FramebufferAttachmentObject *resource); + FramebufferAttachmentObject *resource, + GLsizei numViews, + GLuint baseViewIndex, + GLenum multiviewLayout, + const GLint *viewportOffsets); // Helper methods GLuint getRedSize() const; @@ -111,12 +107,16 @@ class FramebufferAttachment final GLenum cubeMapFace() const; GLint mipLevel() const; GLint layer() const; + GLsizei getNumViews() const; + GLenum getMultiviewLayout() const; + GLint getBaseViewIndex() const; + const std::vector &getMultiviewViewportOffsets() 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; + const Format &getFormat() const; GLsizei getSamples() const; GLenum type() const { return mType; } bool isAttached() const { return mType != GL_NONE; } @@ -124,95 +124,127 @@ class FramebufferAttachment final Renderbuffer *getRenderbuffer() const; Texture *getTexture() const; const egl::Surface *getSurface() const; + FramebufferAttachmentObject *getResource() const; + InitState initState() const; + Error initializeContents(const Context *context); + void setInitState(InitState initState) const; // "T" must be static_castable from FramebufferAttachmentRenderTarget template - gl::Error getRenderTarget(T **rtOut) const + gl::Error getRenderTarget(const Context *context, 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; + static_assert(std::is_base_of(), + "Invalid RenderTarget class."); + return getRenderTargetImpl( + context, reinterpret_cast(rtOut)); } + bool operator==(const FramebufferAttachment &other) const; + bool operator!=(const FramebufferAttachment &other) const; + + static std::vector GetDefaultViewportOffsetVector(); + static const GLsizei kDefaultNumViews; + static const GLenum kDefaultMultiviewLayout; + static const GLint kDefaultBaseViewIndex; + static const GLint kDefaultViewportOffsets[2]; + private: - gl::Error getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const; + gl::Error getRenderTargetImpl(const Context *context, + rx::FramebufferAttachmentRenderTarget **rtOut) const; + + // 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; + }; GLenum mType; Target mTarget; FramebufferAttachmentObject *mResource; + GLsizei mNumViews; + GLenum mMultiviewLayout; + GLint mBaseViewIndex; + std::vector mViewportOffsets; }; // A base class for objects that FBO Attachments may point to. class FramebufferAttachmentObject { public: - FramebufferAttachmentObject() {} - virtual ~FramebufferAttachmentObject() {} + FramebufferAttachmentObject(); + virtual ~FramebufferAttachmentObject(); - 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 Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0; + virtual const Format &getAttachmentFormat(GLenum binding, + const ImageIndex &imageIndex) const = 0; + virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0; - virtual void onAttach() = 0; - virtual void onDetach() = 0; + virtual void onAttach(const Context *context) = 0; + virtual void onDetach(const Context *context) = 0; virtual GLuint getId() const = 0; - Error getAttachmentRenderTarget(const FramebufferAttachment::Target &target, + // These are used for robust resource initialization. + virtual InitState initState(const ImageIndex &imageIndex) const = 0; + virtual void setInitState(const ImageIndex &imageIndex, InitState initState) = 0; + + Error getAttachmentRenderTarget(const Context *context, + GLenum binding, + const ImageIndex &imageIndex, rx::FramebufferAttachmentRenderTarget **rtOut) const; + Error initializeContents(const Context *context, const ImageIndex &imageIndex); + + OnAttachmentDirtyChannel *getDirtyChannel(); + protected: virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0; + + OnAttachmentDirtyChannel mDirtyChannel; }; inline Extents FramebufferAttachment::getSize() const { - return mResource->getAttachmentSize(mTarget); + ASSERT(mResource); + return mResource->getAttachmentSize(mTarget.textureIndex()); } -inline GLenum FramebufferAttachment::getInternalFormat() const +inline const Format &FramebufferAttachment::getFormat() const { - return mResource->getAttachmentInternalFormat(mTarget); + ASSERT(mResource); + return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex()); } inline GLsizei FramebufferAttachment::getSamples() const { - return mResource->getAttachmentSamples(mTarget); -} - -inline gl::Error FramebufferAttachment::getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const -{ - return mResource->getAttachmentRenderTarget(mTarget, rtOut); + ASSERT(mResource); + return mResource->getAttachmentSamples(mTarget.textureIndex()); } -} // namespace gl - -namespace rx -{ - -class FramebufferAttachmentObjectImpl : angle::NonCopyable -{ - public: - FramebufferAttachmentObjectImpl() {} - virtual ~FramebufferAttachmentObjectImpl() {} - - virtual gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, - FramebufferAttachmentRenderTarget **rtOut) = 0; -}; - -} // namespace rx - -namespace gl -{ - -inline Error FramebufferAttachmentObject::getAttachmentRenderTarget( - const FramebufferAttachment::Target &target, +inline gl::Error FramebufferAttachment::getRenderTargetImpl( + const Context *context, rx::FramebufferAttachmentRenderTarget **rtOut) const { - return getAttachmentImpl()->getAttachmentRenderTarget(target, rtOut); + ASSERT(mResource); + return mResource->getAttachmentRenderTarget(context, mTarget.binding(), mTarget.textureIndex(), + rtOut); } -} +} // namespace gl #endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp index 4815855d5a..c3c184258f 100644 --- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp @@ -49,9 +49,10 @@ GLuint HandleAllocator::allocate() { ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty()); - // Allocate from released list, constant time. + // Allocate from released list, logarithmic time for pop_heap. if (!mReleasedList.empty()) { + std::pop_heap(mReleasedList.begin(), mReleasedList.end()); GLuint reusedHandle = mReleasedList.back(); mReleasedList.pop_back(); return reusedHandle; @@ -63,19 +64,23 @@ GLuint HandleAllocator::allocate() GLuint freeListHandle = listIt->begin; ASSERT(freeListHandle > 0); - listIt->begin++; if (listIt->begin == listIt->end) { mUnallocatedList.erase(listIt); } + else + { + listIt->begin++; + } return freeListHandle; } void HandleAllocator::release(GLuint handle) { - // Add to released list, constant time. + // Add to released list, logarithmic time for push_heap. mReleasedList.push_back(handle); + std::push_heap(mReleasedList.begin(), mReleasedList.end()); } void HandleAllocator::reserve(GLuint handle) @@ -101,7 +106,7 @@ void HandleAllocator::reserve(GLuint handle) if (handle == begin || handle == end) { - if (begin + 1 == end) + if (begin == end) { mUnallocatedList.erase(boundIt); } @@ -117,18 +122,21 @@ void HandleAllocator::reserve(GLuint handle) return; } + ASSERT(begin < handle && handle < end); + // need to split the range auto placementIt = mUnallocatedList.erase(boundIt); + placementIt = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); + mUnallocatedList.insert(placementIt, HandleRange(begin, handle - 1)); +} - if (handle + 1 != end) - { - placementIt = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); - } - if (begin != handle) - { - ASSERT(begin < handle); - mUnallocatedList.insert(placementIt, HandleRange(begin, handle)); - } +void HandleAllocator::reset() +{ + mUnallocatedList.clear(); + mUnallocatedList.push_back(HandleRange(1, std::numeric_limits::max())); + mReleasedList.clear(); + mBaseValue = 1; + mNextValue = 1; } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h index 1888d57cfa..cd21d687f4 100644 --- a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h @@ -14,8 +14,6 @@ #include "angle_gl.h" -#include - namespace gl { @@ -24,7 +22,7 @@ class HandleAllocator final : angle::NonCopyable public: // Maximum handle = MAX_UINT-1 HandleAllocator(); - // Specify maximum handle value + // Specify maximum handle value. Used for testing. HandleAllocator(GLuint maximumHandleValue); ~HandleAllocator(); @@ -34,6 +32,7 @@ class HandleAllocator final : angle::NonCopyable GLuint allocate(); void release(GLuint handle); void reserve(GLuint handle); + void reset(); private: GLuint mBaseValue; @@ -41,6 +40,7 @@ class HandleAllocator final : angle::NonCopyable typedef std::vector HandleList; HandleList mFreeValues; + // Represents an inclusive range [begin, end] struct HandleRange { HandleRange(GLuint beginIn, GLuint endIn) : begin(beginIn), end(endIn) {} @@ -53,7 +53,7 @@ class HandleAllocator final : angle::NonCopyable // The freelist consists of never-allocated handles, stored // as ranges, and handles that were previously allocated and - // released, stored in a stack. + // released, stored in a heap. std::vector mUnallocatedList; std::vector mReleasedList; }; diff --git a/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp new file mode 100644 index 0000000000..2a97ce939f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.cpp @@ -0,0 +1,229 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleRangeAllocator.cpp : Implementation for HandleRangeAllocator.h + +#include "libANGLE/HandleRangeAllocator.h" + +#include +#include +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace gl +{ + +const GLuint HandleRangeAllocator::kInvalidHandle = 0; + +HandleRangeAllocator::HandleRangeAllocator() +{ + // Simplify the code by making sure that lower_bound(id) never + // returns the beginning of the map, if id is valid (eg != kInvalidHandle). + mUsed.insert(std::make_pair(0u, 0u)); +} + +HandleRangeAllocator::~HandleRangeAllocator() +{ +} + +GLuint HandleRangeAllocator::allocate() +{ + return allocateRange(1u); +} + +GLuint HandleRangeAllocator::allocateAtOrAbove(GLuint wanted) +{ + if (wanted == 0u || wanted == 1u) + return allocateRange(1u); + + auto current = mUsed.lower_bound(wanted); + auto next = current; + if (current == mUsed.end() || current->first > wanted) + { + current--; + } + else + { + next++; + } + + GLuint firstId = current->first; + GLuint lastId = current->second; + ASSERT(wanted >= firstId); + + if (wanted - 1u <= lastId) + { + // Append to current range. + lastId++; + if (lastId == 0) + { + // The increment overflowed. + return allocateRange(1u); + } + + current->second = lastId; + + if (next != mUsed.end() && next->first - 1u == lastId) + { + // Merge with next range. + current->second = next->second; + mUsed.erase(next); + } + return lastId; + } + else if (next != mUsed.end() && next->first - 1u == wanted) + { + // Prepend to next range. + GLuint lastExisting = next->second; + mUsed.erase(next); + mUsed.insert(std::make_pair(wanted, lastExisting)); + return wanted; + } + mUsed.insert(std::make_pair(wanted, wanted)); + return wanted; +} + +GLuint HandleRangeAllocator::allocateRange(GLuint range) +{ + ASSERT(range != 0); + + auto current = mUsed.begin(); + auto next = current; + + while (++next != mUsed.end()) + { + if (next->first - current->second > range) + break; + current = next; + } + const GLuint firstId = current->second + 1u; + const GLuint lastId = firstId + range - 1u; + + // deal with wraparound + if (firstId == 0u || lastId < firstId) + return kInvalidHandle; + + current->second = lastId; + + if (next != mUsed.end() && next->first - 1u == lastId) + { + // merge with next range + current->second = next->second; + mUsed.erase(next); + } + return firstId; +} + +bool HandleRangeAllocator::markAsUsed(GLuint handle) +{ + ASSERT(handle); + auto current = mUsed.lower_bound(handle); + if (current != mUsed.end() && current->first == handle) + return false; + + auto next = current; + --current; + + if (current->second >= handle) + return false; + + ASSERT(current->first < handle && current->second < handle); + + if (current->second + 1u == handle) + { + // Append to current range. + current->second = handle; + if (next != mUsed.end() && next->first - 1u == handle) + { + // Merge with next range. + current->second = next->second; + mUsed.erase(next); + } + return true; + } + else if (next != mUsed.end() && next->first - 1u == handle) + { + // Prepend to next range. + GLuint lastExisting = next->second; + mUsed.erase(next); + mUsed.insert(std::make_pair(handle, lastExisting)); + return true; + } + + mUsed.insert(std::make_pair(handle, handle)); + return true; +} + +void HandleRangeAllocator::release(GLuint handle) +{ + releaseRange(handle, 1u); +} + +void HandleRangeAllocator::releaseRange(GLuint first, GLuint range) +{ + if (range == 0u || (first == 0u && range == 1u)) + return; + + if (first == 0u) + { + first++; + range--; + } + + GLuint last = first + range - 1u; + if (last < first) + last = std::numeric_limits::max(); + + while (true) + { + auto current = mUsed.lower_bound(last); + if (current == mUsed.end() || current->first > last) + --current; + + if (current->second < first) + return; + + if (current->first >= first) + { + const GLuint lastExisting = current->second; + mUsed.erase(current); + if (last < lastExisting) + { + mUsed.insert(std::make_pair(last + 1u, lastExisting)); + } + } + else if (current->second <= last) + { + current->second = first - 1u; + } + else + { + ASSERT(current->first < first && current->second > last); + const GLuint lastExisting = current->second; + current->second = first - 1u; + mUsed.insert(std::make_pair(last + 1u, lastExisting)); + } + } +} + +bool HandleRangeAllocator::isUsed(GLuint handle) const +{ + if (handle == kInvalidHandle) + return false; + + auto current = mUsed.lower_bound(handle); + if (current != mUsed.end()) + { + if (current->first == handle) + return true; + } + --current; + return current->second >= handle; +} + +} // namespace gl \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h new file mode 100644 index 0000000000..4d4b6f4f69 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleRangeAllocator.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleRangeAllocator.h: Defines the gl::HandleRangeAllocator class, which is used to +// allocate contiguous ranges of GL path handles. + +#ifndef LIBANGLE_HANDLERANGEALLOCATOR_H_ +#define LIBANGLE_HANDLERANGEALLOCATOR_H_ + +#include + +#include "angle_gl.h" +#include "common/angleutils.h" + +namespace gl +{ + +// Allocates contiguous ranges of path object handles. +class HandleRangeAllocator final : angle::NonCopyable +{ + public: + static const GLuint kInvalidHandle; + + HandleRangeAllocator(); + ~HandleRangeAllocator(); + + // Allocates a new path handle. + GLuint allocate(); + + // Allocates a handle starting at or above the value of |wanted|. + // Note: may wrap if it starts near limit. + GLuint allocateAtOrAbove(GLuint wanted); + + // Allocates |range| amount of contiguous paths. + // Returns the first id to |first_id| or |kInvalidHandle| if + // allocation failed. + GLuint allocateRange(GLuint range); + + // Marks an id as used. Returns false if handle was already used. + bool markAsUsed(GLuint handle); + + // Release handle. + void release(GLuint handle); + + // Release a |range| amount of contiguous handles, starting from |first| + void releaseRange(GLuint first, GLuint range); + + // Checks whether or not a resource ID is in use. + bool isUsed(GLuint handle) const; + + private: + std::map mUsed; +}; + +} // namespace gl + +#endif // LIBANGLE_HANDLERANGEALLOCATOR_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/Image.cpp b/src/3rdparty/angle/src/libANGLE/Image.cpp index a9448e3f6c..04c757c2c4 100644 --- a/src/3rdparty/angle/src/libANGLE/Image.cpp +++ b/src/3rdparty/angle/src/libANGLE/Image.cpp @@ -11,13 +11,42 @@ #include "common/debug.h" #include "common/utilities.h" #include "libANGLE/angletypes.h" +#include "libANGLE/formatutils.h" #include "libANGLE/Texture.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/renderer/EGLImplFactory.h" #include "libANGLE/renderer/ImageImpl.h" namespace egl { -ImageSibling::ImageSibling(GLuint id) : RefCountObject(id), mSourcesOf(), mTargetOf() + +namespace +{ +gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs) +{ + if (eglTarget == EGL_GL_RENDERBUFFER) + { + return gl::ImageIndex::MakeInvalid(); + } + + GLenum target = egl_gl::EGLImageTargetToGLTextureTarget(eglTarget); + GLint mip = static_cast(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0)); + GLint layer = static_cast(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0)); + + if (target == GL_TEXTURE_3D) + { + return gl::ImageIndex::Make3D(mip, layer); + } + else + { + ASSERT(layer == 0); + return gl::ImageIndex::MakeGeneric(target, mip); + } +} +} // anonymous namespace + +ImageSibling::ImageSibling(GLuint id) + : RefCountObject(id), FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() { } @@ -25,46 +54,38 @@ 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. + // Child class should orphan images before destruction. ASSERT(mSourcesOf.empty()); - orphanImages(); + ASSERT(mTargetOf.get() == nullptr); } -void ImageSibling::setTargetImage(egl::Image *imageTarget) +void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget) { ASSERT(imageTarget != nullptr); - mTargetOf.set(imageTarget); + mTargetOf.set(context, imageTarget); imageTarget->addTargetSibling(this); } -gl::Error ImageSibling::orphanImages() +gl::Error ImageSibling::orphanImages(const gl::Context *context) { 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); + ANGLE_TRY(mTargetOf->orphanSibling(context, this)); + mTargetOf.set(context, nullptr); } else { - for (auto &sourceImage : mSourcesOf) + for (egl::Image *sourceImage : mSourcesOf) { - gl::Error error = sourceImage->orphanSibling(this); - if (error.isError()) - { - return error; - } + ANGLE_TRY(sourceImage->orphanSibling(context, this)); } mSourcesOf.clear(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void ImageSibling::addImageSource(egl::Image *imageSource) @@ -79,114 +100,146 @@ void ImageSibling::removeImageSource(egl::Image *imageSource) mSourcesOf.erase(imageSource); } -Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) +bool ImageSibling::isEGLImageTarget() const +{ + return (mTargetOf.get() != nullptr); +} + +gl::InitState ImageSibling::sourceEGLImageInitState() const +{ + ASSERT(isEGLImageTarget()); + return mTargetOf->sourceInitState(); +} + +void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const +{ + ASSERT(isEGLImageTarget()); + mTargetOf->setInitState(initState); +} + +ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) + : imageIndex(GetImageIndex(target, attribs)), source(buffer), targets() +{ +} + +ImageState::~ImageState() +{ +} + +Image::Image(rx::EGLImplFactory *factory, + EGLenum target, + ImageSibling *buffer, + const AttributeMap &attribs) : RefCountObject(0), - mImplementation(impl), - mInternalFormat(GL_NONE), - mWidth(0), - mHeight(0), - mSamples(0), - mSource(), - mTargets() + mState(target, buffer, attribs), + mImplementation(factory->createImage(mState, target, attribs)), + mOrphanedAndNeedsInit(false) { 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(); - } + mState.source->addImageSource(this); } -Image::~Image() +gl::Error Image::onDestroy(const gl::Context *context) { - 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()); + ASSERT(mState.targets.empty()); // Tell the source that it is no longer used by this image - if (mSource.get() != nullptr) + if (mState.source.get() != nullptr) { - mSource->removeImageSource(this); - mSource.set(nullptr); + mState.source->removeImageSource(this); + mState.source.set(context, nullptr); } + return gl::NoError(); +} + +Image::~Image() +{ + SafeDelete(mImplementation); } void Image::addTargetSibling(ImageSibling *sibling) { - mTargets.insert(sibling); + mState.targets.insert(sibling); } -gl::Error Image::orphanSibling(ImageSibling *sibling) +gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling) { // notify impl - gl::Error error = mImplementation->orphan(sibling); + ANGLE_TRY(mImplementation->orphan(context, sibling)); - if (mSource.get() == sibling) + if (mState.source.get() == sibling) { // If the sibling is the source, it cannot be a target. - ASSERT(mTargets.find(sibling) == mTargets.end()); - - mSource.set(nullptr); + ASSERT(mState.targets.find(sibling) == mState.targets.end()); + mState.source.set(context, nullptr); + mOrphanedAndNeedsInit = + (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit); } else { - mTargets.erase(sibling); + mState.targets.erase(sibling); } - return error; + return gl::NoError(); } -GLenum Image::getInternalFormat() const +const gl::Format &Image::getFormat() const { - return mInternalFormat; + return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex); } size_t Image::getWidth() const { - return mWidth; + return mState.source->getAttachmentSize(mState.imageIndex).width; } size_t Image::getHeight() const { - return mHeight; + return mState.source->getAttachmentSize(mState.imageIndex).height; } size_t Image::getSamples() const { - return mSamples; + return mState.source->getAttachmentSamples(mState.imageIndex); } -rx::ImageImpl *Image::getImplementation() +rx::ImageImpl *Image::getImplementation() const { return mImplementation; } -const rx::ImageImpl *Image::getImplementation() const +Error Image::initialize() { - return mImplementation; + return mImplementation->initialize(); +} + +bool Image::orphaned() const +{ + return (mState.source.get() == nullptr); +} + +gl::InitState Image::sourceInitState() const +{ + if (orphaned()) + { + return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized; + } + + return mState.source->initState(mState.imageIndex); } + +void Image::setInitState(gl::InitState initState) +{ + if (orphaned()) + { + mOrphanedAndNeedsInit = false; + } + + return mState.source->setInitState(mState.imageIndex, initState); } + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Image.h b/src/3rdparty/angle/src/libANGLE/Image.h index 26c9df914c..d2f1b875c6 100644 --- a/src/3rdparty/angle/src/libANGLE/Image.h +++ b/src/3rdparty/angle/src/libANGLE/Image.h @@ -12,12 +12,15 @@ #include "common/angleutils.h" #include "libANGLE/AttributeMap.h" #include "libANGLE/Error.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/formatutils.h" #include namespace rx { +class EGLImplFactory; class ImageImpl; } @@ -25,18 +28,25 @@ namespace egl { class Image; -class ImageSibling : public RefCountObject +// Only currently Renderbuffers and Textures can be bound with images. This makes the relationship +// explicit, and also ensures that an image sibling can determine if it's been initialized or not, +// which is important for the robust resource init extension with Textures and EGLImages. +class ImageSibling : public gl::RefCountObject, public gl::FramebufferAttachmentObject { public: ImageSibling(GLuint id); - virtual ~ImageSibling(); + ~ImageSibling() override; + + bool isEGLImageTarget() const; + gl::InitState sourceEGLImageInitState() const; + void setSourceEGLImageInitState(gl::InitState initState) const; protected: // Set the image target of this sibling - void setTargetImage(egl::Image *imageTarget); + void setTargetImage(const gl::Context *context, egl::Image *imageTarget); // Orphan all EGL image sources and targets - gl::Error orphanImages(); + gl::Error orphanImages(const gl::Context *context); private: friend class Image; @@ -48,22 +58,42 @@ class ImageSibling : public RefCountObject void removeImageSource(egl::Image *imageSource); std::set mSourcesOf; - BindingPointer mTargetOf; + gl::BindingPointer mTargetOf; +}; + +struct ImageState : private angle::NonCopyable +{ + ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs); + ~ImageState(); + + gl::ImageIndex imageIndex; + gl::BindingPointer source; + std::set targets; }; -class Image final : public RefCountObject +class Image final : public gl::RefCountObject { public: - Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs); - ~Image(); + Image(rx::EGLImplFactory *factory, + EGLenum target, + ImageSibling *buffer, + const AttributeMap &attribs); + + gl::Error onDestroy(const gl::Context *context) override; + ~Image() override; - GLenum getInternalFormat() const; + const gl::Format &getFormat() const; size_t getWidth() const; size_t getHeight() const; size_t getSamples() const; - rx::ImageImpl *getImplementation(); - const rx::ImageImpl *getImplementation() const; + Error initialize(); + + rx::ImageImpl *getImplementation() const; + + bool orphaned() const; + gl::InitState sourceInitState() const; + void setInitState(gl::InitState initState); private: friend class ImageSibling; @@ -74,18 +104,12 @@ class Image final : public RefCountObject // 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); + gl::Error orphanSibling(const gl::Context *context, ImageSibling *sibling); + ImageState mState; rx::ImageImpl *mImplementation; - - GLenum mInternalFormat; - size_t mWidth; - size_t mHeight; - size_t mSamples; - - BindingPointer mSource; - std::set mTargets; + bool mOrphanedAndNeedsInit; }; -} +} // namespace egl #endif // LIBANGLE_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp index c84e7c5d65..6f99f8ab54 100644 --- a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp @@ -1,3 +1,4 @@ +#include "ImageIndex.h" // // Copyright 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -16,7 +17,8 @@ namespace gl ImageIndex::ImageIndex(const ImageIndex &other) : type(other.type), mipIndex(other.mipIndex), - layerIndex(other.layerIndex) + layerIndex(other.layerIndex), + numLayers(other.numLayers) {} ImageIndex &ImageIndex::operator=(const ImageIndex &other) @@ -24,29 +26,45 @@ ImageIndex &ImageIndex::operator=(const ImageIndex &other) type = other.type; mipIndex = other.mipIndex; layerIndex = other.layerIndex; + numLayers = other.numLayers; return *this; } +bool ImageIndex::is3D() const +{ + return type == GL_TEXTURE_3D || type == GL_TEXTURE_2D_ARRAY; +} + ImageIndex ImageIndex::Make2D(GLint mipIndex) { - return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); + return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL, 1); +} + +ImageIndex ImageIndex::MakeRectangle(GLint mipIndex) +{ + return ImageIndex(GL_TEXTURE_RECTANGLE_ANGLE, mipIndex, ENTIRE_LEVEL, 1); } ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) { ASSERT(gl::IsCubeMapTextureTarget(target)); return ImageIndex(target, mipIndex, - static_cast(CubeMapTextureTargetToLayerIndex(target))); + static_cast(CubeMapTextureTargetToLayerIndex(target)), 1); } ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex) { - return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex, 1); +} + +ImageIndex ImageIndex::Make2DArrayRange(GLint mipIndex, GLint layerIndex, GLint numLayers) +{ + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex, numLayers); } ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) { - return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); + return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex, 1); } ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) @@ -54,12 +72,17 @@ ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) GLint layerIndex = IsCubeMapTextureTarget(target) ? static_cast(CubeMapTextureTargetToLayerIndex(target)) : ENTIRE_LEVEL; - return ImageIndex(target, mipIndex, layerIndex); + return ImageIndex(target, mipIndex, layerIndex, 1); +} + +ImageIndex ImageIndex::Make2DMultisample() +{ + return ImageIndex(GL_TEXTURE_2D_MULTISAMPLE, 0, ENTIRE_LEVEL, 1); } ImageIndex ImageIndex::MakeInvalid() { - return ImageIndex(GL_NONE, -1, -1); + return ImageIndex(GL_NONE, -1, -1, -1); } bool ImageIndex::operator<(const ImageIndex &other) const @@ -72,33 +95,58 @@ bool ImageIndex::operator<(const ImageIndex &other) const { return mipIndex < other.mipIndex; } - else + else if (layerIndex != other.layerIndex) { return layerIndex < other.layerIndex; } + else + { + return numLayers < other.numLayers; + } +} + +bool ImageIndex::operator==(const ImageIndex &other) const +{ + return (type == other.type) && (mipIndex == other.mipIndex) && + (layerIndex == other.layerIndex) && (numLayers == other.numLayers); } -ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) - : type(typeIn), - mipIndex(mipIndexIn), - layerIndex(layerIndexIn) +bool ImageIndex::operator!=(const ImageIndex &other) const +{ + return !(*this == other); +} + +ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn, GLint numLayersIn) + : type(typeIn), mipIndex(mipIndexIn), layerIndex(layerIndexIn), numLayers(numLayersIn) {} +ImageIndexIterator::ImageIndexIterator(const ImageIndexIterator &other) = default; + ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) { return ImageIndexIterator(GL_TEXTURE_2D, Range(minMip, maxMip), - Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); +} + +ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_RECTANGLE_ANGLE, Range(minMip, maxMip), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); } ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) { - return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), NULL); + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), + nullptr); } ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer) { - return ImageIndexIterator(GL_TEXTURE_3D, Range(minMip, maxMip), Range(minLayer, maxLayer), NULL); + return ImageIndexIterator(GL_TEXTURE_3D, Range(minMip, maxMip), + Range(minLayer, maxLayer), nullptr); } ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, @@ -108,19 +156,33 @@ ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); } -ImageIndexIterator::ImageIndexIterator(GLenum type, const Range &mipRange, - const Range &layerRange, const GLsizei *layerCounts) +ImageIndexIterator ImageIndexIterator::Make2DMultisample() +{ + return ImageIndexIterator(GL_TEXTURE_2D_MULTISAMPLE, Range(0, 0), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); +} + +ImageIndexIterator::ImageIndexIterator(GLenum type, + const Range &mipRange, + const Range &layerRange, + const GLsizei *layerCounts) : mType(type), mMipRange(mipRange), mLayerRange(layerRange), mLayerCounts(layerCounts), - mCurrentMip(mipRange.start), - mCurrentLayer(layerRange.start) + mCurrentMip(mipRange.low()), + mCurrentLayer(layerRange.low()) {} GLint ImageIndexIterator::maxLayer() const { - return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); + if (mLayerCounts) + { + ASSERT(mCurrentMip >= 0); + return (mCurrentMip < mMipRange.high()) ? mLayerCounts[mCurrentMip] : 0; + } + return mLayerRange.high(); } ImageIndex ImageIndexIterator::next() @@ -134,20 +196,28 @@ ImageIndex ImageIndexIterator::next() if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) { - if (mCurrentLayer < maxLayer()-1) + if (mCurrentLayer < maxLayer() - 1) { mCurrentLayer++; } - else if (mCurrentMip < mMipRange.end-1) + else if (mCurrentMip < mMipRange.high() - 1) { mCurrentMip++; - mCurrentLayer = mLayerRange.start; + mCurrentLayer = mLayerRange.low(); + } + else + { + done(); } } - else if (mCurrentMip < mMipRange.end-1) + else if (mCurrentMip < mMipRange.high() - 1) { mCurrentMip++; - mCurrentLayer = mLayerRange.start; + mCurrentLayer = mLayerRange.low(); + } + else + { + done(); } return value; @@ -155,7 +225,7 @@ ImageIndex ImageIndexIterator::next() ImageIndex ImageIndexIterator::current() const { - ImageIndex value(mType, mCurrentMip, mCurrentLayer); + ImageIndex value(mType, mCurrentMip, mCurrentLayer, 1); if (mType == GL_TEXTURE_CUBE_MAP) { @@ -167,7 +237,13 @@ ImageIndex ImageIndexIterator::current() const bool ImageIndexIterator::hasNext() const { - return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); + return (mCurrentMip < mMipRange.high() || mCurrentLayer < maxLayer()); } +void ImageIndexIterator::done() +{ + mCurrentMip = mMipRange.high(); + mCurrentLayer = maxLayer(); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.h b/src/3rdparty/angle/src/libANGLE/ImageIndex.h index b527c7c8ab..8e1b010325 100644 --- a/src/3rdparty/angle/src/libANGLE/ImageIndex.h +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.h @@ -23,37 +23,48 @@ struct ImageIndex GLenum type; GLint mipIndex; GLint layerIndex; + GLint numLayers; ImageIndex(const ImageIndex &other); ImageIndex &operator=(const ImageIndex &other); bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } + bool is3D() const; static ImageIndex Make2D(GLint mipIndex); + static ImageIndex MakeRectangle(GLint mipIndex); static ImageIndex MakeCube(GLenum target, GLint mipIndex); static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); + static ImageIndex Make2DArrayRange(GLint mipIndex, GLint layerIndex, GLint numLayers); static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); static ImageIndex MakeGeneric(GLenum target, GLint mipIndex); + static ImageIndex Make2DMultisample(); static ImageIndex MakeInvalid(); static const GLint ENTIRE_LEVEL = static_cast(-1); bool operator<(const ImageIndex &other) const; + bool operator==(const ImageIndex &other) const; + bool operator!=(const ImageIndex &other) const; private: friend class ImageIndexIterator; - ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); + ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn, GLint numLayersIn); }; class ImageIndexIterator { public: + ImageIndexIterator(const ImageIndexIterator &other); + static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeRectangle(GLint minMip, GLint maxMip); static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); + static ImageIndexIterator Make2DMultisample(); ImageIndex next(); ImageIndex current() const; @@ -65,6 +76,7 @@ class ImageIndexIterator const Range &layerRange, const GLsizei *layerCounts); GLint maxLayer() const; + void done(); GLenum mType; Range mMipRange; diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp index 4f165c1b28..71a1392b1b 100644 --- a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.cpp @@ -15,6 +15,14 @@ namespace gl { +IndexRangeCache::IndexRangeCache() +{ +} + +IndexRangeCache::~IndexRangeCache() +{ +} + void IndexRangeCache::addRange(GLenum type, size_t offset, size_t count, diff --git a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h index 69de421c13..3b183448e6 100644 --- a/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h +++ b/src/3rdparty/angle/src/libANGLE/IndexRangeCache.h @@ -23,6 +23,9 @@ namespace gl class IndexRangeCache { public: + IndexRangeCache(); + ~IndexRangeCache(); + void addRange(GLenum type, size_t offset, size_t count, diff --git a/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp new file mode 100644 index 0000000000..799399e453 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.cpp @@ -0,0 +1,44 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// LoggingAnnotator.cpp: DebugAnnotator implementing logging +// + +#include "libANGLE/LoggingAnnotator.h" + +#include + +namespace angle +{ + +bool LoggingAnnotator::getStatus() +{ + return false; +} + +void LoggingAnnotator::logMessage(const gl::LogMessage &msg) const +{ + auto *plat = ANGLEPlatformCurrent(); + if (plat != nullptr) + { + switch (msg.getSeverity()) + { + case gl::LOG_ERR: + plat->logError(plat, msg.getMessage().c_str()); + break; + case gl::LOG_WARN: + plat->logWarning(plat, msg.getMessage().c_str()); + break; + default: + UNREACHABLE(); + } + } + else + { + gl::Trace(msg.getSeverity(), msg.getMessage().c_str()); + } +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h new file mode 100644 index 0000000000..5bec68e189 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/LoggingAnnotator.h @@ -0,0 +1,31 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// LoggingAnnotator.h: DebugAnnotator implementing logging +// + +#ifndef LIBANGLE_LOGGINGANNOTATOR_H_ +#define LIBANGLE_LOGGINGANNOTATOR_H_ + +#include "common/debug.h" + +namespace angle +{ + +class LoggingAnnotator : public gl::DebugAnnotator +{ + public: + LoggingAnnotator(){}; + ~LoggingAnnotator() override{}; + void beginEvent(const wchar_t *eventName) override {} + void endEvent() override {} + void setMarker(const wchar_t *markerName) override {} + bool getStatus() override; + void logMessage(const gl::LogMessage &msg) const override; +}; + +} // namespace angle + +#endif // LIBANGLE_LOGGINGANNOTATOR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp new file mode 100644 index 0000000000..9eec12e3ea --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp @@ -0,0 +1,772 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// MemoryProgramCache: Stores compiled and linked programs in memory so they don't +// always have to be re-compiled. Can be used in conjunction with the platform +// layer to warm up the cache from disk. + +#include "libANGLE/MemoryProgramCache.h" + +#include +#include + +#include "common/utilities.h" +#include "common/version.h" +#include "libANGLE/BinaryStream.h" +#include "libANGLE/Context.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/histogram_macros.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "platform/Platform.h" + +namespace gl +{ + +namespace +{ +enum CacheResult +{ + kCacheMiss, + kCacheHitMemory, + kCacheHitDisk, + kCacheResultMax, +}; + +constexpr unsigned int kWarningLimit = 3; + +void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var) +{ + stream->writeInt(var.type); + stream->writeInt(var.precision); + stream->writeString(var.name); + stream->writeString(var.mappedName); + stream->writeIntVector(var.arraySizes); + stream->writeInt(var.staticUse); + stream->writeString(var.structName); + ASSERT(var.fields.empty()); +} + +void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var) +{ + var->type = stream->readInt(); + var->precision = stream->readInt(); + var->name = stream->readString(); + var->mappedName = stream->readString(); + stream->readIntVector(&var->arraySizes); + var->staticUse = stream->readBool(); + var->structName = stream->readString(); +} + +void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var) +{ + stream->writeInt(var.binding); + stream->writeInt(var.dataSize); + + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); + + stream->writeInt(var.memberIndexes.size()); + for (unsigned int memberCounterIndex : var.memberIndexes) + { + stream->writeInt(memberCounterIndex); + } +} + +void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var) +{ + var->binding = stream->readInt(); + var->dataSize = stream->readInt(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = stream->readBool(); + + unsigned int numMembers = stream->readInt(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + var->memberIndexes.push_back(stream->readInt()); + } +} + +void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var) +{ + WriteShaderVar(stream, var); + + stream->writeInt(var.bufferIndex); + stream->writeInt(var.blockInfo.offset); + stream->writeInt(var.blockInfo.arrayStride); + stream->writeInt(var.blockInfo.matrixStride); + stream->writeInt(var.blockInfo.isRowMajorMatrix); + stream->writeInt(var.blockInfo.topLevelArrayStride); + stream->writeInt(var.topLevelArraySize); + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); +} + +void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var) +{ + LoadShaderVar(stream, var); + + var->bufferIndex = stream->readInt(); + var->blockInfo.offset = stream->readInt(); + var->blockInfo.arrayStride = stream->readInt(); + var->blockInfo.matrixStride = stream->readInt(); + var->blockInfo.isRowMajorMatrix = stream->readBool(); + var->blockInfo.topLevelArrayStride = stream->readInt(); + var->topLevelArraySize = stream->readInt(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = stream->readBool(); +} + +void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block) +{ + stream->writeString(block.name); + stream->writeString(block.mappedName); + stream->writeInt(block.isArray); + stream->writeInt(block.arrayElement); + + WriteShaderVariableBuffer(stream, block); +} + +void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block) +{ + block->name = stream->readString(); + block->mappedName = stream->readString(); + block->isArray = stream->readBool(); + block->arrayElement = stream->readInt(); + + LoadShaderVariableBuffer(stream, block); +} + +class HashStream final : angle::NonCopyable +{ + public: + std::string str() { return mStringStream.str(); } + + template + HashStream &operator<<(T value) + { + mStringStream << value << kSeparator; + return *this; + } + + private: + static constexpr char kSeparator = ':'; + std::ostringstream mStringStream; +}; + +HashStream &operator<<(HashStream &stream, const Shader *shader) +{ + if (shader) + { + stream << shader->getSourceString().c_str() << shader->getSourceString().length() + << shader->getCompilerResourcesString().c_str(); + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const Program::Bindings &bindings) +{ + for (const auto &binding : bindings) + { + stream << binding.first << binding.second; + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const std::vector &strings) +{ + for (const auto &str : strings) + { + stream << str; + } + return stream; +} + +} // anonymous namespace + +MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes) + : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0) +{ +} + +MemoryProgramCache::~MemoryProgramCache() +{ +} + +// static +LinkResult MemoryProgramCache::Deserialize(const Context *context, + const Program *program, + ProgramState *state, + const uint8_t *binary, + size_t length, + InfoLog &infoLog) +{ + BinaryInputStream stream(binary, length); + + unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; + stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); + if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != + 0) + { + infoLog << "Invalid program binary version."; + return false; + } + + int majorVersion = stream.readInt(); + int minorVersion = stream.readInt(); + if (majorVersion != context->getClientMajorVersion() || + minorVersion != context->getClientMinorVersion()) + { + infoLog << "Cannot load program binaries across different ES context versions."; + return false; + } + + state->mComputeShaderLocalSize[0] = stream.readInt(); + state->mComputeShaderLocalSize[1] = stream.readInt(); + state->mComputeShaderLocalSize[2] = stream.readInt(); + + state->mNumViews = stream.readInt(); + + static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, + "Too many vertex attribs for mask"); + state->mActiveAttribLocationsMask = stream.readInt(); + + unsigned int attribCount = stream.readInt(); + ASSERT(state->mAttributes.empty()); + for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex) + { + sh::Attribute attrib; + LoadShaderVar(&stream, &attrib); + attrib.location = stream.readInt(); + state->mAttributes.push_back(attrib); + } + + unsigned int uniformCount = stream.readInt(); + ASSERT(state->mUniforms.empty()); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) + { + LinkedUniform uniform; + LoadShaderVar(&stream, &uniform); + + uniform.bufferIndex = stream.readInt(); + uniform.blockInfo.offset = stream.readInt(); + uniform.blockInfo.arrayStride = stream.readInt(); + uniform.blockInfo.matrixStride = stream.readInt(); + uniform.blockInfo.isRowMajorMatrix = stream.readBool(); + + uniform.typeInfo = &GetUniformTypeInfo(uniform.type); + + state->mUniforms.push_back(uniform); + } + + const unsigned int uniformIndexCount = stream.readInt(); + ASSERT(state->mUniformLocations.empty()); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; + uniformIndexIndex++) + { + VariableLocation variable; + stream.readInt(&variable.arrayIndex); + stream.readInt(&variable.index); + stream.readBool(&variable.ignored); + + state->mUniformLocations.push_back(variable); + } + + unsigned int uniformBlockCount = stream.readInt(); + ASSERT(state->mUniformBlocks.empty()); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; + ++uniformBlockIndex) + { + InterfaceBlock uniformBlock; + LoadInterfaceBlock(&stream, &uniformBlock); + state->mUniformBlocks.push_back(uniformBlock); + + state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0); + } + + unsigned int bufferVariableCount = stream.readInt(); + ASSERT(state->mBufferVariables.empty()); + for (unsigned int index = 0; index < bufferVariableCount; ++index) + { + BufferVariable bufferVariable; + LoadBufferVariable(&stream, &bufferVariable); + state->mBufferVariables.push_back(bufferVariable); + } + + unsigned int shaderStorageBlockCount = stream.readInt(); + ASSERT(state->mShaderStorageBlocks.empty()); + for (unsigned int shaderStorageBlockIndex = 0; + shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex) + { + InterfaceBlock shaderStorageBlock; + LoadInterfaceBlock(&stream, &shaderStorageBlock); + state->mShaderStorageBlocks.push_back(shaderStorageBlock); + } + + unsigned int atomicCounterBufferCount = stream.readInt(); + ASSERT(state->mAtomicCounterBuffers.empty()); + for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex) + { + AtomicCounterBuffer atomicCounterBuffer; + LoadShaderVariableBuffer(&stream, &atomicCounterBuffer); + + state->mAtomicCounterBuffers.push_back(atomicCounterBuffer); + } + + unsigned int transformFeedbackVaryingCount = stream.readInt(); + + // Reject programs that use transform feedback varyings if the hardware cannot support them. + if (transformFeedbackVaryingCount > 0 && + context->getWorkarounds().disableProgramCachingForTransformFeedback) + { + infoLog << "Current driver does not support transform feedback in binary programs."; + return false; + } + + ASSERT(state->mLinkedTransformFeedbackVaryings.empty()); + for (unsigned int transformFeedbackVaryingIndex = 0; + transformFeedbackVaryingIndex < transformFeedbackVaryingCount; + ++transformFeedbackVaryingIndex) + { + sh::Varying varying; + stream.readIntVector(&varying.arraySizes); + stream.readInt(&varying.type); + stream.readString(&varying.name); + + GLuint arrayIndex = stream.readInt(); + + state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex); + } + + stream.readInt(&state->mTransformFeedbackBufferMode); + + unsigned int outputCount = stream.readInt(); + ASSERT(state->mOutputVariables.empty()); + for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex) + { + sh::OutputVariable output; + LoadShaderVar(&stream, &output); + output.location = stream.readInt(); + state->mOutputVariables.push_back(output); + } + + unsigned int outputVarCount = stream.readInt(); + ASSERT(state->mOutputLocations.empty()); + for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) + { + VariableLocation locationData; + stream.readInt(&locationData.arrayIndex); + stream.readInt(&locationData.index); + stream.readBool(&locationData.ignored); + state->mOutputLocations.push_back(locationData); + } + + unsigned int outputTypeCount = stream.readInt(); + for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex) + { + state->mOutputVariableTypes.push_back(stream.readInt()); + } + static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + state->mActiveOutputVariables = stream.readInt(); + + unsigned int samplerRangeLow = stream.readInt(); + unsigned int samplerRangeHigh = stream.readInt(); + state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh); + unsigned int samplerCount = stream.readInt(); + for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex) + { + GLenum textureType = stream.readInt(); + size_t bindingCount = stream.readInt(); + bool unreferenced = stream.readBool(); + state->mSamplerBindings.emplace_back( + SamplerBinding(textureType, bindingCount, unreferenced)); + } + + unsigned int imageRangeLow = stream.readInt(); + unsigned int imageRangeHigh = stream.readInt(); + state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh); + unsigned int imageBindingCount = stream.readInt(); + for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex) + { + unsigned int elementCount = stream.readInt(); + ImageBinding imageBinding(elementCount); + for (unsigned int i = 0; i < elementCount; ++i) + { + imageBinding.boundImageUnits[i] = stream.readInt(); + } + state->mImageBindings.emplace_back(imageBinding); + } + + unsigned int atomicCounterRangeLow = stream.readInt(); + unsigned int atomicCounterRangeHigh = stream.readInt(); + state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh); + + static_assert(SHADER_TYPE_MAX <= sizeof(unsigned long) * 8, "Too many shader types"); + state->mLinkedShaderStages = stream.readInt(); + + return program->getImplementation()->load(context, infoLog, &stream); +} + +// static +void MemoryProgramCache::Serialize(const Context *context, + const gl::Program *program, + angle::MemoryBuffer *binaryOut) +{ + BinaryOutputStream stream; + + stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), + ANGLE_COMMIT_HASH_SIZE); + + // nullptr context is supported when computing binary length. + if (context) + { + stream.writeInt(context->getClientVersion().major); + stream.writeInt(context->getClientVersion().minor); + } + else + { + stream.writeInt(2); + stream.writeInt(0); + } + + const auto &state = program->getState(); + + const auto &computeLocalSize = state.getComputeShaderLocalSize(); + + stream.writeInt(computeLocalSize[0]); + stream.writeInt(computeLocalSize[1]); + stream.writeInt(computeLocalSize[2]); + + stream.writeInt(state.mNumViews); + + stream.writeInt(state.getActiveAttribLocationsMask().to_ulong()); + + stream.writeInt(state.getAttributes().size()); + for (const sh::Attribute &attrib : state.getAttributes()) + { + WriteShaderVar(&stream, attrib); + stream.writeInt(attrib.location); + } + + stream.writeInt(state.getUniforms().size()); + for (const LinkedUniform &uniform : state.getUniforms()) + { + WriteShaderVar(&stream, uniform); + + // FIXME: referenced + + stream.writeInt(uniform.bufferIndex); + stream.writeInt(uniform.blockInfo.offset); + stream.writeInt(uniform.blockInfo.arrayStride); + stream.writeInt(uniform.blockInfo.matrixStride); + stream.writeInt(uniform.blockInfo.isRowMajorMatrix); + } + + stream.writeInt(state.getUniformLocations().size()); + for (const auto &variable : state.getUniformLocations()) + { + stream.writeInt(variable.arrayIndex); + stream.writeIntOrNegOne(variable.index); + stream.writeInt(variable.ignored); + } + + stream.writeInt(state.getUniformBlocks().size()); + for (const InterfaceBlock &uniformBlock : state.getUniformBlocks()) + { + WriteInterfaceBlock(&stream, uniformBlock); + } + + stream.writeInt(state.getBufferVariables().size()); + for (const BufferVariable &bufferVariable : state.getBufferVariables()) + { + WriteBufferVariable(&stream, bufferVariable); + } + + stream.writeInt(state.getShaderStorageBlocks().size()); + for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks()) + { + WriteInterfaceBlock(&stream, shaderStorageBlock); + } + + stream.writeInt(state.mAtomicCounterBuffers.size()); + for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers) + { + WriteShaderVariableBuffer(&stream, atomicCounterBuffer); + } + + // Warn the app layer if saving a binary with unsupported transform feedback. + if (!state.getLinkedTransformFeedbackVaryings().empty() && + context->getWorkarounds().disableProgramCachingForTransformFeedback) + { + WARN() << "Saving program binary with transform feedback, which is not supported on this " + "driver."; + } + + stream.writeInt(state.getLinkedTransformFeedbackVaryings().size()); + for (const auto &var : state.getLinkedTransformFeedbackVaryings()) + { + stream.writeIntVector(var.arraySizes); + stream.writeInt(var.type); + stream.writeString(var.name); + + stream.writeIntOrNegOne(var.arrayIndex); + } + + stream.writeInt(state.getTransformFeedbackBufferMode()); + + stream.writeInt(state.getOutputVariables().size()); + for (const sh::OutputVariable &output : state.getOutputVariables()) + { + WriteShaderVar(&stream, output); + stream.writeInt(output.location); + } + + stream.writeInt(state.getOutputLocations().size()); + for (const auto &outputVar : state.getOutputLocations()) + { + stream.writeInt(outputVar.arrayIndex); + stream.writeIntOrNegOne(outputVar.index); + stream.writeInt(outputVar.ignored); + } + + stream.writeInt(state.mOutputVariableTypes.size()); + for (const auto &outputVariableType : state.mOutputVariableTypes) + { + stream.writeInt(outputVariableType); + } + + static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + stream.writeInt(static_cast(state.mActiveOutputVariables.to_ulong())); + + stream.writeInt(state.getSamplerUniformRange().low()); + stream.writeInt(state.getSamplerUniformRange().high()); + + stream.writeInt(state.getSamplerBindings().size()); + for (const auto &samplerBinding : state.getSamplerBindings()) + { + stream.writeInt(samplerBinding.textureType); + stream.writeInt(samplerBinding.boundTextureUnits.size()); + stream.writeInt(samplerBinding.unreferenced); + } + + stream.writeInt(state.getImageUniformRange().low()); + stream.writeInt(state.getImageUniformRange().high()); + + stream.writeInt(state.getImageBindings().size()); + for (const auto &imageBinding : state.getImageBindings()) + { + stream.writeInt(imageBinding.boundImageUnits.size()); + for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i) + { + stream.writeInt(imageBinding.boundImageUnits[i]); + } + } + + stream.writeInt(state.getAtomicCounterUniformRange().low()); + stream.writeInt(state.getAtomicCounterUniformRange().high()); + + stream.writeInt(state.getLinkedShaderStages().to_ulong()); + + program->getImplementation()->save(context, &stream); + + ASSERT(binaryOut); + binaryOut->resize(stream.length()); + memcpy(binaryOut->data(), stream.data(), stream.length()); +} + +// static +void MemoryProgramCache::ComputeHash(const Context *context, + const Program *program, + ProgramHash *hashOut) +{ + const Shader *vertexShader = program->getAttachedVertexShader(); + const Shader *fragmentShader = program->getAttachedFragmentShader(); + const Shader *computeShader = program->getAttachedComputeShader(); + + // Compute the program hash. Start with the shader hashes and resource strings. + HashStream hashStream; + hashStream << vertexShader << fragmentShader << computeShader; + + // Add some ANGLE metadata and Context properties, such as version and back-end. + hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion() + << context->getClientMinorVersion() << context->getString(GL_RENDERER); + + // Hash pre-link program properties. + hashStream << program->getAttributeBindings() << program->getUniformLocationBindings() + << program->getFragmentInputBindings() + << program->getState().getTransformFeedbackVaryingNames() + << program->getState().getTransformFeedbackBufferMode(); + + // Call the secure SHA hashing function. + const std::string &programKey = hashStream.str(); + angle::base::SHA1HashBytes(reinterpret_cast(programKey.c_str()), + programKey.length(), hashOut->data()); +} + +LinkResult MemoryProgramCache::getProgram(const Context *context, + const Program *program, + ProgramState *state, + ProgramHash *hashOut) +{ + ComputeHash(context, program, hashOut); + const angle::MemoryBuffer *binaryProgram = nullptr; + LinkResult result(false); + if (get(*hashOut, &binaryProgram)) + { + InfoLog infoLog; + ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(), + binaryProgram->size(), infoLog), + result); + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult()); + if (!result.getResult()) + { + // Cache load failed, evict. + if (mIssuedWarnings++ < kWarningLimit) + { + WARN() << "Failed to load binary from cache: " << infoLog.str(); + + if (mIssuedWarnings == kWarningLimit) + { + WARN() << "Reaching warning limit for cache load failures, silencing " + "subsequent warnings."; + } + } + remove(*hashOut); + } + } + return result; +} + +bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.get(programHash, &entry)) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss, + kCacheResultMax); + return false; + } + + if (entry->second == CacheSource::PutProgram) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory, + kCacheResultMax); + } + else + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk, + kCacheResultMax); + } + + *programOut = &entry->first; + return true; +} + +bool MemoryProgramCache::getAt(size_t index, + ProgramHash *hashOut, + const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.getAt(index, hashOut, &entry)) + { + return false; + } + + *programOut = &entry->first; + return true; +} + +void MemoryProgramCache::remove(const ProgramHash &programHash) +{ + bool result = mProgramBinaryCache.eraseByKey(programHash); + ASSERT(result); +} + +void MemoryProgramCache::putProgram(const ProgramHash &programHash, + const Context *context, + const Program *program) +{ + CacheEntry newEntry; + Serialize(context, program, &newEntry.first); + newEntry.second = CacheSource::PutProgram; + + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes", + static_cast(newEntry.first.size())); + + const CacheEntry *result = + mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size()); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } + else + { + auto *platform = ANGLEPlatformCurrent(); + platform->cacheProgram(platform, programHash, result->first.size(), result->first.data()); + } +} + +void MemoryProgramCache::updateProgram(const Context *context, const Program *program) +{ + gl::ProgramHash programHash; + ComputeHash(context, program, &programHash); + putProgram(programHash, context, program); +} + +void MemoryProgramCache::putBinary(const ProgramHash &programHash, + const uint8_t *binary, + size_t length) +{ + // Copy the binary. + CacheEntry newEntry; + newEntry.first.resize(length); + memcpy(newEntry.first.data(), binary, length); + newEntry.second = CacheSource::PutBinary; + + // Store the binary. + const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } +} + +void MemoryProgramCache::clear() +{ + mProgramBinaryCache.clear(); + mIssuedWarnings = 0; +} + +void MemoryProgramCache::resize(size_t maxCacheSizeBytes) +{ + mProgramBinaryCache.resize(maxCacheSizeBytes); +} + +size_t MemoryProgramCache::entryCount() const +{ + return mProgramBinaryCache.entryCount(); +} + +size_t MemoryProgramCache::trim(size_t limit) +{ + return mProgramBinaryCache.shrinkToSize(limit); +} + +size_t MemoryProgramCache::size() const +{ + return mProgramBinaryCache.size(); +} + +size_t MemoryProgramCache::maxSize() const +{ + return mProgramBinaryCache.maxSize(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h new file mode 100644 index 0000000000..044bd48ecc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.h @@ -0,0 +1,130 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// MemoryProgramCache: Stores compiled and linked programs in memory so they don't +// always have to be re-compiled. Can be used in conjunction with the platform +// layer to warm up the cache from disk. + +#ifndef LIBANGLE_MEMORY_PROGRAM_CACHE_H_ +#define LIBANGLE_MEMORY_PROGRAM_CACHE_H_ + +#include + +#include "common/MemoryBuffer.h" +#include "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" + +namespace gl +{ +// 160-bit SHA-1 hash key. +constexpr size_t kProgramHashLength = 20; +using ProgramHash = std::array; +} // namespace gl + +namespace std +{ +template <> +struct hash +{ + // Simple routine to hash four ints. + size_t operator()(const gl::ProgramHash &programHash) const + { + unsigned int hash = 0; + for (uint32_t num : programHash) + { + hash *= 37; + hash += num; + } + return hash; + } +}; +} // namespace std + +namespace gl +{ +class Context; +class InfoLog; +class Program; +class ProgramState; + +class MemoryProgramCache final : angle::NonCopyable +{ + public: + MemoryProgramCache(size_t maxCacheSizeBytes); + ~MemoryProgramCache(); + + // Writes a program's binary to the output memory buffer. + static void Serialize(const Context *context, + const Program *program, + angle::MemoryBuffer *binaryOut); + + // Loads program state according to the specified binary blob. + static LinkResult Deserialize(const Context *context, + const Program *program, + ProgramState *state, + const uint8_t *binary, + size_t length, + InfoLog &infoLog); + + static void ComputeHash(const Context *context, const Program *program, ProgramHash *hashOut); + + // Check if the cache contains a binary matching the specified program. + bool get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut); + + // For querying the contents of the cache. + bool getAt(size_t index, ProgramHash *hashOut, const angle::MemoryBuffer **programOut); + + // Evict a program from the binary cache. + void remove(const ProgramHash &programHash); + + // Helper method that serializes a program. + void putProgram(const ProgramHash &programHash, const Context *context, const Program *program); + + // Same as putProgram but computes the hash. + void updateProgram(const Context *context, const Program *program); + + // Store a binary directly. + void putBinary(const ProgramHash &programHash, const uint8_t *binary, size_t length); + + // Check the cache, and deserialize and load the program if found. Evict existing hash if load + // fails. + LinkResult getProgram(const Context *context, + const Program *program, + ProgramState *state, + ProgramHash *hashOut); + + // Empty the cache. + void clear(); + + // Resize the cache. Discards current contents. + void resize(size_t maxCacheSizeBytes); + + // Returns the number of entries in the cache. + size_t entryCount() const; + + // Reduces the current cache size and returns the number of bytes freed. + size_t trim(size_t limit); + + // Returns the current cache size in bytes. + size_t size() const; + + // Returns the maximum cache size in bytes. + size_t maxSize() const; + + private: + enum class CacheSource + { + PutProgram, + PutBinary, + }; + + using CacheEntry = std::pair; + angle::SizedMRUCache mProgramBinaryCache; + unsigned int mIssuedWarnings; +}; + +} // namespace gl + +#endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h b/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h new file mode 100644 index 0000000000..70e32910fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums.h @@ -0,0 +1,111 @@ +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// PackedGLEnums_autogen.h: +// Declares ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#ifndef LIBANGLE_PACKEDGLENUMS_H_ +#define LIBANGLE_PACKEDGLENUMS_H_ + +#include "libANGLE/PackedGLEnums_autogen.h" + +#include +#include + +namespace angle +{ + +template +class EnumIterator final +{ + private: + using UnderlyingType = typename std::underlying_type::type; + + public: + EnumIterator(E value) : mValue(static_cast(value)) {} + EnumIterator &operator++() + { + mValue++; + return *this; + } + bool operator==(const EnumIterator &other) const { return mValue == other.mValue; } + bool operator!=(const EnumIterator &other) const { return mValue != other.mValue; } + E operator*() const { return static_cast(mValue); } + + private: + UnderlyingType mValue; +}; + +template +struct AllEnums +{ + EnumIterator begin() const { return {static_cast(0)}; } + EnumIterator end() const { return {E::InvalidEnum}; } +}; + +template +class PackedEnumMap +{ + private: + using UnderlyingType = typename std::underlying_type::type; + static constexpr size_t kSize = static_cast(E::EnumCount); + using Storage = std::array; + + Storage mData; + + public: + // types: + using value_type = T; + using pointer = T *; + using const_pointer = const T *; + using reference = T &; + using const_reference = const T &; + + using size_type = size_t; + using difference_type = ptrdiff_t; + + using iterator = typename Storage::iterator; + using const_iterator = typename Storage::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // No explicit construct/copy/destroy for aggregate type + void fill(const T &u) { mData.fill(u); } + void swap(PackedEnumMap &a) noexcept { mData.swap(a.mData); } + + // iterators: + iterator begin() noexcept { return mData.begin(); } + const_iterator begin() const noexcept { return mData.begin(); } + iterator end() noexcept { return mData.end(); } + const_iterator end() const noexcept { return mData.end(); } + + reverse_iterator rbegin() noexcept { return mData.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return mData.rbegin(); } + reverse_iterator rend() noexcept { return mData.rend(); } + const_reverse_iterator rend() const noexcept { return mData.rend(); } + + // capacity: + constexpr size_type size() const noexcept { return mData.size(); } + constexpr size_type max_size() const noexcept { return mData.max_size(); } + constexpr bool empty() const noexcept { return mData.empty(); } + + // element access: + reference operator[](E n) { return mData[static_cast(n)]; } + const_reference operator[](E n) const { return mData[static_cast(n)]; } + const_reference at(E n) const { return mData.at(static_cast(n)); } + reference at(E n) { return mData.at(static_cast(n)); } + + reference front() { return mData.front(); } + const_reference front() const { return mData.front(); } + reference back() { return mData.back(); } + const_reference back() const { return mData.back(); } + + T *data() noexcept { return mData.data(); } + const T *data() const noexcept { return mData.data(); } +}; + +} // namespace angle + +#endif // LIBANGLE_PACKEDGLENUMS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp new file mode 100644 index 0000000000..4959a8ff14 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.cpp @@ -0,0 +1,174 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_packed_gl_enums.py using data from packed_gl_enums.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// PackedGLEnums_autogen.cpp: +// Implements ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#include "libANGLE/PackedGLEnums_autogen.h" +#include "common/debug.h" + +namespace gl +{ + +template <> +BufferBinding FromGLenum(GLenum from) +{ + switch (from) + { + case GL_ARRAY_BUFFER: + return BufferBinding::Array; + case GL_ATOMIC_COUNTER_BUFFER: + return BufferBinding::AtomicCounter; + case GL_COPY_READ_BUFFER: + return BufferBinding::CopyRead; + case GL_COPY_WRITE_BUFFER: + return BufferBinding::CopyWrite; + case GL_DISPATCH_INDIRECT_BUFFER: + return BufferBinding::DispatchIndirect; + case GL_DRAW_INDIRECT_BUFFER: + return BufferBinding::DrawIndirect; + case GL_ELEMENT_ARRAY_BUFFER: + return BufferBinding::ElementArray; + case GL_PIXEL_PACK_BUFFER: + return BufferBinding::PixelPack; + case GL_PIXEL_UNPACK_BUFFER: + return BufferBinding::PixelUnpack; + case GL_SHADER_STORAGE_BUFFER: + return BufferBinding::ShaderStorage; + case GL_TRANSFORM_FEEDBACK_BUFFER: + return BufferBinding::TransformFeedback; + case GL_UNIFORM_BUFFER: + return BufferBinding::Uniform; + default: + return BufferBinding::InvalidEnum; + } +} + +GLenum ToGLenum(BufferBinding from) +{ + switch (from) + { + case BufferBinding::Array: + return GL_ARRAY_BUFFER; + case BufferBinding::AtomicCounter: + return GL_ATOMIC_COUNTER_BUFFER; + case BufferBinding::CopyRead: + return GL_COPY_READ_BUFFER; + case BufferBinding::CopyWrite: + return GL_COPY_WRITE_BUFFER; + case BufferBinding::DispatchIndirect: + return GL_DISPATCH_INDIRECT_BUFFER; + case BufferBinding::DrawIndirect: + return GL_DRAW_INDIRECT_BUFFER; + case BufferBinding::ElementArray: + return GL_ELEMENT_ARRAY_BUFFER; + case BufferBinding::PixelPack: + return GL_PIXEL_PACK_BUFFER; + case BufferBinding::PixelUnpack: + return GL_PIXEL_UNPACK_BUFFER; + case BufferBinding::ShaderStorage: + return GL_SHADER_STORAGE_BUFFER; + case BufferBinding::TransformFeedback: + return GL_TRANSFORM_FEEDBACK_BUFFER; + case BufferBinding::Uniform: + return GL_UNIFORM_BUFFER; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +template <> +BufferUsage FromGLenum(GLenum from) +{ + switch (from) + { + case GL_DYNAMIC_COPY: + return BufferUsage::DynamicCopy; + case GL_DYNAMIC_DRAW: + return BufferUsage::DynamicDraw; + case GL_DYNAMIC_READ: + return BufferUsage::DynamicRead; + case GL_STATIC_COPY: + return BufferUsage::StaticCopy; + case GL_STATIC_DRAW: + return BufferUsage::StaticDraw; + case GL_STATIC_READ: + return BufferUsage::StaticRead; + case GL_STREAM_COPY: + return BufferUsage::StreamCopy; + case GL_STREAM_DRAW: + return BufferUsage::StreamDraw; + case GL_STREAM_READ: + return BufferUsage::StreamRead; + default: + return BufferUsage::InvalidEnum; + } +} + +GLenum ToGLenum(BufferUsage from) +{ + switch (from) + { + case BufferUsage::DynamicCopy: + return GL_DYNAMIC_COPY; + case BufferUsage::DynamicDraw: + return GL_DYNAMIC_DRAW; + case BufferUsage::DynamicRead: + return GL_DYNAMIC_READ; + case BufferUsage::StaticCopy: + return GL_STATIC_COPY; + case BufferUsage::StaticDraw: + return GL_STATIC_DRAW; + case BufferUsage::StaticRead: + return GL_STATIC_READ; + case BufferUsage::StreamCopy: + return GL_STREAM_COPY; + case BufferUsage::StreamDraw: + return GL_STREAM_DRAW; + case BufferUsage::StreamRead: + return GL_STREAM_READ; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +template <> +CullFaceMode FromGLenum(GLenum from) +{ + switch (from) + { + case GL_BACK: + return CullFaceMode::Back; + case GL_FRONT: + return CullFaceMode::Front; + case GL_FRONT_AND_BACK: + return CullFaceMode::FrontAndBack; + default: + return CullFaceMode::InvalidEnum; + } +} + +GLenum ToGLenum(CullFaceMode from) +{ + switch (from) + { + case CullFaceMode::Back: + return GL_BACK; + case CullFaceMode::Front: + return GL_FRONT; + case CullFaceMode::FrontAndBack: + return GL_FRONT_AND_BACK; + default: + UNREACHABLE(); + return GL_NONE; + } +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h new file mode 100644 index 0000000000..f3f349ab68 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/PackedGLEnums_autogen.h @@ -0,0 +1,84 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_packed_gl_enums.py using data from packed_gl_enums.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// PackedGLEnums_autogen.h: +// Declares ANGLE-specific enums classes for GLEnum and functions operating +// on them. + +#ifndef LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ +#define LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ + +#include + +#include + +namespace gl +{ + +template +Enum FromGLenum(GLenum from); + +enum class BufferBinding : uint8_t +{ + Array = 0, + AtomicCounter = 1, + CopyRead = 2, + CopyWrite = 3, + DispatchIndirect = 4, + DrawIndirect = 5, + ElementArray = 6, + PixelPack = 7, + PixelUnpack = 8, + ShaderStorage = 9, + TransformFeedback = 10, + Uniform = 11, + + InvalidEnum = 12, + EnumCount = 12, +}; + +template <> +BufferBinding FromGLenum(GLenum from); +GLenum ToGLenum(BufferBinding from); + +enum class BufferUsage : uint8_t +{ + DynamicCopy = 0, + DynamicDraw = 1, + DynamicRead = 2, + StaticCopy = 3, + StaticDraw = 4, + StaticRead = 5, + StreamCopy = 6, + StreamDraw = 7, + StreamRead = 8, + + InvalidEnum = 9, + EnumCount = 9, +}; + +template <> +BufferUsage FromGLenum(GLenum from); +GLenum ToGLenum(BufferUsage from); + +enum class CullFaceMode : uint8_t +{ + Back = 0, + Front = 1, + FrontAndBack = 2, + + InvalidEnum = 3, + EnumCount = 3, +}; + +template <> +CullFaceMode FromGLenum(GLenum from); +GLenum ToGLenum(CullFaceMode from); + +} // namespace gl + +#endif // LIBANGLE_PACKEDGLENUMS_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Path.cpp b/src/3rdparty/angle/src/libANGLE/Path.cpp new file mode 100644 index 0000000000..8f2ce9ef92 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Path.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Path.h: Defines the gl::Path class, representing CHROMIUM_path_rendering +// path object. + +#include "libANGLE/Path.h" +#include "libANGLE/renderer/PathImpl.h" + +#include "common/mathutil.h" +#include "common/debug.h" + +namespace gl +{ + +Path::Path(rx::PathImpl *impl) + : mPath(impl), + mHasData(false), + mEndCaps(GL_FLAT_CHROMIUM), + mJoinStyle(GL_MITER_REVERT_CHROMIUM), + mStrokeWidth(1.0f), + mStrokeBound(0.2f), + mMiterLimit(4.0f) +{ +} + +Path::~Path() +{ + delete mPath; +} + +Error Path::setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + ANGLE_TRY(mPath->setCommands(numCommands, commands, numCoords, coordType, coords)); + + mHasData = true; + + return NoError(); +} + +void Path::setStrokeWidth(GLfloat width) +{ + mStrokeWidth = width; + mPath->setPathParameter(GL_PATH_STROKE_WIDTH_CHROMIUM, mStrokeWidth); +} + +void Path::setStrokeBound(GLfloat bound) +{ + mStrokeBound = clamp(bound, 0.0f, 1.0f); + mPath->setPathParameter(GL_PATH_STROKE_BOUND_CHROMIUM, mStrokeBound); +} + +void Path::setEndCaps(GLenum type) +{ + mEndCaps = type; + mPath->setPathParameter(GL_PATH_END_CAPS_CHROMIUM, static_cast(type)); +} + +void Path::setJoinStyle(GLenum type) +{ + mJoinStyle = type; + mPath->setPathParameter(GL_PATH_JOIN_STYLE_CHROMIUM, static_cast(type)); +} + +void Path::setMiterLimit(GLfloat value) +{ + mMiterLimit = value; + mPath->setPathParameter(GL_PATH_MITER_LIMIT_CHROMIUM, value); +} + +} // gl diff --git a/src/3rdparty/angle/src/libANGLE/Path.h b/src/3rdparty/angle/src/libANGLE/Path.h new file mode 100644 index 0000000000..b103c84607 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Path.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Path.h: Defines the gl::Path class, representing CHROMIUM_path_rendering +// path object. + +#ifndef LIBANGLE_PATH_H_ +#define LIBANGLE_PATH_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class PathImpl; +} + +namespace gl +{ +class Path final : angle::NonCopyable +{ + public: + Path(rx::PathImpl *impl); + + ~Path(); + + Error setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); + + void setStrokeWidth(GLfloat width); + void setStrokeBound(GLfloat bound); + void setEndCaps(GLenum type); + void setJoinStyle(GLenum type); + void setMiterLimit(GLfloat value); + + GLfloat getStrokeWidth() const { return mStrokeWidth; } + GLfloat getStrokeBound() const { return mStrokeBound; } + GLfloat getMiterLimit() const { return mMiterLimit; } + GLenum getEndCaps() const { return mEndCaps; } + GLenum getJoinStyle() const { return mJoinStyle; } + + bool hasPathData() const { return mHasData; } + + rx::PathImpl *getImplementation() const { return mPath; } + + private: + rx::PathImpl *mPath; + + // a Path object is not actually considered "a path" + // untill it has been specified with data. So we'll + // keep this flag to support this semantics. + bool mHasData; + + GLenum mEndCaps; + GLenum mJoinStyle; + GLfloat mStrokeWidth; + GLfloat mStrokeBound; + GLfloat mMiterLimit; +}; + +} // namespace gl + +#endif // LIBANGLE_PATH_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/Platform.cpp b/src/3rdparty/angle/src/libANGLE/Platform.cpp index bfcdb1494e..702091624f 100644 --- a/src/3rdparty/angle/src/libANGLE/Platform.cpp +++ b/src/3rdparty/angle/src/libANGLE/Platform.cpp @@ -8,28 +8,62 @@ #include +#include + #include "common/debug.h" namespace { -angle::Platform *currentPlatform = nullptr; +// TODO(jmadill): Make methods owned by egl::Display. +angle::PlatformMethods g_platformMethods; +} // anonymous namespace + +angle::PlatformMethods::PlatformMethods() +{ } -// static -angle::Platform *ANGLE_APIENTRY ANGLEPlatformCurrent() +angle::PlatformMethods *ANGLEPlatformCurrent() { - return currentPlatform; + return &g_platformMethods; } -// static -void ANGLE_APIENTRY ANGLEPlatformInitialize(angle::Platform *platformImpl) +bool ANGLE_APIENTRY ANGLEGetDisplayPlatform(angle::EGLDisplayType display, + const char *const methodNames[], + unsigned int methodNameCount, + void *context, + void *platformMethods) { - ASSERT(platformImpl != nullptr); - currentPlatform = platformImpl; + angle::PlatformMethods **platformMethodsOut = + reinterpret_cast(platformMethods); + + // We allow for a lower input count of impl platform methods if the subset is correct. + if (methodNameCount > angle::g_NumPlatformMethods) + { + ERR() << "Invalid platform method count: " << methodNameCount << ", expected " + << angle::g_NumPlatformMethods << "."; + return false; + } + + for (unsigned int nameIndex = 0; nameIndex < methodNameCount; ++nameIndex) + { + const char *expectedName = angle::g_PlatformMethodNames[nameIndex]; + const char *actualName = methodNames[nameIndex]; + if (strcmp(expectedName, actualName) != 0) + { + ERR() << "Invalid platform method name: " << actualName << ", expected " << expectedName + << "."; + return false; + } + } + + // TODO(jmadill): Store platform methods in display. + g_platformMethods.context = context; + *platformMethodsOut = &g_platformMethods; + return true; } -// static -void ANGLE_APIENTRY ANGLEPlatformShutdown() +void ANGLE_APIENTRY ANGLEResetDisplayPlatform(angle::EGLDisplayType display) { - currentPlatform = nullptr; + // TODO(jmadill): Store platform methods in display. + g_platformMethods = angle::PlatformMethods(); } diff --git a/src/3rdparty/angle/src/libANGLE/Program.cpp b/src/3rdparty/angle/src/libANGLE/Program.cpp index 69497c4436..795d326041 100644 --- a/src/3rdparty/angle/src/libANGLE/Program.cpp +++ b/src/3rdparty/angle/src/libANGLE/Program.cpp @@ -11,18 +11,24 @@ #include -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/debug.h" #include "common/platform.h" +#include "common/string_utils.h" #include "common/utilities.h" -#include "common/version.h" #include "compiler/translator/blocklayout.h" -#include "libANGLE/Data.h" +#include "libANGLE/Context.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/ResourceManager.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VaryingPacking.h" #include "libANGLE/features.h" -#include "libANGLE/renderer/Renderer.h" -#include "libANGLE/renderer/ProgramImpl.h" +#include "libANGLE/histogram_macros.h" #include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "platform/Platform.h" namespace gl { @@ -30,29 +36,6 @@ namespace gl namespace { -void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var) -{ - 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()); -} - -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 @@ -88,19 +71,19 @@ GLuint UniformStateQueryCast(GLint value) template <> GLfloat UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1.0f : 0.0f); + return (ConvertToBool(value) ? 1.0f : 0.0f); } template <> GLint UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1 : 0); + return (ConvertToBool(value) ? 1 : 0); } template <> GLuint UniformStateQueryCast(GLboolean value) { - return (value == GL_TRUE ? 1u : 0u); + return (ConvertToBool(value) ? 1u : 0u); } // Default to static_cast @@ -123,29 +106,224 @@ void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int co } } -bool UniformInList(const std::vector &list, const std::string &name) +template +GLuint GetResourceIndexFromName(const std::vector &list, const std::string &name) { - for (const LinkedUniform &uniform : list) + std::string nameAsArrayName = name + "[0]"; + for (size_t index = 0; index < list.size(); index++) { - if (uniform.name == name) - return true; + const VarT &resource = list[index]; + if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName)) + { + return static_cast(index); + } + } + + return GL_INVALID_INDEX; +} + +template +GLint GetVariableLocation(const std::vector &list, + const std::vector &locationList, + const std::string &name) +{ + size_t nameLengthWithoutArrayIndex; + unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex); + + for (size_t location = 0u; location < locationList.size(); ++location) + { + const VariableLocation &variableLocation = locationList[location]; + if (!variableLocation.used()) + { + continue; + } + + const VarT &variable = list[variableLocation.index]; + + if (angle::BeginsWith(variable.name, name)) + { + if (name.length() == variable.name.length()) + { + ASSERT(name == variable.name); + // GLES 3.1 November 2016 page 87. + // The string exactly matches the name of the active variable. + return static_cast(location); + } + if (name.length() + 3u == variable.name.length() && variable.isArray()) + { + ASSERT(name + "[0]" == variable.name); + // The string identifies the base name of an active array, where the string would + // exactly match the name of the variable if the suffix "[0]" were appended to the + // string. + return static_cast(location); + } + } + if (variable.isArray() && variableLocation.arrayIndex == arrayIndex && + nameLengthWithoutArrayIndex + 3u == variable.name.length() && + angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex)) + { + ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == variable.name); + // The string identifies an active element of the array, where the string ends with the + // concatenation of the "[" character, an integer (with no "+" sign, extra leading + // zeroes, or whitespace) identifying an array element, and the "]" character, the + // integer is less than the number of active elements of the array variable, and where + // the string would exactly match the enumerated name of the array if the decimal + // integer were replaced with zero. + return static_cast(location); + } + } + + return -1; +} + +void CopyStringToBuffer(GLchar *buffer, const std::string &string, GLsizei bufSize, GLsizei *length) +{ + ASSERT(bufSize > 0); + strncpy(buffer, string.c_str(), bufSize); + buffer[bufSize - 1] = '\0'; + + if (length) + { + *length = static_cast(strlen(buffer)); } +} +bool IncludeSameArrayElement(const std::set &nameSet, const std::string &name) +{ + std::vector subscripts; + std::string baseName = ParseResourceName(name, &subscripts); + for (auto nameInSet : nameSet) + { + std::vector arrayIndices; + std::string arrayName = ParseResourceName(nameInSet, &arrayIndices); + if (baseName == arrayName && + (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices)) + { + return true; + } + } return false; } -} // anonymous namespace +bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks, + const std::vector &interfaceBlocks, + const std::string &errorMessage, + InfoLog &infoLog) +{ + GLuint blockCount = 0; + for (const sh::InterfaceBlock &block : interfaceBlocks) + { + if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED) + { + blockCount += (block.arraySize ? block.arraySize : 1); + if (blockCount > maxInterfaceBlocks) + { + infoLog << errorMessage << maxInterfaceBlocks << ")"; + return false; + } + } + } + return true; +} -const char *const g_fakepath = "C:\\fakepath"; +GLuint GetInterfaceBlockIndex(const std::vector &list, const std::string &name) +{ + std::vector subscripts; + std::string baseName = ParseResourceName(name, &subscripts); + + unsigned int numBlocks = static_cast(list.size()); + for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++) + { + const auto &block = list[blockIndex]; + if (block.name == baseName) + { + const bool arrayElementZero = + (subscripts.empty() && (!block.isArray || block.arrayElement == 0)); + const bool arrayElementMatches = + (subscripts.size() == 1 && subscripts[0] == block.arrayElement); + if (arrayElementMatches || arrayElementZero) + { + return blockIndex; + } + } + } + + return GL_INVALID_INDEX; +} + +void GetInterfaceBlockName(const GLuint index, + const std::vector &list, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + ASSERT(index < list.size()); + + const auto &block = list[index]; -AttributeBindings::AttributeBindings() + if (bufSize > 0) + { + std::string blockName = block.name; + + if (block.isArray) + { + blockName += ArrayString(block.arrayElement); + } + CopyStringToBuffer(name, blockName, bufSize, length); + } +} + +void InitUniformBlockLinker(const gl::Context *context, + const ProgramState &state, + UniformBlockLinker *blockLinker) { + if (state.getAttachedVertexShader()) + { + blockLinker->addShaderBlocks(GL_VERTEX_SHADER, + &state.getAttachedVertexShader()->getUniformBlocks(context)); + } + + if (state.getAttachedFragmentShader()) + { + blockLinker->addShaderBlocks(GL_FRAGMENT_SHADER, + &state.getAttachedFragmentShader()->getUniformBlocks(context)); + } + + if (state.getAttachedComputeShader()) + { + blockLinker->addShaderBlocks(GL_COMPUTE_SHADER, + &state.getAttachedComputeShader()->getUniformBlocks(context)); + } } -AttributeBindings::~AttributeBindings() +void InitShaderStorageBlockLinker(const gl::Context *context, + const ProgramState &state, + ShaderStorageBlockLinker *blockLinker) { + if (state.getAttachedVertexShader()) + { + blockLinker->addShaderBlocks( + GL_VERTEX_SHADER, &state.getAttachedVertexShader()->getShaderStorageBlocks(context)); + } + + if (state.getAttachedFragmentShader()) + { + blockLinker->addShaderBlocks( + GL_FRAGMENT_SHADER, + &state.getAttachedFragmentShader()->getShaderStorageBlocks(context)); + } + + if (state.getAttachedComputeShader()) + { + blockLinker->addShaderBlocks( + GL_COMPUTE_SHADER, &state.getAttachedComputeShader()->getShaderStorageBlocks(context)); + } } +} // anonymous namespace + +const char *const g_fakepath = "C:\\fakepath"; + InfoLog::InfoLog() { } @@ -156,7 +334,12 @@ InfoLog::~InfoLog() size_t InfoLog::getLength() const { - const std::string &logString = mStream.str(); + if (!mLazyStream) + { + return 0; + } + + const std::string &logString = mLazyStream->str(); return logString.empty() ? 0 : logString.length() + 1; } @@ -166,12 +349,12 @@ void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const if (bufSize > 0) { - const std::string str(mStream.str()); + const std::string logString(str()); - if (!str.empty()) + if (!logString.empty()) { - index = std::min(static_cast(bufSize) - 1, str.length()); - memcpy(infoLog, str.c_str(), index); + index = std::min(static_cast(bufSize) - 1, logString.length()); + memcpy(infoLog, logString.c_str(), index); } infoLog[index] = '\0'; @@ -184,10 +367,12 @@ void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const } // append a santized message to the program info log. -// The D3D compiler includes a fake file path in some of the warning or error +// The D3D compiler includes a fake file path in some of the warning or error // messages, so lets remove all occurrences of this fake file path from the log. void InfoLog::appendSanitized(const char *message) { + ensureInitialized(); + std::string msg(message); size_t found; @@ -201,569 +386,682 @@ void InfoLog::appendSanitized(const char *message) } while (found != std::string::npos); - mStream << message << std::endl; + *mLazyStream << message << std::endl; } void InfoLog::reset() { } -VariableLocation::VariableLocation() - : name(), - element(0), - index(0) +VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false) +{ +} + +VariableLocation::VariableLocation(unsigned int arrayIndex, unsigned int index) + : arrayIndex(arrayIndex), index(index), ignored(false) +{ + ASSERT(arrayIndex != GL_INVALID_INDEX); +} + +SamplerBinding::SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced) + : textureType(textureTypeIn), boundTextureUnits(elementCount, 0), unreferenced(unreferenced) +{ +} + +SamplerBinding::SamplerBinding(const SamplerBinding &other) = default; + +SamplerBinding::~SamplerBinding() = default; + +Program::Bindings::Bindings() +{ +} + +Program::Bindings::~Bindings() +{ +} + +void Program::Bindings::bindLocation(GLuint index, const std::string &name) +{ + mBindings[name] = index; +} + +int Program::Bindings::getBinding(const std::string &name) const +{ + auto iter = mBindings.find(name); + return (iter != mBindings.end()) ? iter->second : -1; +} + +Program::Bindings::const_iterator Program::Bindings::begin() const { + return mBindings.begin(); } -VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) - : name(name), - element(element), - index(index) +Program::Bindings::const_iterator Program::Bindings::end() const { + return mBindings.end(); } -Program::Data::Data() +ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0) +{ +} +ImageBinding::ImageBinding(GLuint imageUnit, size_t count) +{ + for (size_t index = 0; index < count; ++index) + { + boundImageUnits.push_back(imageUnit + static_cast(index)); + } +} + +ImageBinding::ImageBinding(const ImageBinding &other) = default; + +ImageBinding::~ImageBinding() = default; + +ProgramState::ProgramState() : mLabel(), mAttachedFragmentShader(nullptr), mAttachedVertexShader(nullptr), + mAttachedComputeShader(nullptr), + mAttachedGeometryShader(nullptr), mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS), - mBinaryRetrieveableHint(false) + mMaxActiveAttribLocation(0), + mSamplerUniformRange(0, 0), + mImageUniformRange(0, 0), + mAtomicCounterUniformRange(0, 0), + mBinaryRetrieveableHint(false), + mNumViews(-1) { + mComputeShaderLocalSize.fill(1); } -Program::Data::~Data() +ProgramState::~ProgramState() { - if (mAttachedVertexShader != nullptr) - { - mAttachedVertexShader->release(); - } - - if (mAttachedFragmentShader != nullptr) - { - mAttachedFragmentShader->release(); - } + ASSERT(!mAttachedVertexShader && !mAttachedFragmentShader && !mAttachedComputeShader && + !mAttachedGeometryShader); } -const std::string &Program::Data::getLabel() +const std::string &ProgramState::getLabel() { return mLabel; } -const LinkedUniform *Program::Data::getUniformByName(const std::string &name) const +GLuint ProgramState::getUniformIndexFromName(const std::string &name) const { - for (const LinkedUniform &linkedUniform : mUniforms) - { - if (linkedUniform.name == name) - { - return &linkedUniform; - } - } + return GetResourceIndexFromName(mUniforms, name); +} - return nullptr; +GLuint ProgramState::getBufferVariableIndexFromName(const std::string &name) const +{ + return GetResourceIndexFromName(mBufferVariables, name); } -GLint Program::Data::getUniformLocation(const std::string &name) const +GLuint ProgramState::getUniformIndexFromLocation(GLint location) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + ASSERT(location >= 0 && static_cast(location) < mUniformLocations.size()); + return mUniformLocations[location].index; +} - for (size_t location = 0; location < mUniformLocations.size(); ++location) +Optional ProgramState::getSamplerIndex(GLint location) const +{ + GLuint index = getUniformIndexFromLocation(location); + if (!isSamplerUniformIndex(index)) { - 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 Optional::Invalid(); } - return -1; + return getSamplerIndexFromUniformIndex(index); } -GLuint Program::Data::getUniformIndex(const std::string &name) const +bool ProgramState::isSamplerUniformIndex(GLuint index) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + return mSamplerUniformRange.contains(index); +} - // 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; - } +GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const +{ + ASSERT(isSamplerUniformIndex(uniformIndex)); + return uniformIndex - mSamplerUniformRange.low(); +} - for (size_t index = 0; index < mUniforms.size(); index++) +GLuint ProgramState::getAttributeLocation(const std::string &name) const +{ + for (const sh::Attribute &attribute : mAttributes) { - const LinkedUniform &uniform = mUniforms[index]; - if (uniform.name == baseName) + if (attribute.name == name) { - if (uniform.isArray() || subscript == GL_INVALID_INDEX) - { - return static_cast(index); - } + return attribute.location; } } - return GL_INVALID_INDEX; + return static_cast(-1); } -Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle) - : mProgram(factory->createProgram(mData)), +Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle) + : mProgram(factory->createProgram(mState)), mValidated(false), mLinked(false), mDeleteStatus(false), mRefCount(0), mResourceManager(manager), - mHandle(handle), - mSamplerUniformRange(0, 0) + mHandle(handle) { ASSERT(mProgram); - resetUniformBlockBindings(); unlink(); } Program::~Program() { - unlink(true); + ASSERT(!mProgram); +} + +void Program::onDestroy(const Context *context) +{ + if (mState.mAttachedVertexShader != nullptr) + { + mState.mAttachedVertexShader->release(context); + mState.mAttachedVertexShader = nullptr; + } + + if (mState.mAttachedFragmentShader != nullptr) + { + mState.mAttachedFragmentShader->release(context); + mState.mAttachedFragmentShader = nullptr; + } + if (mState.mAttachedComputeShader != nullptr) + { + mState.mAttachedComputeShader->release(context); + mState.mAttachedComputeShader = nullptr; + } + + if (mState.mAttachedGeometryShader != nullptr) + { + mState.mAttachedGeometryShader->release(context); + mState.mAttachedGeometryShader = nullptr; + } + + mProgram->destroy(context); + + ASSERT(!mState.mAttachedVertexShader && !mState.mAttachedFragmentShader && + !mState.mAttachedComputeShader && !mState.mAttachedGeometryShader); SafeDelete(mProgram); + + delete this; } void Program::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &Program::getLabel() const { - return mData.mLabel; + return mState.mLabel; } -bool Program::attachShader(Shader *shader) +void Program::attachShader(Shader *shader) { - if (shader->getType() == GL_VERTEX_SHADER) + switch (shader->getType()) { - if (mData.mAttachedVertexShader) + case GL_VERTEX_SHADER: { - return false; + ASSERT(!mState.mAttachedVertexShader); + mState.mAttachedVertexShader = shader; + mState.mAttachedVertexShader->addRef(); + break; } - - mData.mAttachedVertexShader = shader; - mData.mAttachedVertexShader->addRef(); - } - else if (shader->getType() == GL_FRAGMENT_SHADER) - { - if (mData.mAttachedFragmentShader) + case GL_FRAGMENT_SHADER: { - return false; + ASSERT(!mState.mAttachedFragmentShader); + mState.mAttachedFragmentShader = shader; + mState.mAttachedFragmentShader->addRef(); + break; } - - mData.mAttachedFragmentShader = shader; - mData.mAttachedFragmentShader->addRef(); + case GL_COMPUTE_SHADER: + { + ASSERT(!mState.mAttachedComputeShader); + mState.mAttachedComputeShader = shader; + mState.mAttachedComputeShader->addRef(); + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + ASSERT(!mState.mAttachedGeometryShader); + mState.mAttachedGeometryShader = shader; + mState.mAttachedGeometryShader->addRef(); + break; + } + default: + UNREACHABLE(); } - else UNREACHABLE(); - - return true; } -bool Program::detachShader(Shader *shader) +void Program::detachShader(const Context *context, Shader *shader) { - if (shader->getType() == GL_VERTEX_SHADER) + switch (shader->getType()) { - if (mData.mAttachedVertexShader != shader) + case GL_VERTEX_SHADER: { - return false; + ASSERT(mState.mAttachedVertexShader == shader); + shader->release(context); + mState.mAttachedVertexShader = nullptr; + break; } - - shader->release(); - mData.mAttachedVertexShader = nullptr; - } - else if (shader->getType() == GL_FRAGMENT_SHADER) - { - if (mData.mAttachedFragmentShader != shader) + case GL_FRAGMENT_SHADER: { - return false; + ASSERT(mState.mAttachedFragmentShader == shader); + shader->release(context); + mState.mAttachedFragmentShader = nullptr; + break; } - - shader->release(); - mData.mAttachedFragmentShader = nullptr; + case GL_COMPUTE_SHADER: + { + ASSERT(mState.mAttachedComputeShader == shader); + shader->release(context); + mState.mAttachedComputeShader = nullptr; + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + ASSERT(mState.mAttachedGeometryShader == shader); + shader->release(context); + mState.mAttachedGeometryShader = nullptr; + break; + } + default: + UNREACHABLE(); } - else UNREACHABLE(); - - return true; } int Program::getAttachedShadersCount() const { - return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0); + return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) + + (mState.mAttachedComputeShader ? 1 : 0) + (mState.mAttachedGeometryShader ? 1 : 0); } -void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) +void Program::bindAttributeLocation(GLuint index, const char *name) { - if (index < MAX_VERTEX_ATTRIBS) - { - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - mAttributeBinding[i].erase(name); - } + mAttributeBindings.bindLocation(index, name); +} - mAttributeBinding[index].insert(name); - } +void Program::bindUniformLocation(GLuint index, const char *name) +{ + mUniformLocationBindings.bindLocation(index, name); } -void Program::bindAttributeLocation(GLuint index, const char *name) +void Program::bindFragmentInputLocation(GLint index, const char *name) { - mAttributeBindings.bindAttributeLocation(index, name); + mFragmentInputBindings.bindLocation(index, 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 gl::Data &data) +BindingInfo Program::getFragmentInputBindingInfo(const Context *context, GLint index) const { - unlink(false); + BindingInfo ret; + ret.type = GL_NONE; + ret.valid = false; - mInfoLog.reset(); - resetUniformBlockBindings(); + Shader *fragmentShader = mState.getAttachedFragmentShader(); + ASSERT(fragmentShader); - if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled()) - { - return Error(GL_NO_ERROR); - } - ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER); + // Find the actual fragment shader varying we're interested in + const std::vector &inputs = fragmentShader->getInputVaryings(context); - if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled()) + for (const auto &binding : mFragmentInputBindings) { - return Error(GL_NO_ERROR); - } - ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER); + if (binding.second != static_cast(index)) + continue; - if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader)) - { - return Error(GL_NO_ERROR); - } + ret.valid = true; - if (!linkVaryings(mInfoLog, mData.mAttachedVertexShader, mData.mAttachedFragmentShader)) - { - return Error(GL_NO_ERROR); - } + size_t nameLengthWithoutArrayIndex; + unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex); - if (!linkUniforms(mInfoLog, *data.caps)) - { - return Error(GL_NO_ERROR); + for (const auto &in : inputs) + { + if (in.name.length() == nameLengthWithoutArrayIndex && + angle::BeginsWith(in.name, binding.first, nameLengthWithoutArrayIndex)) + { + if (in.isArray()) + { + // The client wants to bind either "name" or "name[0]". + // GL ES 3.1 spec refers to active array names with language such as: + // "if the string identifies the base name of an active array, where the + // string would exactly match the name of the variable if the suffix "[0]" + // were appended to the string". + if (arrayIndex == GL_INVALID_INDEX) + arrayIndex = 0; + + ret.name = in.mappedName + "[" + ToString(arrayIndex) + "]"; + } + else + { + ret.name = in.mappedName; + } + ret.type = in.type; + return ret; + } + } } - if (!linkUniformBlocks(mInfoLog, *data.caps)) - { - return Error(GL_NO_ERROR); - } + return ret; +} + +void Program::pathFragmentInputGen(const Context *context, + GLint index, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + // If the location is -1 then the command is silently ignored + if (index == -1) + return; + + const auto &binding = getFragmentInputBindingInfo(context, index); + + // If the input doesn't exist then then the command is silently ignored + // This could happen through optimization for example, the shader translator + // decides that a variable is not actually being used and optimizes it away. + if (binding.name.empty()) + return; - const auto &mergedVaryings = getMergedVaryings(); + mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs); +} + +// The attached shaders are checked for linking errors by matching up their variables. +// Uniform, input and output variables get collected. +// The code gets compiled into binaries. +Error Program::link(const gl::Context *context) +{ + const auto &data = context->getContextState(); + + auto *platform = ANGLEPlatformCurrent(); + double startTime = platform->currentTime(platform); - if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, *data.caps)) + unlink(); + + ProgramHash programHash; + auto *cache = context->getMemoryProgramCache(); + if (cache) { - return Error(GL_NO_ERROR); + ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked); + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", mLinked); } - linkOutputVariables(); - - rx::LinkResult result = mProgram->link(data, mInfoLog); - if (result.error.isError() || !result.linkSuccess) + if (mLinked) { - return result.error; + double delta = platform->currentTime(platform) - startTime; + int us = static_cast(delta * 1000000.0); + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheHitTimeUS", us); + return NoError(); } - gatherTransformFeedbackVaryings(mergedVaryings); - gatherInterfaceBlockInfo(); + // Cache load failed, fall through to normal linking. + unlink(); + mInfoLog.reset(); - mLinked = true; - return gl::Error(GL_NO_ERROR); -} + const Caps &caps = data.getCaps(); -int AttributeBindings::getAttributeBinding(const std::string &name) const -{ - for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + Shader *computeShader = mState.mAttachedComputeShader; + + bool isComputeShaderAttached = (computeShader != nullptr); + bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr); + // Check whether we both have a compute and non-compute shaders attached. + // If there are of both types attached, then linking should fail. + // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram + if (isComputeShaderAttached == true && nonComputeShadersAttached == true) + { + mInfoLog << "Both a compute and non-compute shaders are attached to the same program."; + return NoError(); + } + + if (computeShader) { - if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) + if (!computeShader->isCompiled(context)) { - return location; + mInfoLog << "Attached compute shader is not compiled."; + return NoError(); } - } + ASSERT(computeShader->getType() == GL_COMPUTE_SHADER); - return -1; -} + mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize(context); -// Returns the program object to an unlinked state, before re-linking, or at destruction -void Program::unlink(bool destroy) -{ - if (destroy) // Object being destructed - { - if (mData.mAttachedFragmentShader) + // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs + // If the work group size is not specified, a link time error should occur. + if (!mState.mComputeShaderLocalSize.isDeclared()) { - mData.mAttachedFragmentShader->release(); - mData.mAttachedFragmentShader = nullptr; + mInfoLog << "Work group size is not specified."; + return NoError(); } - if (mData.mAttachedVertexShader) + if (!linkUniforms(context, mInfoLog, mUniformLocationBindings)) { - mData.mAttachedVertexShader->release(); - mData.mAttachedVertexShader = nullptr; + return NoError(); } - } - mData.mAttributes.clear(); - mData.mActiveAttribLocationsMask.reset(); - mData.mTransformFeedbackVaryingVars.clear(); - mData.mUniforms.clear(); - mData.mUniformLocations.clear(); - mData.mUniformBlocks.clear(); - mData.mOutputVariables.clear(); + if (!linkInterfaceBlocks(context, mInfoLog)) + { + return NoError(); + } - mValidated = false; + ProgramLinkedResources resources = { + {0, PackMode::ANGLE_RELAXED}, + {&mState.mUniformBlocks, &mState.mUniforms}, + {&mState.mShaderStorageBlocks, &mState.mBufferVariables}}; - mLinked = false; -} + InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker); + InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker); -bool Program::isLinked() const -{ - return mLinked; -} + ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked); + if (!mLinked) + { + return NoError(); + } + } + else + { + if (!fragmentShader || !fragmentShader->isCompiled(context)) + { + return NoError(); + } + ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER); -Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length) -{ - unlink(false); + if (!vertexShader || !vertexShader->isCompiled(context)) + { + return NoError(); + } + ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); -#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED - return Error(GL_NO_ERROR); -#else - ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE); - if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) - { - mInfoLog << "Invalid program binary format."; - return Error(GL_NO_ERROR); - } + if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context)) + { + mInfoLog << "Fragment shader version does not match vertex shader version."; + return NoError(); + } - BinaryInputStream stream(binary, length); + if (!linkAttributes(context, mInfoLog)) + { + return NoError(); + } - int majorVersion = stream.readInt(); - int minorVersion = stream.readInt(); - if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) - { - mInfoLog << "Invalid program binary version."; - return Error(GL_NO_ERROR); - } + if (!linkVaryings(context, mInfoLog)) + { + return NoError(); + } - unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; - stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); - if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) - { - mInfoLog << "Invalid program binary version."; - return Error(GL_NO_ERROR); - } + if (!linkUniforms(context, mInfoLog, mUniformLocationBindings)) + { + return NoError(); + } - static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, - "Too many vertex attribs for mask"); - mData.mActiveAttribLocationsMask = stream.readInt(); + if (!linkInterfaceBlocks(context, mInfoLog)) + { + return NoError(); + } - 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); - } + if (!linkValidateGlobalNames(context, mInfoLog)) + { + return NoError(); + } - unsigned int uniformCount = stream.readInt(); - ASSERT(mData.mUniforms.empty()); - for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex) - { - LinkedUniform uniform; - LoadShaderVar(&stream, &uniform); + const auto &mergedVaryings = getMergedVaryings(context); - uniform.blockIndex = stream.readInt(); - uniform.blockInfo.offset = stream.readInt(); - uniform.blockInfo.arrayStride = stream.readInt(); - uniform.blockInfo.matrixStride = stream.readInt(); - uniform.blockInfo.isRowMajorMatrix = stream.readBool(); + mState.mNumViews = vertexShader->getNumViews(context); - mData.mUniforms.push_back(uniform); - } + linkOutputVariables(context); - 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); + // Map the varyings to the register file + // In WebGL, we use a slightly different handling for packing variables. + auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT + : PackMode::ANGLE_RELAXED; - mData.mUniformLocations.push_back(variable); - } + ProgramLinkedResources resources = { + {data.getCaps().maxVaryingVectors, packMode}, + {&mState.mUniformBlocks, &mState.mUniforms}, + {&mState.mShaderStorageBlocks, &mState.mBufferVariables}}; - 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); + InitUniformBlockLinker(context, mState, &resources.uniformBlockLinker); + InitShaderStorageBlockLinker(context, mState, &resources.shaderStorageBlockLinker); - unsigned int numMembers = stream.readInt(); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + if (!linkValidateTransformFeedback(context, mInfoLog, mergedVaryings, caps)) { - uniformBlock.memberUniformIndexes.push_back(stream.readInt()); + return NoError(); } - mData.mUniformBlocks.push_back(uniformBlock); - } + if (!resources.varyingPacking.collectAndPackUserVaryings( + mInfoLog, mergedVaryings, mState.getTransformFeedbackVaryingNames())) + { + return NoError(); + } - unsigned int transformFeedbackVaryingCount = stream.readInt(); - ASSERT(mData.mTransformFeedbackVaryingVars.empty()); - for (unsigned int transformFeedbackVaryingIndex = 0; - transformFeedbackVaryingIndex < transformFeedbackVaryingCount; - ++transformFeedbackVaryingIndex) - { - sh::Varying varying; - stream.readInt(&varying.arraySize); - stream.readInt(&varying.type); - stream.readString(&varying.name); + ANGLE_TRY_RESULT(mProgram->link(context, resources, mInfoLog), mLinked); + if (!mLinked) + { + return NoError(); + } - mData.mTransformFeedbackVaryingVars.push_back(varying); + gatherTransformFeedbackVaryings(mergedVaryings); } - stream.readInt(&mData.mTransformFeedbackBufferMode); + gatherAtomicCounterBuffers(); + initInterfaceBlockBindings(); - 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; - } + setUniformValuesFromBindingQualifiers(); - stream.readInt(&mSamplerUniformRange.start); - stream.readInt(&mSamplerUniformRange.end); + ASSERT(mLinked); + updateLinkedShaderStages(); - rx::LinkResult result = mProgram->load(mInfoLog, &stream); - if (result.error.isError() || !result.linkSuccess) + // Mark implementation-specific unreferenced uniforms as ignored. + mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings); + + // Save to the program cache. + if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() || + !context->getWorkarounds().disableProgramCachingForTransformFeedback)) { - return result.error; + cache->putProgram(programHash, context, this); } - mLinked = true; - return Error(GL_NO_ERROR); -#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED + double delta = platform->currentTime(platform) - startTime; + int us = static_cast(delta * 1000000.0); + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramCacheMissTimeUS", us); + + return NoError(); } -Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const +void Program::updateLinkedShaderStages() { - if (binaryFormat) + if (mState.mAttachedVertexShader) { - *binaryFormat = GL_PROGRAM_BINARY_ANGLE; + mState.mLinkedShaderStages.set(SHADER_VERTEX); } - BinaryOutputStream stream; - - stream.writeInt(ANGLE_MAJOR_VERSION); - stream.writeInt(ANGLE_MINOR_VERSION); - stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); - - stream.writeInt(mData.mActiveAttribLocationsMask.to_ulong()); - - stream.writeInt(mData.mAttributes.size()); - for (const sh::Attribute &attrib : mData.mAttributes) + if (mState.mAttachedFragmentShader) { - WriteShaderVar(&stream, attrib); - stream.writeInt(attrib.location); + mState.mLinkedShaderStages.set(SHADER_FRAGMENT); } - stream.writeInt(mData.mUniforms.size()); - for (const gl::LinkedUniform &uniform : mData.mUniforms) + if (mState.mAttachedComputeShader) { - 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); + mState.mLinkedShaderStages.set(SHADER_COMPUTE); } +} - stream.writeInt(mData.mUniformLocations.size()); - for (const auto &variable : mData.mUniformLocations) - { - stream.writeString(variable.name); - stream.writeInt(variable.element); - stream.writeInt(variable.index); - } +// Returns the program object to an unlinked state, before re-linking, or at destruction +void Program::unlink() +{ + mState.mAttributes.clear(); + mState.mActiveAttribLocationsMask.reset(); + mState.mMaxActiveAttribLocation = 0; + mState.mLinkedTransformFeedbackVaryings.clear(); + mState.mUniforms.clear(); + mState.mUniformLocations.clear(); + mState.mUniformBlocks.clear(); + mState.mActiveUniformBlockBindings.reset(); + mState.mAtomicCounterBuffers.clear(); + mState.mOutputVariables.clear(); + mState.mOutputLocations.clear(); + mState.mOutputVariableTypes.clear(); + mState.mActiveOutputVariables.reset(); + mState.mComputeShaderLocalSize.fill(1); + mState.mSamplerBindings.clear(); + mState.mImageBindings.clear(); + mState.mNumViews = -1; + mState.mLinkedShaderStages.reset(); - 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); + mValidated = false; - stream.writeInt(uniformBlock.vertexStaticUse); - stream.writeInt(uniformBlock.fragmentStaticUse); + mLinked = false; +} - stream.writeInt(uniformBlock.memberUniformIndexes.size()); - for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes) - { - stream.writeInt(memberUniformIndex); - } - } +bool Program::isLinked() const +{ + return mLinked; +} - stream.writeInt(mData.mTransformFeedbackVaryingVars.size()); - for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars) +Error Program::loadBinary(const Context *context, + GLenum binaryFormat, + const void *binary, + GLsizei length) +{ + unlink(); + +#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED + return NoError(); +#else + ASSERT(binaryFormat == GL_PROGRAM_BINARY_ANGLE); + if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) { - stream.writeInt(varying.arraySize); - stream.writeInt(varying.type); - stream.writeString(varying.name); + mInfoLog << "Invalid program binary format."; + return NoError(); } - stream.writeInt(mData.mTransformFeedbackBufferMode); + const uint8_t *bytes = reinterpret_cast(binary); + ANGLE_TRY_RESULT( + MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked); - stream.writeInt(mData.mOutputVariables.size()); - for (const auto &outputPair : mData.mOutputVariables) - { - stream.writeInt(outputPair.first); - stream.writeInt(outputPair.second.element); - stream.writeInt(outputPair.second.index); - stream.writeString(outputPair.second.name); - } + // Currently we require the full shader text to compute the program hash. + // TODO(jmadill): Store the binary in the internal program cache. - stream.writeInt(mSamplerUniformRange.start); - stream.writeInt(mSamplerUniformRange.end); + return NoError(); +#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED +} - gl::Error error = mProgram->save(&stream); - if (error.isError()) +Error Program::saveBinary(const Context *context, + GLenum *binaryFormat, + void *binary, + GLsizei bufSize, + GLsizei *length) const +{ + if (binaryFormat) { - return error; + *binaryFormat = GL_PROGRAM_BINARY_ANGLE; } - GLsizei streamLength = static_cast(stream.length()); - const void *streamData = stream.data(); + angle::MemoryBuffer memoryBuf; + MemoryProgramCache::Serialize(context, this, &memoryBuf); + + GLsizei streamLength = static_cast(memoryBuf.size()); + const uint8_t *streamState = memoryBuf.data(); if (streamLength > bufSize) { @@ -775,14 +1073,14 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G // TODO: This should be moved to the validation layer but computing the size of the binary before saving // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate // sizes and then copy it. - return Error(GL_INVALID_OPERATION); + return InternalError(); } if (binary) { char *ptr = reinterpret_cast(binary); - memcpy(ptr, streamData, streamLength); + memcpy(ptr, streamState, streamLength); ptr += streamLength; ASSERT(ptr - streamLength == binary); @@ -793,13 +1091,13 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G *length = streamLength; } - return Error(GL_NO_ERROR); + return NoError(); } -GLint Program::getBinaryLength() const +GLint Program::getBinaryLength(const Context *context) const { GLint length; - Error error = saveBinary(nullptr, nullptr, std::numeric_limits::max(), &length); + Error error = saveBinary(context, nullptr, nullptr, std::numeric_limits::max(), &length); if (error.isError()) { return 0; @@ -812,21 +1110,36 @@ void Program::setBinaryRetrievableHint(bool retrievable) { // TODO(jmadill) : replace with dirty bits mProgram->setBinaryRetrievableHint(retrievable); - mData.mBinaryRetrieveableHint = retrievable; + mState.mBinaryRetrieveableHint = retrievable; } bool Program::getBinaryRetrievableHint() const { - return mData.mBinaryRetrieveableHint; + return mState.mBinaryRetrieveableHint; } -void Program::release() +void Program::setSeparable(bool separable) +{ + // TODO(yunchao) : replace with dirty bits + if (mState.mSeparable != separable) + { + mProgram->setSeparable(separable); + mState.mSeparable = separable; + } +} + +bool Program::isSeparable() const +{ + return mState.mSeparable; +} + +void Program::release(const Context *context) { mRefCount--; if (mRefCount == 0 && mDeleteStatus) { - mResourceManager->deleteProgram(mHandle); + mResourceManager->deleteProgram(context, mHandle); } } @@ -854,24 +1167,40 @@ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shade { int total = 0; - if (mData.mAttachedVertexShader) + if (mState.mAttachedComputeShader) { if (total < maxCount) { - shaders[total] = mData.mAttachedVertexShader->getHandle(); + shaders[total] = mState.mAttachedComputeShader->getHandle(); + total++; } + } - total++; + if (mState.mAttachedVertexShader) + { + if (total < maxCount) + { + shaders[total] = mState.mAttachedVertexShader->getHandle(); + total++; + } } - if (mData.mAttachedFragmentShader) + if (mState.mAttachedFragmentShader) { if (total < maxCount) { - shaders[total] = mData.mAttachedFragmentShader->getHandle(); + shaders[total] = mState.mAttachedFragmentShader->getHandle(); + total++; } + } - total++; + if (mState.mAttachedGeometryShader) + { + if (total < maxCount) + { + shaders[total] = mState.mAttachedGeometryShader->getHandle(); + total++; + } } if (count) @@ -882,24 +1211,21 @@ void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shade GLuint Program::getAttributeLocation(const std::string &name) const { - for (const sh::Attribute &attribute : mData.mAttributes) - { - if (attribute.name == name && attribute.staticUse) - { - return attribute.location; - } - } - - return static_cast(-1); + return mState.getAttributeLocation(name); } bool Program::isAttribLocationActive(size_t attribLocation) const { - ASSERT(attribLocation < mData.mActiveAttribLocationsMask.size()); - return mData.mActiveAttribLocationsMask[attribLocation]; + ASSERT(attribLocation < mState.mActiveAttribLocationsMask.size()); + return mState.mActiveAttribLocationsMask[attribLocation]; } -void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +void Program::getActiveAttribute(GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) const { if (!mLinked) { @@ -918,35 +1244,12 @@ void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, return; } - size_t attributeIndex = 0; - - for (const sh::Attribute &attribute : mData.mAttributes) - { - // Skip over inactive attributes - if (attribute.staticUse) - { - if (static_cast(index) == attributeIndex) - { - break; - } - attributeIndex++; - } - } - - ASSERT(index == attributeIndex && attributeIndex < mData.mAttributes.size()); - const sh::Attribute &attrib = mData.mAttributes[attributeIndex]; + ASSERT(index < mState.mAttributes.size()); + const sh::Attribute &attrib = mState.mAttributes[index]; if (bufsize > 0) { - const char *string = attrib.name.c_str(); - - strncpy(name, string, bufsize); - name[bufsize - 1] = '\0'; - - if (length) - { - *length = static_cast(strlen(name)); - } + CopyStringToBuffer(name, attrib.name, bufsize, length); } // Always a single 'type' instance @@ -961,14 +1264,7 @@ GLint Program::getActiveAttributeCount() const return 0; } - GLint count = 0; - - for (const sh::Attribute &attrib : mData.mAttributes) - { - count += (attrib.staticUse ? 1 : 0); - } - - return count; + return static_cast(mState.mAttributes.size()); } GLint Program::getActiveAttributeMaxLength() const @@ -980,30 +1276,105 @@ GLint Program::getActiveAttributeMaxLength() const size_t maxLength = 0; - for (const sh::Attribute &attrib : mData.mAttributes) + for (const sh::Attribute &attrib : mState.mAttributes) { - if (attrib.staticUse) - { - maxLength = std::max(attrib.name.length() + 1, maxLength); - } + maxLength = std::max(attrib.name.length() + 1, maxLength); } return static_cast(maxLength); } -GLint Program::getFragDataLocation(const std::string &name) const +GLuint Program::getInputResourceIndex(const GLchar *name) const +{ + return GetResourceIndexFromName(mState.mAttributes, std::string(name)); +} + +GLuint Program::getOutputResourceIndex(const GLchar *name) const +{ + return GetResourceIndexFromName(mState.mOutputVariables, std::string(name)); +} + +size_t Program::getOutputResourceCount() const +{ + return (mLinked ? mState.mOutputVariables.size() : 0); +} + +template +void Program::getResourceName(GLuint index, + const std::vector &resources, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const { - std::string baseName(name); - unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName); - for (auto outputPair : mData.mOutputVariables) + if (length) + { + *length = 0; + } + + if (!mLinked) { - const VariableLocation &outputVariable = outputPair.second; - if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) + if (bufSize > 0) { - return static_cast(outputPair.first); + name[0] = '\0'; } + return; } - return -1; + ASSERT(index < resources.size()); + const auto &resource = resources[index]; + + if (bufSize > 0) + { + CopyStringToBuffer(name, resource.name, bufSize, length); + } +} + +void Program::getInputResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mAttributes, bufSize, length, name); +} + +void Program::getOutputResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mOutputVariables, bufSize, length, name); +} + +void Program::getUniformResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mUniforms, bufSize, length, name); +} + +void Program::getBufferVariableResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const +{ + getResourceName(index, mState.mBufferVariables, bufSize, length, name); +} + +const sh::Attribute &Program::getInputResource(GLuint index) const +{ + ASSERT(index < mState.mAttributes.size()); + return mState.mAttributes[index]; +} + +const sh::OutputVariable &Program::getOutputResource(GLuint index) const +{ + ASSERT(index < mState.mOutputVariables.size()); + return mState.mOutputVariables[index]; +} + +GLint Program::getFragDataLocation(const std::string &name) const +{ + return GetVariableLocation(mState.mOutputVariables, mState.mOutputLocations, name); } void Program::getActiveUniform(GLuint index, @@ -1016,27 +1387,16 @@ void Program::getActiveUniform(GLuint index, if (mLinked) { // index must be smaller than getActiveUniformCount() - ASSERT(index < mData.mUniforms.size()); - const LinkedUniform &uniform = mData.mUniforms[index]; + ASSERT(index < mState.mUniforms.size()); + const LinkedUniform &uniform = mState.mUniforms[index]; if (bufsize > 0) { std::string string = uniform.name; - if (uniform.isArray()) - { - string += "[0]"; - } - - strncpy(name, string.c_str(), bufsize); - name[bufsize - 1] = '\0'; - - if (length) - { - *length = static_cast(strlen(name)); - } + CopyStringToBuffer(name, string, bufsize, length); } - *size = uniform.elementCount(); + *size = clampCast(uniform.getBasicTypeElementCount()); *type = uniform.type; } else @@ -1060,7 +1420,7 @@ GLint Program::getActiveUniformCount() const { if (mLinked) { - return static_cast(mData.mUniforms.size()); + return static_cast(mState.mUniforms.size()); } else { @@ -1068,13 +1428,18 @@ GLint Program::getActiveUniformCount() const } } +size_t Program::getActiveBufferVariableCount() const +{ + return mLinked ? mState.mBufferVariables.size() : 0; +} + GLint Program::getActiveUniformMaxLength() const { size_t maxLength = 0; if (mLinked) { - for (const LinkedUniform &uniform : mData.mUniforms) + for (const LinkedUniform &uniform : mState.mUniforms) { if (!uniform.name.empty()) { @@ -1091,189 +1456,249 @@ GLint Program::getActiveUniformMaxLength() const return static_cast(maxLength); } -GLint Program::getActiveUniformi(GLuint index, GLenum pname) const +bool Program::isValidUniformLocation(GLint location) const { - 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); - case GL_UNIFORM_SIZE: return static_cast(uniform.elementCount()); - case GL_UNIFORM_NAME_LENGTH: return static_cast(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); - case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; - case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; - case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; - case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; - case GL_UNIFORM_IS_ROW_MAJOR: return static_cast(uniform.blockInfo.isRowMajorMatrix); - default: - UNREACHABLE(); - break; - } - return 0; + ASSERT(angle::IsValueInRangeForNumericType(mState.mUniformLocations.size())); + return (location >= 0 && static_cast(location) < mState.mUniformLocations.size() && + mState.mUniformLocations[static_cast(location)].used()); } -bool Program::isValidUniformLocation(GLint location) const +const LinkedUniform &Program::getUniformByLocation(GLint location) const { - ASSERT(rx::IsIntegerCastSafe(mData.mUniformLocations.size())); - return (location >= 0 && static_cast(location) < mData.mUniformLocations.size()); + ASSERT(location >= 0 && static_cast(location) < mState.mUniformLocations.size()); + return mState.mUniforms[mState.getUniformIndexFromLocation(location)]; } -const LinkedUniform &Program::getUniformByLocation(GLint location) const +const VariableLocation &Program::getUniformLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast(location) < mState.mUniformLocations.size()); + return mState.mUniformLocations[location]; +} + +const std::vector &Program::getUniformLocations() const +{ + return mState.mUniformLocations; +} + +const LinkedUniform &Program::getUniformByIndex(GLuint index) const { - ASSERT(location >= 0 && static_cast(location) < mData.mUniformLocations.size()); - return mData.mUniforms[mData.mUniformLocations[location].index]; + ASSERT(index < static_cast(mState.mUniforms.size())); + return mState.mUniforms[index]; +} + +const BufferVariable &Program::getBufferVariableByIndex(GLuint index) const +{ + ASSERT(index < static_cast(mState.mBufferVariables.size())); + return mState.mBufferVariables[index]; } GLint Program::getUniformLocation(const std::string &name) const { - return mData.getUniformLocation(name); + return GetVariableLocation(mState.mUniforms, mState.mUniformLocations, name); } GLuint Program::getUniformIndex(const std::string &name) const { - return mData.getUniformIndex(name); + return mState.getUniformIndexFromName(name); } void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + mProgram->setUniform1fv(location, clampedCount, v); } void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2fv(location, clampedCount, v); } void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3fv(location, clampedCount, v); } void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4fv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4fv(location, clampedCount, v); } -void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) +Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + + mProgram->setUniform1iv(location, clampedCount, v); + + if (mState.isSamplerUniformIndex(locationInfo.index)) + { + updateSamplerUniform(locationInfo, clampedCount, v); + return SetUniformResult::SamplerChanged; + } + + return SetUniformResult::NoSamplerChange; } void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2iv(location, clampedCount, v); } void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3iv(location, clampedCount, v); } void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4iv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4iv(location, clampedCount, v); } void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 1, v); - mProgram->setUniform1uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v); + mProgram->setUniform1uiv(location, clampedCount, v); } void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 2, v); - mProgram->setUniform2uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 2, v); + mProgram->setUniform2uiv(location, clampedCount, v); } void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 3, v); - mProgram->setUniform3uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 3, v); + mProgram->setUniform3uiv(location, clampedCount, v); } void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - setUniformInternal(location, count * 4, v); - mProgram->setUniform4uiv(location, count, v); + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + GLsizei clampedCount = clampUniformCount(locationInfo, count, 4, v); + mProgram->setUniform4uiv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<2, 2>(location, count, transpose, v); + mProgram->setUniformMatrix2fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<3, 3>(location, count, transpose, v); + mProgram->setUniformMatrix3fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<4, 4>(location, count, transpose, v); + mProgram->setUniformMatrix4fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<2, 3>(location, count, transpose, v); + mProgram->setUniformMatrix2x3fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<2, 4>(location, count, transpose, v); + mProgram->setUniformMatrix2x4fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<3, 2>(location, count, transpose, v); + mProgram->setUniformMatrix3x2fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<3, 4>(location, count, transpose, v); + mProgram->setUniformMatrix3x4fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<4, 2>(location, count, transpose, v); + mProgram->setUniformMatrix4x2fv(location, clampedCount, 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); + GLsizei clampedCount = clampMatrixUniformCount<4, 3>(location, count, transpose, v); + mProgram->setUniformMatrix4x3fv(location, clampedCount, transpose, v); } -void Program::getUniformfv(GLint location, GLfloat *v) const +void Program::getUniformfv(const Context *context, GLint location, GLfloat *v) const { - getUniformInternal(location, v); -} + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; -void Program::getUniformiv(GLint location, GLint *v) const -{ - getUniformInternal(location, v); + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_FLOAT) + { + mProgram->getUniformfv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } } -void Program::getUniformuiv(GLint location, GLuint *v) const +void Program::getUniformiv(const Context *context, GLint location, GLint *v) const { - getUniformInternal(location, v); -} + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; + + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_INT || nativeType == GL_BOOL) + { + mProgram->getUniformiv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } +} + +void Program::getUniformuiv(const Context *context, GLint location, GLuint *v) const +{ + const auto &uniformLocation = mState.getUniformLocations()[location]; + const auto &uniform = mState.getUniforms()[uniformLocation.index]; + + GLenum nativeType = gl::VariableComponentType(uniform.type); + if (nativeType == GL_UNSIGNED_INT) + { + mProgram->getUniformuiv(context, location, v); + } + else + { + getUniformInternal(context, v, location, nativeType, + gl::VariableComponentCount(uniform.type)); + } +} void Program::flagForDeletion() { @@ -1291,7 +1716,7 @@ void Program::validate(const Caps &caps) if (mLinked) { - mValidated = (mProgram->validate(caps, &mInfoLog) == GL_TRUE); + mValidated = ConvertToBool(mProgram->validate(caps, &mInfoLog)); } else { @@ -1320,22 +1745,15 @@ bool Program::validateSamplers(InfoLog *infoLog, const 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. - for (unsigned int samplerIndex = mSamplerUniformRange.start; - samplerIndex < mSamplerUniformRange.end; ++samplerIndex) + for (const auto &samplerBinding : mState.mSamplerBindings) { - const LinkedUniform &uniform = mData.mUniforms[samplerIndex]; - ASSERT(uniform.isSampler()); - - if (!uniform.staticUse) + if (samplerBinding.unreferenced) continue; - const GLuint *dataPtr = reinterpret_cast(uniform.getDataPtrToElement(0)); - GLenum textureType = SamplerTypeToTextureType(uniform.type); + GLenum textureType = samplerBinding.textureType; - for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement) + for (GLuint textureUnit : samplerBinding.boundTextureUnits) { - GLuint textureUnit = dataPtr[arrayElement]; - if (textureUnit >= caps.maxCombinedTextureImageUnits) { if (infoLog) @@ -1382,70 +1800,34 @@ bool Program::isValidated() const GLuint Program::getActiveUniformBlockCount() const { - return static_cast(mData.mUniformBlocks.size()); + return static_cast(mState.mUniformBlocks.size()); } -void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +GLuint Program::getActiveAtomicCounterBufferCount() const { - ASSERT(uniformBlockIndex < - mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() - - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; - - if (bufSize > 0) - { - std::string string = uniformBlock.name; - - if (uniformBlock.isArray) - { - string += ArrayString(uniformBlock.arrayElement); - } - - strncpy(uniformBlockName, string.c_str(), bufSize); - uniformBlockName[bufSize - 1] = '\0'; + return static_cast(mState.mAtomicCounterBuffers.size()); +} - if (length) - { - *length = static_cast(strlen(uniformBlockName)); - } - } +GLuint Program::getActiveShaderStorageBlockCount() const +{ + return static_cast(mState.mShaderStorageBlocks.size()); } -void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +void Program::getActiveUniformBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const { - ASSERT(uniformBlockIndex < - mData.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + GetInterfaceBlockName(blockIndex, mState.mUniformBlocks, bufSize, length, blockName); +} - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; +void Program::getActiveShaderStorageBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const +{ - switch (pname) - { - case GL_UNIFORM_BLOCK_DATA_SIZE: - *params = static_cast(uniformBlock.dataSize); - break; - case GL_UNIFORM_BLOCK_NAME_LENGTH: - *params = - static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArray ? 3 : 0)); - break; - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: - *params = static_cast(uniformBlock.memberUniformIndexes.size()); - break; - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: - { - for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) - { - params[blockMemberIndex] = static_cast(uniformBlock.memberUniformIndexes[blockMemberIndex]); - } - } - break; - case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: - *params = static_cast(uniformBlock.vertexStaticUse); - break; - case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - *params = static_cast(uniformBlock.fragmentStaticUse); - break; - default: UNREACHABLE(); - } + GetInterfaceBlockName(blockIndex, mState.mShaderStorageBlocks, bufSize, length, blockName); } GLint Program::getActiveUniformBlockMaxLength() const @@ -1454,18 +1836,14 @@ GLint Program::getActiveUniformBlockMaxLength() const if (mLinked) { - unsigned int numUniformBlocks = static_cast(mData.mUniformBlocks.size()); + unsigned int numUniformBlocks = static_cast(mState.mUniformBlocks.size()); for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) { - const UniformBlock &uniformBlock = mData.mUniformBlocks[uniformBlockIndex]; + const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex]; if (!uniformBlock.name.empty()) { - const int length = static_cast(uniformBlock.name.length()) + 1; - - // Counting in "[0]". - const int arrayLength = (uniformBlock.isArray ? 3 : 0); - - maxLength = std::max(length + arrayLength, maxLength); + int length = static_cast(uniformBlock.nameWithArrayIndex().length()); + maxLength = std::max(length + 1, maxLength); } } } @@ -1475,87 +1853,77 @@ GLint Program::getActiveUniformBlockMaxLength() const GLuint Program::getUniformBlockIndex(const std::string &name) const { - size_t subscript = GL_INVALID_INDEX; - std::string baseName = gl::ParseUniformName(name, &subscript); + return GetInterfaceBlockIndex(mState.mUniformBlocks, name); +} - 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; - } - } - } +GLuint Program::getShaderStorageBlockIndex(const std::string &name) const +{ + return GetInterfaceBlockIndex(mState.mShaderStorageBlocks, name); +} - return GL_INVALID_INDEX; +const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const +{ + ASSERT(index < static_cast(mState.mUniformBlocks.size())); + return mState.mUniformBlocks[index]; } -const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const +const InterfaceBlock &Program::getShaderStorageBlockByIndex(GLuint index) const { - ASSERT(index < static_cast(mData.mUniformBlocks.size())); - return mData.mUniformBlocks[index]; + ASSERT(index < static_cast(mState.mShaderStorageBlocks.size())); + return mState.mShaderStorageBlocks[index]; } void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) { - mData.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; + mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding; + mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0); mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding); } GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const { - return mData.getUniformBlockBinding(uniformBlockIndex); + return mState.getUniformBlockBinding(uniformBlockIndex); } -void Program::resetUniformBlockBindings() +GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const { - for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) - { - mData.mUniformBlockBindings[blockId] = 0; - } - mData.mActiveUniformBlockBindings.reset(); + return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex); } void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) { - mData.mTransformFeedbackVaryingNames.resize(count); + mState.mTransformFeedbackVaryingNames.resize(count); for (GLsizei i = 0; i < count; i++) { - mData.mTransformFeedbackVaryingNames[i] = varyings[i]; + mState.mTransformFeedbackVaryingNames[i] = varyings[i]; } - mData.mTransformFeedbackBufferMode = bufferMode; + mState.mTransformFeedbackBufferMode = bufferMode; } void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const { if (mLinked) { - ASSERT(index < mData.mTransformFeedbackVaryingVars.size()); - const sh::Varying &varying = mData.mTransformFeedbackVaryingVars[index]; - GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varying.name.length())); + ASSERT(index < mState.mLinkedTransformFeedbackVaryings.size()); + const auto &var = mState.mLinkedTransformFeedbackVaryings[index]; + std::string varName = var.nameWithArrayIndex(); + GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varName.length())); if (length) { *length = lastNameIdx; } if (size) { - *size = varying.elementCount(); + *size = var.size(); } if (type) { - *type = varying.type; + *type = var.type; } if (name) { - memcpy(name, varying.name.c_str(), lastNameIdx); + memcpy(name, varName.c_str(), lastNameIdx); name[lastNameIdx] = '\0'; } } @@ -1565,7 +1933,7 @@ GLsizei Program::getTransformFeedbackVaryingCount() const { if (mLinked) { - return static_cast(mData.mTransformFeedbackVaryingVars.size()); + return static_cast(mState.mLinkedTransformFeedbackVaryings.size()); } else { @@ -1578,9 +1946,10 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const if (mLinked) { GLsizei maxSize = 0; - for (const sh::Varying &varying : mData.mTransformFeedbackVaryingVars) + for (const auto &var : mState.mLinkedTransformFeedbackVaryings) { - maxSize = std::max(maxSize, static_cast(varying.name.length() + 1)); + maxSize = + std::max(maxSize, static_cast(var.nameWithArrayIndex().length() + 1)); } return maxSize; @@ -1593,16 +1962,20 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const GLenum Program::getTransformFeedbackBufferMode() const { - return mData.mTransformFeedbackBufferMode; + return mState.mTransformFeedbackBufferMode; } -// static -bool Program::linkVaryings(InfoLog &infoLog, - const Shader *vertexShader, - const Shader *fragmentShader) +bool Program::linkVaryings(const Context *context, InfoLog &infoLog) const { - const std::vector &vertexVaryings = vertexShader->getVaryings(); - const std::vector &fragmentVaryings = fragmentShader->getVaryings(); + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + + ASSERT(vertexShader->getShaderVersion(context) == fragmentShader->getShaderVersion(context)); + + const std::vector &vertexVaryings = vertexShader->getOutputVaryings(context); + const std::vector &fragmentVaryings = fragmentShader->getInputVaryings(context); + + std::map staticFragmentInputLocations; for (const sh::Varying &output : fragmentVaryings) { @@ -1619,7 +1992,8 @@ bool Program::linkVaryings(InfoLog &infoLog, if (output.name == input.name) { ASSERT(!input.isBuiltIn()); - if (!linkValidateVaryings(infoLog, output.name, input, output)) + if (!linkValidateVaryings(infoLog, output.name, input, output, + vertexShader->getShaderVersion(context))) { return false; } @@ -1635,6 +2009,34 @@ bool Program::linkVaryings(InfoLog &infoLog, infoLog << "Fragment varying " << output.name << " does not match any vertex varying"; return false; } + + // Check for aliased path rendering input bindings (if any). + // If more than one binding refer statically to the same + // location the link must fail. + + if (!output.staticUse) + continue; + + const auto inputBinding = mFragmentInputBindings.getBinding(output.name); + if (inputBinding == -1) + continue; + + const auto it = staticFragmentInputLocations.find(inputBinding); + if (it == std::end(staticFragmentInputLocations)) + { + staticFragmentInputLocations.insert(std::make_pair(inputBinding, output.name)); + } + else + { + infoLog << "Binding for fragment input " << output.name << " conflicts with " + << it->second; + return false; + } + } + + if (!linkValidateBuiltInVaryings(context, infoLog)) + { + return false; } // TODO(jmadill): verify no unmatched vertex varyings? @@ -1642,67 +2044,135 @@ bool Program::linkVaryings(InfoLog &infoLog, return true; } -bool Program::linkUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) +bool Program::linkUniforms(const Context *context, + InfoLog &infoLog, + const Bindings &uniformLocationBindings) +{ + UniformLinker linker(mState); + if (!linker.link(context, infoLog, uniformLocationBindings)) + { + return false; + } + + linker.getResults(&mState.mUniforms, &mState.mUniformLocations); + + linkSamplerAndImageBindings(); + + if (!linkAtomicCounterBuffers()) + { + return false; + } + + return true; +} + +void Program::linkSamplerAndImageBindings() { - const std::vector &vertexUniforms = mData.mAttachedVertexShader->getUniforms(); - const std::vector &fragmentUniforms = mData.mAttachedFragmentShader->getUniforms(); + unsigned int high = static_cast(mState.mUniforms.size()); + unsigned int low = high; + + for (auto counterIter = mState.mUniforms.rbegin(); + counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter) + { + --low; + } + + mState.mAtomicCounterUniformRange = RangeUI(low, high); - // Check that uniforms defined in the vertex and fragment shaders are identical - std::map linkedUniforms; + high = low; - for (const sh::Uniform &vertexUniform : vertexUniforms) + for (auto imageIter = mState.mUniforms.rbegin(); + imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter) { - linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform); + --low; } - for (const sh::Uniform &fragmentUniform : fragmentUniforms) + mState.mImageUniformRange = RangeUI(low, high); + + // If uniform is a image type, insert it into the mImageBindings array. + for (unsigned int imageIndex : mState.mImageUniformRange) { - auto entry = linkedUniforms.find(fragmentUniform.name); - if (entry != linkedUniforms.end()) + // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands + // cannot load values into a uniform defined as an image. if declare without a + // binding qualifier, any uniform image variable (include all elements of + // unbound image array) shoud be bound to unit zero. + auto &imageUniform = mState.mUniforms[imageIndex]; + if (imageUniform.binding == -1) { - LinkedUniform *vertexUniform = &entry->second; - const std::string &uniformName = "uniform '" + vertexUniform->name + "'"; - if (!linkValidateUniforms(infoLog, uniformName, *vertexUniform, fragmentUniform)) - { - return false; - } + mState.mImageBindings.emplace_back( + ImageBinding(imageUniform.getBasicTypeElementCount())); + } + else + { + mState.mImageBindings.emplace_back( + ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount())); } } - // 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)) + high = low; + + for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length(); + samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter) { - return false; + --low; } - indexUniforms(); + mState.mSamplerUniformRange = RangeUI(low, high); - return true; + // If uniform is a sampler type, insert it into the mSamplerBindings array. + for (unsigned int samplerIndex : mState.mSamplerUniformRange) + { + const auto &samplerUniform = mState.mUniforms[samplerIndex]; + GLenum textureType = SamplerTypeToTextureType(samplerUniform.type); + mState.mSamplerBindings.emplace_back( + SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false)); + } } -void Program::indexUniforms() +bool Program::linkAtomicCounterBuffers() { - for (size_t uniformIndex = 0; uniformIndex < mData.mUniforms.size(); uniformIndex++) + for (unsigned int index : mState.mAtomicCounterUniformRange) { - const gl::LinkedUniform &uniform = mData.mUniforms[uniformIndex]; - - for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++) + auto &uniform = mState.mUniforms[index]; + bool found = false; + for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size(); + ++bufferIndex) { - if (!uniform.isBuiltIn()) + auto &buffer = mState.mAtomicCounterBuffers[bufferIndex]; + if (buffer.binding == uniform.binding) { - // Assign in-order uniform locations - mData.mUniformLocations.push_back(gl::VariableLocation( - uniform.name, arrayIndex, static_cast(uniformIndex))); + buffer.memberIndexes.push_back(index); + uniform.bufferIndex = bufferIndex; + found = true; + buffer.unionReferencesWith(uniform); + break; } } + if (!found) + { + AtomicCounterBuffer atomicCounterBuffer; + atomicCounterBuffer.binding = uniform.binding; + atomicCounterBuffer.memberIndexes.push_back(index); + atomicCounterBuffer.unionReferencesWith(uniform); + mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer); + uniform.bufferIndex = static_cast(mState.mAtomicCounterBuffers.size() - 1); + } } + // TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against + // gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers. + + return true; } -bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, + const std::string &uniformName, + const sh::InterfaceBlockField &vertexUniform, + const sh::InterfaceBlockField &fragmentUniform, + bool webglCompatibility) { - // We don't validate precision on UBO fields. See resolution of Khronos bug 10287. - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false)) + // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287. + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, + webglCompatibility)) { return false; } @@ -1716,32 +2186,34 @@ bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::stri return true; } -// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices -bool Program::linkAttributes(const gl::Data &data, - InfoLog &infoLog, - const AttributeBindings &attributeBindings, - const Shader *vertexShader) +// Assigns locations to all attributes from the bindings and program locations. +bool Program::linkAttributes(const Context *context, InfoLog &infoLog) { + const ContextState &data = context->getContextState(); + auto *vertexShader = mState.getAttachedVertexShader(); + unsigned int usedLocations = 0; - mData.mAttributes = vertexShader->getActiveAttributes(); - GLuint maxAttribs = data.caps->maxVertexAttributes; + mState.mAttributes = vertexShader->getActiveAttributes(context); + GLuint maxAttribs = data.getCaps().maxVertexAttributes; // TODO(jmadill): handle aliasing robustly - if (mData.mAttributes.size() > maxAttribs) + if (mState.mAttributes.size() > maxAttribs) { infoLog << "Too many vertex attributes."; return false; } - std::vector usedAttribMap(data.caps->maxVertexAttributes, nullptr); + std::vector usedAttribMap(maxAttribs, nullptr); // Link attributes that have a binding location - for (sh::Attribute &attribute : mData.mAttributes) + for (sh::Attribute &attribute : mState.mAttributes) { - // TODO(jmadill): do staticUse filtering step here, or not at all - ASSERT(attribute.staticUse); + // GLSL ES 3.10 January 2016 section 4.3.4: Vertex shader inputs can't be arrays or + // structures, so we don't need to worry about adjusting their names or generating entries + // for each member/element (unlike uniforms for example). + ASSERT(!attribute.isArray() && !attribute.isStruct()); - int bindingLocation = attributeBindings.getAttributeBinding(attribute.name); + int bindingLocation = mAttributeBindings.getBinding(attribute.name); if (attribute.location == -1 && bindingLocation != -1) { attribute.location = bindingLocation; @@ -1788,10 +2260,8 @@ bool Program::linkAttributes(const gl::Data &data, } // Link attributes that don't have a binding location - for (sh::Attribute &attribute : mData.mAttributes) + for (sh::Attribute &attribute : mState.mAttributes) { - ASSERT(attribute.staticUse); - // Not set by glBindAttribLocation or by location layout qualifier if (attribute.location == -1) { @@ -1808,82 +2278,150 @@ bool Program::linkAttributes(const gl::Data &data, } } - for (const sh::Attribute &attribute : mData.mAttributes) + for (const sh::Attribute &attribute : mState.mAttributes) { - ASSERT(attribute.staticUse); ASSERT(attribute.location != -1); - int regs = VariableRegisterCount(attribute.type); + unsigned int regs = static_cast(VariableRegisterCount(attribute.type)); - for (int r = 0; r < regs; r++) + for (unsigned int r = 0; r < regs; r++) { - mData.mActiveAttribLocationsMask.set(attribute.location + r); + unsigned int location = static_cast(attribute.location) + r; + mState.mActiveAttribLocationsMask.set(location); + mState.mMaxActiveAttribLocation = + std::max(mState.mMaxActiveAttribLocation, location + 1); } } return true; } -bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps) +bool Program::validateVertexAndFragmentInterfaceBlocks( + const std::vector &vertexInterfaceBlocks, + const std::vector &fragmentInterfaceBlocks, + InfoLog &infoLog, + bool webglCompatibility) const { - 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; + typedef std::map InterfaceBlockMap; + InterfaceBlockMap linkedInterfaceBlocks; - GLuint vertexBlockCount = 0; for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks) { - linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } - // Note: shared and std140 layouts are always considered active - if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks) + { + auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedInterfaceBlocks.end()) { - if (++vertexBlockCount > caps.maxVertexUniformBlocks) + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock, + webglCompatibility)) { - infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (" - << caps.maxVertexUniformBlocks << ")"; return false; } } + // TODO(jiajia.qin@intel.com): Add + // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation. } + return true; +} - GLuint fragmentBlockCount = 0; - for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks) +bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog) +{ + const auto &caps = context->getCaps(); + + if (mState.mAttachedComputeShader) { - auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); - if (entry != linkedUniformBlocks.end()) + Shader &computeShader = *mState.mAttachedComputeShader; + const auto &computeUniformBlocks = computeShader.getUniformBlocks(context); + + if (!validateInterfaceBlocksCount( + caps.maxComputeUniformBlocks, computeUniformBlocks, + "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (", + infoLog)) { - const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; - if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) - { - return false; - } + return false; } - // Note: shared and std140 layouts are always considered active - if (fragmentInterfaceBlock.staticUse || - fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context); + if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks, + computeShaderStorageBlocks, + "Compute shader shader storage block count exceeds " + "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (", + infoLog)) { - if (++fragmentBlockCount > caps.maxFragmentUniformBlocks) - { - infoLog - << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (" - << caps.maxFragmentUniformBlocks << ")"; - return false; - } + return false; } + return true; + } + + Shader &vertexShader = *mState.mAttachedVertexShader; + Shader &fragmentShader = *mState.mAttachedFragmentShader; + + const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context); + const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context); + + if (!validateInterfaceBlocksCount( + caps.maxVertexUniformBlocks, vertexUniformBlocks, + "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog)) + { + return false; + } + if (!validateInterfaceBlocksCount( + caps.maxFragmentUniformBlocks, fragmentUniformBlocks, + "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (", + infoLog)) + { + + return false; } + bool webglCompatibility = context->getExtensions().webglCompatibility; + if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks, + infoLog, webglCompatibility)) + { + return false; + } + + if (context->getClientVersion() >= Version(3, 1)) + { + const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context); + const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context); + + if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks, + vertexShaderStorageBlocks, + "Vertex shader shader storage block count exceeds " + "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (", + infoLog)) + { + return false; + } + if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks, + fragmentShaderStorageBlocks, + "Fragment shader shader storage block count exceeds " + "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (", + infoLog)) + { + + return false; + } + + if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks, + fragmentShaderStorageBlocks, infoLog, + webglCompatibility)) + { + return false; + } + } return true; } -bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, - const sh::InterfaceBlock &fragmentInterfaceBlock) +bool Program::areMatchingInterfaceBlocks(InfoLog &infoLog, + const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock, + bool webglCompatibility) const { const char* blockName = vertexInterfaceBlock.name.c_str(); // validate blocks for the same member types @@ -1899,7 +2437,9 @@ bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::Interfa << "' between vertex and fragment shaders"; return false; } - if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || + vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout || + vertexInterfaceBlock.binding != fragmentInterfaceBlock.binding) { infoLog << "Layout qualifiers differ for interface block '" << blockName << "' between vertex and fragment shaders"; @@ -1920,7 +2460,8 @@ bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::Interfa return false; } std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; - if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) + if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember, + webglCompatibility)) { return false; } @@ -1936,7 +2477,7 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var infoLog << "Types for " << variableName << " differ between vertex and fragment shaders"; return false; } - if (vertexVariable.arraySize != fragmentVariable.arraySize) + if (vertexVariable.arraySizes != fragmentVariable.arraySizes) { infoLog << "Array sizes for " << variableName << " differ between vertex and fragment shaders"; return false; @@ -1946,6 +2487,12 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var infoLog << "Precisions for " << variableName << " differ between vertex and fragment shaders"; return false; } + if (vertexVariable.structName != fragmentVariable.structName) + { + infoLog << "Structure names for " << variableName + << " differ between vertex and fragment shaders"; + return false; + } if (vertexVariable.fields.size() != fragmentVariable.fields.size()) { @@ -1979,52 +2526,125 @@ bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &var return true; } -bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) +bool Program::linkValidateVaryings(InfoLog &infoLog, + const std::string &varyingName, + const sh::Varying &vertexVarying, + const sh::Varying &fragmentVarying, + int shaderVersion) { -#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED - const bool validatePrecision = true; -#else - const bool validatePrecision = false; -#endif + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + { + return false; + } - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision)) + if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) { + infoLog << "Interpolation types for " << varyingName + << " differ between vertex and fragment shaders."; + return false; + } + + if (shaderVersion == 100 && vertexVarying.isInvariant != fragmentVarying.isInvariant) + { + infoLog << "Invariance for " << varyingName + << " differs between vertex and fragment shaders."; return false; } return true; } -bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +bool Program::linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const { - if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + Shader *vertexShader = mState.mAttachedVertexShader; + Shader *fragmentShader = mState.mAttachedFragmentShader; + const auto &vertexVaryings = vertexShader->getOutputVaryings(context); + const auto &fragmentVaryings = fragmentShader->getInputVaryings(context); + int shaderVersion = vertexShader->getShaderVersion(context); + + if (shaderVersion != 100) { - return false; + // Only ESSL 1.0 has restrictions on matching input and output invariance + return true; } - if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) + bool glPositionIsInvariant = false; + bool glPointSizeIsInvariant = false; + bool glFragCoordIsInvariant = false; + bool glPointCoordIsInvariant = false; + + for (const sh::Varying &varying : vertexVaryings) + { + if (!varying.isBuiltIn()) + { + continue; + } + if (varying.name.compare("gl_Position") == 0) + { + glPositionIsInvariant = varying.isInvariant; + } + else if (varying.name.compare("gl_PointSize") == 0) + { + glPointSizeIsInvariant = varying.isInvariant; + } + } + + for (const sh::Varying &varying : fragmentVaryings) + { + if (!varying.isBuiltIn()) + { + continue; + } + if (varying.name.compare("gl_FragCoord") == 0) + { + glFragCoordIsInvariant = varying.isInvariant; + } + else if (varying.name.compare("gl_PointCoord") == 0) + { + glPointCoordIsInvariant = varying.isInvariant; + } + } + + // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation, + // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842. + // Not requiring invariance to match is supported by: + // dEQP, WebGL CTS, Nexus 5X GLES + if (glFragCoordIsInvariant && !glPositionIsInvariant) + { + infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is " + "declared invariant."; + return false; + } + if (glPointCoordIsInvariant && !glPointSizeIsInvariant) { - infoLog << "Interpolation types for " << varyingName << " differ between vertex and fragment shaders"; + infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is " + "declared invariant."; return false; } return true; } -bool Program::linkValidateTransformFeedback(InfoLog &infoLog, - const std::vector &varyings, +bool Program::linkValidateTransformFeedback(const gl::Context *context, + InfoLog &infoLog, + const Program::MergedVaryings &varyings, const Caps &caps) const { size_t totalComponents = 0; std::set uniqueNames; - for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames) + for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) { bool found = false; - for (const sh::Varying *varying : varyings) + std::vector subscripts; + std::string baseName = ParseResourceName(tfVaryingName, &subscripts); + + for (const auto &ref : varyings) { - if (tfVaryingName == varying->name) + const sh::Varying *varying = ref.second.get(); + + if (baseName == varying->name) { if (uniqueNames.count(tfVaryingName) > 0) { @@ -2032,17 +2652,33 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, << tfVaryingName << ")."; return false; } - uniqueNames.insert(tfVaryingName); - - if (varying->isArray()) + if (context->getClientVersion() >= Version(3, 1)) + { + if (IncludeSameArrayElement(uniqueNames, tfVaryingName)) + { + infoLog + << "Two transform feedback varyings include the same array element (" + << tfVaryingName << ")."; + return false; + } + } + else if (varying->isArray()) { infoLog << "Capture of arrays is undefined and not supported."; return false; } + uniqueNames.insert(tfVaryingName); + // TODO(jmadill): Investigate implementation limits on D3D11 - size_t componentCount = gl::VariableComponentCount(varying->type); - if (mData.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + + // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays. + ASSERT(!varying->isArrayOfArrays()); + size_t elementCount = + ((varying->isArray() && subscripts.empty()) ? varying->getOutermostArraySize() + : 1); + size_t componentCount = VariableComponentCount(varying->type) * elementCount; + if (mState.mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && componentCount > caps.maxTransformFeedbackSeparateComponents) { infoLog << "Transform feedback varying's " << varying->name << " components (" @@ -2056,19 +2692,21 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, break; } } - - if (tfVaryingName.find('[') != std::string::npos) + if (context->getClientVersion() < Version(3, 1) && + 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 (!found) + { + infoLog << "Transform feedback varying " << tfVaryingName + << " does not exist in the vertex shader."; + return false; + } } - if (mData.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && + if (mState.mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents) { infoLog << "Transform feedback varying total components (" << totalComponents @@ -2080,454 +2718,349 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, return true; } -void Program::gatherTransformFeedbackVaryings(const std::vector &varyings) +bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const { - // Gather the linked varyings that are used for transform feedback, they should all exist. - mData.mTransformFeedbackVaryingVars.clear(); - for (const std::string &tfVaryingName : mData.mTransformFeedbackVaryingNames) + const std::vector &vertexUniforms = + mState.mAttachedVertexShader->getUniforms(context); + const std::vector &fragmentUniforms = + mState.mAttachedFragmentShader->getUniforms(context); + const std::vector &attributes = + mState.mAttachedVertexShader->getActiveAttributes(context); + for (const auto &attrib : attributes) { - for (const sh::Varying *varying : varyings) + for (const auto &uniform : vertexUniforms) { - if (tfVaryingName == varying->name) + if (uniform.name == attrib.name) { - mData.mTransformFeedbackVaryingVars.push_back(*varying); - break; + infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name; + return false; + } + } + for (const auto &uniform : fragmentUniforms) + { + if (uniform.name == attrib.name) + { + infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name; + return false; } } } + return true; } -std::vector Program::getMergedVaryings() const +void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings) { - std::set uniqueNames; - std::vector varyings; - - for (const sh::Varying &varying : mData.mAttachedVertexShader->getVaryings()) + // Gather the linked varyings that are used for transform feedback, they should all exist. + mState.mLinkedTransformFeedbackVaryings.clear(); + for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) { - if (uniqueNames.count(varying.name) == 0) + std::vector subscripts; + std::string baseName = ParseResourceName(tfVaryingName, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) { - uniqueNames.insert(varying.name); - varyings.push_back(&varying); + subscript = subscripts.back(); } - } - - for (const sh::Varying &varying : mData.mAttachedFragmentShader->getVaryings()) - { - if (uniqueNames.count(varying.name) == 0) + for (const auto &ref : varyings) { - uniqueNames.insert(varying.name); - varyings.push_back(&varying); + const sh::Varying *varying = ref.second.get(); + if (baseName == varying->name) + { + mState.mLinkedTransformFeedbackVaryings.emplace_back( + *varying, static_cast(subscript)); + break; + } } } - - return varyings; } -void Program::linkOutputVariables() +Program::MergedVaryings Program::getMergedVaryings(const Context *context) const { - const Shader *fragmentShader = mData.mAttachedFragmentShader; - ASSERT(fragmentShader != nullptr); + MergedVaryings merged; - // 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++) + for (const sh::Varying &varying : mState.mAttachedVertexShader->getOutputVaryings(context)) { - 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); - } + merged[varying.name].vertex = &varying; } -} - -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()) + for (const sh::Varying &varying : mState.mAttachedFragmentShader->getInputVaryings(context)) { - if (uniform.staticUse) - { - vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms); - } + merged[varying.name].fragment = &varying; } - if (vsCounts.vectorCount > caps.maxVertexUniformVectors) - { - infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (" - << caps.maxVertexUniformVectors << ")."; - return false; - } + return merged; +} - 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; +void Program::linkOutputVariables(const Context *context) +{ + Shader *fragmentShader = mState.mAttachedFragmentShader; + ASSERT(fragmentShader != nullptr); + + ASSERT(mState.mOutputVariableTypes.empty()); + ASSERT(mState.mActiveOutputVariables.none()); - for (const sh::Uniform &uniform : fragmentShader->getUniforms()) + // Gather output variable types + for (const auto &outputVariable : fragmentShader->getActiveOutputVariables(context)) { - if (uniform.staticUse) + if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" && + outputVariable.name != "gl_FragData") { - fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms); + continue; } - } - - 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; + unsigned int baseLocation = + (outputVariable.location == -1 ? 0u + : static_cast(outputVariable.location)); - if (uniform.isStruct()) - { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + unsigned int elementCount = outputVariable.getBasicTypeElementCount(); + for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++) { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + const unsigned int location = baseLocation + elementIndex; + if (location >= mState.mOutputVariableTypes.size()) { - const sh::ShaderVariable &field = uniform.fields[fieldIndex]; - const std::string &fieldFullName = (fullName + elementString + "." + field.name); - - vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms); + mState.mOutputVariableTypes.resize(location + 1, GL_NONE); } + ASSERT(location < mState.mActiveOutputVariables.size()); + mState.mActiveOutputVariables.set(location); + mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type); } - - return vectorAndSamplerCount; } - // Not a struct - bool isSampler = IsSamplerType(uniform.type); - if (!UniformInList(mData.getUniforms(), fullName) && !UniformInList(*samplerUniforms, fullName)) + // Skip this step for GLES2 shaders. + if (fragmentShader->getShaderVersion(context) == 100) + return; + + mState.mOutputVariables = fragmentShader->getActiveOutputVariables(context); + // TODO(jmadill): any caps validation here? + + for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size(); + outputVariableIndex++) { - gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, - uniform.arraySize, -1, - sh::BlockMemberInfo::getDefaultBlockInfo()); - linkedUniform.staticUse = true; + const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex]; - // Store sampler uniforms separately, so we'll append them to the end of the list. - if (isSampler) - { - samplerUniforms->push_back(linkedUniform); - } - else + if (outputVariable.isArray()) { - mData.mUniforms.push_back(linkedUniform); + // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active + // Resources and including [0] at the end of array variable names. + mState.mOutputVariables[outputVariableIndex].name += "[0]"; + mState.mOutputVariables[outputVariableIndex].mappedName += "[0]"; } - } - - 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) + // Don't store outputs for gl_FragDepth, gl_FragColor, etc. + if (outputVariable.isBuiltIn()) 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; + // Since multiple output locations must be specified, use 0 for non-specified locations. + unsigned int baseLocation = + (outputVariable.location == -1 ? 0u + : static_cast(outputVariable.location)); - if (visitedList.count(fragmentBlock.name) > 0) + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + unsigned int elementCount = outputVariable.getBasicTypeElementCount(); + for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++) { - for (gl::UniformBlock &block : mData.mUniformBlocks) + const unsigned int location = baseLocation + elementIndex; + if (location >= mState.mOutputLocations.size()) { - if (block.name == fragmentBlock.name) - { - block.fragmentStaticUse = fragmentBlock.staticUse; - } + mState.mOutputLocations.resize(location + 1); + } + ASSERT(!mState.mOutputLocations.at(location).used()); + if (outputVariable.isArray()) + { + mState.mOutputLocations[location] = + VariableLocation(elementIndex, outputVariableIndex); + } + else + { + VariableLocation locationInfo; + locationInfo.index = outputVariableIndex; + mState.mOutputLocations[location] = locationInfo; } - - continue; } - - defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER); - visitedList.insert(fragmentBlock.name); } } -template -void Program::defineUniformBlockMembers(const std::vector &fields, - const std::string &prefix, - int blockIndex) +void Program::setUniformValuesFromBindingQualifiers() { - for (const VarT &field : fields) + for (unsigned int samplerIndex : mState.mSamplerUniformRange) { - const std::string &fullName = (prefix.empty() ? field.name : prefix + "." + field.name); - - if (field.isStruct()) + const auto &samplerUniform = mState.mUniforms[samplerIndex]; + if (samplerUniform.binding != -1) { - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + GLint location = getUniformLocation(samplerUniform.name); + ASSERT(location != -1); + std::vector boundTextureUnits; + for (unsigned int elementIndex = 0; + elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex) { - const std::string uniformElementName = - fullName + (field.isArray() ? ArrayString(arrayElement) : ""); - defineUniformBlockMembers(field.fields, uniformElementName, blockIndex); + boundTextureUnits.push_back(samplerUniform.binding + elementIndex); } - } - 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); + setUniform1iv(location, static_cast(boundTextureUnits.size()), + boundTextureUnits.data()); } } } -void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType) +void Program::gatherAtomicCounterBuffers() { - 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)) + for (unsigned int index : mState.mAtomicCounterUniformRange) { - return; + auto &uniform = mState.mUniforms[index]; + uniform.blockInfo.offset = uniform.offset; + uniform.blockInfo.arrayStride = (uniform.isArray() ? 4 : 0); + uniform.blockInfo.matrixStride = 0; + uniform.blockInfo.isRowMajorMatrix = false; } - // 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(); + // TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer. +} - std::vector blockUniformIndexes; - for (size_t blockUniformIndex = firstBlockUniformIndex; - blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex) +void Program::initInterfaceBlockBindings() +{ + // Set initial bindings from shader. + for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++) { - blockUniformIndexes.push_back(static_cast(blockUniformIndex)); + InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex]; + bindUniformBlock(blockIndex, uniformBlock.binding); } +} - 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; - } +void Program::updateSamplerUniform(const VariableLocation &locationInfo, + GLsizei clampedCount, + const GLint *v) +{ + ASSERT(mState.isSamplerUniformIndex(locationInfo.index)); + GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index); + std::vector *boundTextureUnits = + &mState.mSamplerBindings[samplerIndex].boundTextureUnits; - ASSERT(blockElementSize == blockSize); - block.dataSize = static_cast(blockElementSize); - mData.mUniformBlocks.push_back(block); - } - } - else - { - UniformBlock block(interfaceBlock.name, false, 0); - block.memberUniformIndexes = blockUniformIndexes; + std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex); - 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); - } + // Invalidate the validation cache. + mCachedValidateSamplersResult.reset(); } template -void Program::setUniformInternal(GLint location, GLsizei count, const T *v) +GLsizei Program::clampUniformCount(const VariableLocation &locationInfo, + GLsizei count, + int vectorSize, + const T *v) { - const VariableLocation &locationInfo = mData.mUniformLocations[location]; - LinkedUniform *linkedUniform = &mData.mUniforms[locationInfo.index]; - uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element); + if (count == 1) + return 1; + + const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index]; + + // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array + // element index used, as reported by GetActiveUniform, will be ignored by the GL." + unsigned int remainingElements = + linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex; + GLsizei maxElementCount = + static_cast(remainingElements * linkedUniform.getElementComponents()); - if (VariableComponentType(linkedUniform->type) == GL_BOOL) + if (count * vectorSize > maxElementCount) { - // 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); - } + return maxElementCount / vectorSize; } - 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); - } + return count; } template -void Program::setMatrixUniformInternal(GLint location, - GLsizei count, - GLboolean transpose, - const T *v) +GLsizei Program::clampMatrixUniformCount(GLint location, + GLsizei count, + GLboolean transpose, + const T *v) { + const VariableLocation &locationInfo = mState.mUniformLocations[location]; + if (!transpose) { - setUniformInternal(location, count * cols * rows, v); - return; + return clampUniformCount(locationInfo, count, cols * rows, v); } - // 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; + const LinkedUniform &linkedUniform = mState.mUniforms[locationInfo.index]; - 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]; - } - } - } + // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array + // element index used, as reported by GetActiveUniform, will be ignored by the GL." + unsigned int remainingElements = + linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex; + return std::min(count, static_cast(remainingElements)); } +// Driver differences mean that doing the uniform value cast ourselves gives consistent results. +// EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT. template -void Program::getUniformInternal(GLint location, DestT *dataOut) const +void Program::getUniformInternal(const Context *context, + DestT *dataOut, + GLint location, + GLenum nativeType, + int components) 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); - - switch (componentType) + switch (nativeType) { + case GL_BOOL: + { + GLint tempValue[16] = {0}; + mProgram->getUniformiv(context, location, tempValue); + UniformStateQueryCastLoop( + dataOut, reinterpret_cast(tempValue), components); + break; + } case GL_INT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLint tempValue[16] = {0}; + mProgram->getUniformiv(context, location, tempValue); + UniformStateQueryCastLoop(dataOut, reinterpret_cast(tempValue), + components); break; + } case GL_UNSIGNED_INT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); - break; - case GL_BOOL: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLuint tempValue[16] = {0}; + mProgram->getUniformuiv(context, location, tempValue); + UniformStateQueryCastLoop(dataOut, reinterpret_cast(tempValue), + components); break; + } case GL_FLOAT: - UniformStateQueryCastLoop(dataOut, srcPointer, components); + { + GLfloat tempValue[16] = {0}; + mProgram->getUniformfv(context, location, tempValue); + UniformStateQueryCastLoop( + dataOut, reinterpret_cast(tempValue), components); break; + } default: UNREACHABLE(); + break; } } + +bool Program::samplesFromTexture(const gl::State &state, GLuint textureID) const +{ + // Must be called after samplers are validated. + ASSERT(mCachedValidateSamplersResult.valid() && mCachedValidateSamplersResult.value()); + + for (const auto &binding : mState.mSamplerBindings) + { + GLenum textureType = binding.textureType; + for (const auto &unit : binding.boundTextureUnits) + { + GLenum programTextureID = state.getSamplerTextureId(unit, textureType); + if (programTextureID == textureID) + { + // TODO(jmadill): Check for appropriate overlap. + return true; + } + } + } + + return false; } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Program.h b/src/3rdparty/angle/src/libANGLE/Program.h index f885ad1694..c242d84671 100644 --- a/src/3rdparty/angle/src/libANGLE/Program.h +++ b/src/3rdparty/angle/src/libANGLE/Program.h @@ -11,8 +11,10 @@ #define LIBANGLE_PROGRAM_H_ #include -#include +#include +#include +#include #include #include #include @@ -22,15 +24,16 @@ #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" +#include "libANGLE/Uniform.h" +#include "libANGLE/angletypes.h" namespace rx { -class ImplFactory; +class GLImplFactory; class ProgramImpl; struct TranslatedAttribute; } @@ -38,31 +41,17 @@ struct TranslatedAttribute; namespace gl { struct Caps; -struct Data; -class ResourceManager; +class Context; +class ContextState; class Shader; +class ShaderProgramManager; +class State; class InfoLog; -class AttributeBindings; class Buffer; class Framebuffer; -struct UniformBlock; -struct LinkedUniform; extern const char * const g_fakepath; -class AttributeBindings -{ - public: - AttributeBindings(); - ~AttributeBindings(); - - void bindAttributeLocation(GLuint index, const char *name); - int getAttributeBinding(const std::string &name) const; - - private: - std::set mAttributeBinding[MAX_VERTEX_ATTRIBS]; -}; - class InfoLog : angle::NonCopyable { public: @@ -122,134 +111,330 @@ class InfoLog : angle::NonCopyable template StreamHelper operator<<(const T &value) { - StreamHelper helper(&mStream); + ensureInitialized(); + StreamHelper helper(mLazyStream.get()); helper << value; return helper; } - std::string str() const { return mStream.str(); } + std::string str() const { return mLazyStream ? mLazyStream->str() : ""; } private: - std::stringstream mStream; + void ensureInitialized() + { + if (!mLazyStream) + { + mLazyStream.reset(new std::stringstream()); + } + } + + std::unique_ptr mLazyStream; }; // Struct used for correlating uniforms/elements of uniform arrays to handles struct VariableLocation { + static constexpr unsigned int kUnused = GL_INVALID_INDEX; + VariableLocation(); - VariableLocation(const std::string &name, unsigned int element, unsigned int index); + VariableLocation(unsigned int arrayIndex, unsigned int index); + + // If used is false, it means this location is only used to fill an empty space in an array, + // and there is no corresponding uniform variable for this location. It can also mean the + // uniform was optimized out by the implementation. + bool used() const { return (index != kUnused); } + void markUnused() { index = kUnused; } + void markIgnored() { ignored = true; } + + // "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays. + unsigned int arrayIndex; + // "index" is an index of the variable. The variable contains the indices for other than the + // innermost GLSL arrays. + unsigned int index; + + // If this location was bound to an unreferenced uniform. Setting data on this uniform is a + // no-op. + bool ignored; +}; +// Information about a variable binding. +// Currently used by CHROMIUM_path_rendering +struct BindingInfo +{ + // The type of binding, for example GL_FLOAT_VEC3. + // This can be GL_NONE if the variable is optimized away. + GLenum type; + + // This is the name of the variable in + // the translated shader program. Note that + // this can be empty in the case where the + // variable has been optimized away. std::string name; - unsigned int element; - unsigned int index; + + // True if the binding is valid, otherwise false. + bool valid; }; -class Program final : angle::NonCopyable, public LabeledObject +// This small structure encapsulates binding sampler uniforms to active GL textures. +struct SamplerBinding { - public: - class Data final : angle::NonCopyable - { - public: - Data(); - ~Data(); + SamplerBinding(GLenum textureTypeIn, size_t elementCount, bool unreferenced); + SamplerBinding(const SamplerBinding &other); + ~SamplerBinding(); - const std::string &getLabel(); + // Necessary for retrieving active textures from the GL state. + GLenum textureType; - 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 + // List of all textures bound to this sampler, of type textureType. + std::vector boundTextureUnits; + + // A note if this sampler is an unreferenced uniform. + bool unreferenced; +}; + +// A varying with tranform feedback enabled. If it's an array, either the whole array or one of its +// elements specified by 'arrayIndex' can set to be enabled. +struct TransformFeedbackVarying : public sh::Varying +{ + TransformFeedbackVarying(const sh::Varying &varyingIn, GLuint index) + : sh::Varying(varyingIn), arrayIndex(index) + { + ASSERT(!isArrayOfArrays()); + } + std::string nameWithArrayIndex() const + { + std::stringstream fullNameStr; + fullNameStr << name; + if (arrayIndex != GL_INVALID_INDEX) { - return mUniformLocations; + fullNameStr << "[" << arrayIndex << "]"; } - const std::vector &getUniformBlocks() const { return mUniformBlocks; } + return fullNameStr.str(); + } + GLsizei size() const + { + return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1); + } - const LinkedUniform *getUniformByName(const std::string &name) const; - GLint getUniformLocation(const std::string &name) const; - GLuint getUniformIndex(const std::string &name) const; + GLuint arrayIndex; +}; - private: - friend class Program; +struct ImageBinding +{ + ImageBinding(size_t count); + ImageBinding(GLuint imageUnit, size_t count); + ImageBinding(const ImageBinding &other); + ~ImageBinding(); + + std::vector boundImageUnits; +}; + +using ShaderStagesMask = angle::BitSet; + +class ProgramState final : angle::NonCopyable +{ + public: + ProgramState(); + ~ProgramState(); + + const std::string &getLabel(); + + Shader *getAttachedVertexShader() const { return mAttachedVertexShader; } + Shader *getAttachedFragmentShader() const { return mAttachedFragmentShader; } + Shader *getAttachedComputeShader() const { return mAttachedComputeShader; } + Shader *getAttachedGeometryShader() const { return mAttachedGeometryShader; } + const std::vector &getTransformFeedbackVaryingNames() const + { + return mTransformFeedbackVaryingNames; + } + GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } + GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const + { + ASSERT(uniformBlockIndex < mUniformBlocks.size()); + return mUniformBlocks[uniformBlockIndex].binding; + } + GLuint getShaderStorageBlockBinding(GLuint blockIndex) const + { + ASSERT(blockIndex < mShaderStorageBlocks.size()); + return mShaderStorageBlocks[blockIndex].binding; + } + const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const + { + return mActiveUniformBlockBindings; + } + const std::vector &getAttributes() const { return mAttributes; } + const AttributesMask &getActiveAttribLocationsMask() const + { + return mActiveAttribLocationsMask; + } + unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; } + DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; } + const std::vector &getOutputVariables() const { return mOutputVariables; } + const std::vector &getOutputLocations() const { return mOutputLocations; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformLocations() const { return mUniformLocations; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getShaderStorageBlocks() const + { + return mShaderStorageBlocks; + } + const std::vector &getBufferVariables() const { return mBufferVariables; } + const std::vector &getSamplerBindings() const { return mSamplerBindings; } + const std::vector &getImageBindings() const { return mImageBindings; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } + const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } + const RangeUI &getImageUniformRange() const { return mImageUniformRange; } + const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; } + + const std::vector &getLinkedTransformFeedbackVaryings() const + { + return mLinkedTransformFeedbackVaryings; + } + const std::vector &getAtomicCounterBuffers() const + { + return mAtomicCounterBuffers; + } - std::string mLabel; + GLuint getUniformIndexFromName(const std::string &name) const; + GLuint getUniformIndexFromLocation(GLint location) const; + Optional getSamplerIndex(GLint location) const; + bool isSamplerUniformIndex(GLuint index) const; + GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; + GLuint getAttributeLocation(const std::string &name) const; - Shader *mAttachedFragmentShader; - Shader *mAttachedVertexShader; + GLuint getBufferVariableIndexFromName(const std::string &name) const; - std::vector mTransformFeedbackVaryingNames; - std::vector mTransformFeedbackVaryingVars; - GLenum mTransformFeedbackBufferMode; + int getNumViews() const { return mNumViews; } + bool usesMultiview() const { return mNumViews != -1; } - GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; - UniformBlockBindingMask mActiveUniformBlockBindings; + const ShaderStagesMask &getLinkedShaderStages() const { return mLinkedShaderStages; } - std::vector mAttributes; - std::bitset mActiveAttribLocationsMask; + private: + friend class MemoryProgramCache; + friend class Program; + + std::string mLabel; + + sh::WorkGroupSize mComputeShaderLocalSize; + + Shader *mAttachedFragmentShader; + Shader *mAttachedVertexShader; + Shader *mAttachedComputeShader; + Shader *mAttachedGeometryShader; + + std::vector mTransformFeedbackVaryingNames; + std::vector mLinkedTransformFeedbackVaryings; + GLenum mTransformFeedbackBufferMode; + + // For faster iteration on the blocks currently being bound. + UniformBlockBindingMask mActiveUniformBlockBindings; + + std::vector mAttributes; + angle::BitSet mActiveAttribLocationsMask; + unsigned int mMaxActiveAttribLocation; + + // Uniforms are sorted in order: + // 1. Non-opaque uniforms + // 2. Sampler uniforms + // 3. Image uniforms + // 4. Atomic counter uniforms + // 5. Uniform block uniforms + // This makes opaque uniform validation easier, since we don't need a separate list. + // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section + // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each + // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include + // [0] in the end. This makes implementation of queries simpler. + std::vector mUniforms; + + std::vector mUniformLocations; + std::vector mUniformBlocks; + std::vector mBufferVariables; + std::vector mShaderStorageBlocks; + std::vector mAtomicCounterBuffers; + RangeUI mSamplerUniformRange; + RangeUI mImageUniformRange; + RangeUI mAtomicCounterUniformRange; - // 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; + // An array of the samplers that are used by the program + std::vector mSamplerBindings; - // TODO(jmadill): use unordered/hash map when available - std::map mOutputVariables; + // An array of the images that are used by the program + std::vector mImageBindings; - bool mBinaryRetrieveableHint; - }; + // Names and mapped names of output variables that are arrays include [0] in the end, similarly + // to uniforms. + std::vector mOutputVariables; + std::vector mOutputLocations; + DrawBufferMask mActiveOutputVariables; - Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle); - ~Program(); + // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. + std::vector mOutputVariableTypes; + + bool mBinaryRetrieveableHint; + bool mSeparable; + ShaderStagesMask mLinkedShaderStages; + + // ANGLE_multiview. + int mNumViews; +}; + +class Program final : angle::NonCopyable, public LabeledObject +{ + public: + Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle); + void onDestroy(const Context *context); 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; } + rx::ProgramImpl *getImplementation() const { return mProgram; } - bool attachShader(Shader *shader); - bool detachShader(Shader *shader); + void attachShader(Shader *shader); + void detachShader(const Context *context, Shader *shader); int getAttachedShadersCount() const; - void bindAttributeLocation(GLuint index, const char *name); + const Shader *getAttachedVertexShader() const { return mState.mAttachedVertexShader; } + const Shader *getAttachedFragmentShader() const { return mState.mAttachedFragmentShader; } + const Shader *getAttachedComputeShader() const { return mState.mAttachedComputeShader; } + const Shader *getAttachedGeometryShader() const { return mState.mAttachedGeometryShader; } - Error link(const gl::Data &data); + void bindAttributeLocation(GLuint index, const char *name); + void bindUniformLocation(GLuint index, const char *name); + + // CHROMIUM_path_rendering + BindingInfo getFragmentInputBindingInfo(const Context *context, GLint index) const; + void bindFragmentInputLocation(GLint index, const char *name); + void pathFragmentInputGen(const Context *context, + GLint index, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + + Error link(const gl::Context *context); 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; + bool hasLinkedVertexShader() const { return mState.mLinkedShaderStages[SHADER_VERTEX]; } + bool hasLinkedFragmentShader() const { return mState.mLinkedShaderStages[SHADER_FRAGMENT]; } + bool hasLinkedComputeShader() const { return mState.mLinkedShaderStages[SHADER_COMPUTE]; } + + Error loadBinary(const Context *context, + GLenum binaryFormat, + const void *binary, + GLsizei length); + Error saveBinary(const Context *context, + GLenum *binaryFormat, + void *binary, + GLsizei bufSize, + GLsizei *length) const; + GLint getBinaryLength(const Context *context) const; void setBinaryRetrievableHint(bool retrievable); bool getBinaryRetrievableHint() const; + void setSeparable(bool separable); + bool isSeparable() const; + int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const; @@ -257,12 +442,23 @@ class Program final : angle::NonCopyable, public LabeledObject 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); + void getActiveAttribute(GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) const; GLint getActiveAttributeCount() const; GLint getActiveAttributeMaxLength() const; - const std::vector &getAttributes() const { return mData.mAttributes; } + const std::vector &getAttributes() const { return mState.mAttributes; } GLint getFragDataLocation(const std::string &name) const; + size_t getOutputResourceCount() const; + const std::vector &getOutputVariableTypes() const + { + return mState.mOutputVariableTypes; + } + DrawBufferMask getActiveOutputVariables() const { return mState.mActiveOutputVariables; } void getActiveUniform(GLuint index, GLsizei bufsize, @@ -271,10 +467,21 @@ class Program final : angle::NonCopyable, public LabeledObject GLenum *type, GLchar *name) const; GLint getActiveUniformCount() const; + size_t getActiveBufferVariableCount() const; GLint getActiveUniformMaxLength() const; - GLint getActiveUniformi(GLuint index, GLenum pname) const; bool isValidUniformLocation(GLint location) const; const LinkedUniform &getUniformByLocation(GLint location) const; + const VariableLocation &getUniformLocation(GLint location) const; + const std::vector &getUniformLocations() const; + const LinkedUniform &getUniformByIndex(GLuint index) const; + + const BufferVariable &getBufferVariableByIndex(GLuint index) const; + + enum SetUniformResult + { + SamplerChanged, + NoSamplerChange, + }; GLint getUniformLocation(const std::string &name) const; GLuint getUniformIndex(const std::string &name) const; @@ -282,7 +489,7 @@ class Program final : angle::NonCopyable, public LabeledObject void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform1iv(GLint location, GLsizei count, const GLint *v); + SetUniformResult setUniform1iv(GLint location, GLsizei count, const GLint *v); void setUniform2iv(GLint location, GLsizei count, const GLint *v); void setUniform3iv(GLint location, GLsizei count, const GLint *v); void setUniform4iv(GLint location, GLsizei count, const GLint *v); @@ -300,21 +507,32 @@ class Program final : angle::NonCopyable, public LabeledObject 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) 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; + void getUniformfv(const Context *context, GLint location, GLfloat *params) const; + void getUniformiv(const Context *context, GLint location, GLint *params) const; + void getUniformuiv(const Context *context, GLint location, GLuint *params) const; + + void getActiveUniformBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const; + void getActiveShaderStorageBlockName(const GLuint blockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *blockName) const; GLuint getActiveUniformBlockCount() const; + GLuint getActiveAtomicCounterBufferCount() const; + GLuint getActiveShaderStorageBlockCount() const; GLint getActiveUniformBlockMaxLength() const; GLuint getUniformBlockIndex(const std::string &name) const; + GLuint getShaderStorageBlockIndex(const std::string &name) const; void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; + GLuint getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const; - const UniformBlock &getUniformBlockByIndex(GLuint index) const; + const InterfaceBlock &getUniformBlockByIndex(GLuint index) const; + const InterfaceBlock &getShaderStorageBlockByIndex(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; @@ -322,11 +540,14 @@ class Program final : angle::NonCopyable, public LabeledObject GLsizei getTransformFeedbackVaryingMaxLength() const; GLenum getTransformFeedbackBufferMode() const; - 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); + static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, + const std::string &uniformName, + const sh::InterfaceBlockField &vertexUniform, + const sh::InterfaceBlockField &fragmentUniform, + bool webglCompatibility); void addRef(); - void release(); + void release(const Context *context); unsigned int getRefCount() const; void flagForDeletion(); bool isFlaggedForDeletion() const; @@ -334,28 +555,25 @@ class Program final : angle::NonCopyable, public LabeledObject void validate(const Caps &caps); bool validateSamplers(InfoLog *infoLog, const Caps &caps); bool isValidated() const; + bool samplesFromTexture(const gl::State &state, GLuint textureID) const; const AttributesMask &getActiveAttribLocationsMask() const { - return mData.mActiveAttribLocationsMask; + return mState.mActiveAttribLocationsMask; } - private: - void unlink(bool destroy = false); - void resetUniformBlockBindings(); - - 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); + const std::vector &getSamplerBindings() const + { + return mState.mSamplerBindings; + } + + const std::vector &getImageBindings() const { return mState.mImageBindings; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const + { + return mState.mComputeShaderLocalSize; + } + + const ProgramState &getState() const { return mState; } static bool linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, @@ -363,71 +581,147 @@ class Program final : angle::NonCopyable, public LabeledObject const sh::ShaderVariable &fragmentVariable, bool validatePrecision); - static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); - bool linkValidateTransformFeedback(InfoLog &infoLog, - const std::vector &linkedVaryings, - const Caps &caps) const; + GLuint getInputResourceIndex(const GLchar *name) const; + GLuint getOutputResourceIndex(const GLchar *name) const; + void getInputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getOutputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getUniformResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; + void getBufferVariableResourceName(GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const; + const sh::Attribute &getInputResource(GLuint index) const; + const sh::OutputVariable &getOutputResource(GLuint index) const; + + class Bindings final : angle::NonCopyable + { + public: + Bindings(); + ~Bindings(); + void bindLocation(GLuint index, const std::string &name); + int getBinding(const std::string &name) 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); + typedef std::unordered_map::const_iterator const_iterator; + const_iterator begin() const; + const_iterator end() const; - std::vector getMergedVaryings() const; - void linkOutputVariables(); + private: + std::unordered_map mBindings; + }; - bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog); + const Bindings &getAttributeBindings() const { return mAttributeBindings; } + const Bindings &getUniformLocationBindings() const { return mUniformLocationBindings; } + const Bindings &getFragmentInputBindings() const { return mFragmentInputBindings; } - struct VectorAndSamplerCount - { - VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {} - VectorAndSamplerCount(const VectorAndSamplerCount &other) = default; - VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default; + int getNumViews() const { return mState.getNumViews(); } + bool usesMultiview() const { return mState.usesMultiview(); } - VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other) - { - vectorCount += other.vectorCount; - samplerCount += other.samplerCount; - return *this; - } + struct VaryingRef + { + const sh::Varying *get() const { return vertex ? vertex : fragment; } - unsigned int vectorCount; - unsigned int samplerCount; + const sh::Varying *vertex = nullptr; + const sh::Varying *fragment = nullptr; }; + using MergedVaryings = std::map; + + private: + ~Program() override; + + void unlink(); + + bool linkAttributes(const Context *context, InfoLog &infoLog); + bool validateVertexAndFragmentInterfaceBlocks( + const std::vector &vertexInterfaceBlocks, + const std::vector &fragmentInterfaceBlocks, + InfoLog &infoLog, + bool webglCompatibility) const; + bool linkInterfaceBlocks(const Context *context, InfoLog &infoLog); + bool linkVaryings(const Context *context, InfoLog &infoLog) const; + + bool linkUniforms(const Context *context, + InfoLog &infoLog, + const Bindings &uniformLocationBindings); + void linkSamplerAndImageBindings(); + bool linkAtomicCounterBuffers(); + + void updateLinkedShaderStages(); + + bool areMatchingInterfaceBlocks(InfoLog &infoLog, + const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock, + bool webglCompatibility) const; + + static bool linkValidateVaryings(InfoLog &infoLog, + const std::string &varyingName, + const sh::Varying &vertexVarying, + const sh::Varying &fragmentVarying, + int shaderVersion); + bool linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const; + bool linkValidateTransformFeedback(const gl::Context *context, + InfoLog &infoLog, + const MergedVaryings &linkedVaryings, + const Caps &caps) const; + bool linkValidateGlobalNames(const Context *context, InfoLog &infoLog) const; - VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform, - const std::string &fullName, - std::vector *samplerUniforms); + void gatherTransformFeedbackVaryings(const MergedVaryings &varyings); - void gatherInterfaceBlockInfo(); - template - void defineUniformBlockMembers(const std::vector &fields, - const std::string &prefix, - int blockIndex); + MergedVaryings getMergedVaryings(const Context *context) const; + void linkOutputVariables(const Context *context); - void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType); + void setUniformValuesFromBindingQualifiers(); - template - void setUniformInternal(GLint location, GLsizei count, const T *v); + void gatherAtomicCounterBuffers(); + void initInterfaceBlockBindings(); + // Both these function update the cached uniform values and return a modified "count" + // so that the uniform update doesn't overflow the uniform. + template + GLsizei clampUniformCount(const VariableLocation &locationInfo, + GLsizei count, + int vectorSize, + const T *v); template - void setMatrixUniformInternal(GLint location, GLsizei count, GLboolean transpose, const T *v); + GLsizei clampMatrixUniformCount(GLint location, GLsizei count, GLboolean transpose, const T *v); + + void updateSamplerUniform(const VariableLocation &locationInfo, + GLsizei clampedCount, + const GLint *v); template - void getUniformInternal(GLint location, DestT *dataOut) const; + void getUniformInternal(const Context *context, + DestT *dataOut, + GLint location, + GLenum nativeType, + int components) const; + + template + void getResourceName(GLuint index, + const std::vector &resources, + GLsizei bufSize, + GLsizei *length, + GLchar *name) const; - Data mData; + ProgramState mState; rx::ProgramImpl *mProgram; bool mValidated; - AttributeBindings mAttributeBindings; + Bindings mAttributeBindings; + + // Note that this has nothing to do with binding layout qualifiers that can be set for some + // uniforms in GLES3.1+. It is used to pre-set the location of uniforms. + Bindings mUniformLocationBindings; + + // CHROMIUM_path_rendering + Bindings mFragmentInputBindings; bool mLinked; bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use unsigned int mRefCount; - ResourceManager *mResourceManager; + ShaderProgramManager *mResourceManager; const GLuint mHandle; InfoLog mInfoLog; @@ -435,8 +729,7 @@ class Program final : angle::NonCopyable, public LabeledObject // Cache for sampler validation Optional mCachedValidateSamplersResult; std::vector mTextureUnitTypesCache; - RangeUI mSamplerUniformRange; }; -} +} // namespace gl #endif // LIBANGLE_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp new file mode 100644 index 0000000000..a33f751525 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.cpp @@ -0,0 +1,1040 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// UniformLinker.cpp: implements link-time checks for default block uniforms, and generates uniform +// locations. Populates data structures related to uniforms so that they can be stored in program +// state. + +#include "libANGLE/ProgramLinkedResources.h" + +#include "common/string_utils.h" +#include "common/utilities.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Context.h" +#include "libANGLE/Shader.h" +#include "libANGLE/features.h" + +namespace gl +{ + +namespace +{ + +LinkedUniform *FindUniform(std::vector &list, const std::string &name) +{ + for (LinkedUniform &uniform : list) + { + if (uniform.name == name) + return &uniform; + } + + return nullptr; +} + +int GetUniformLocationBinding(const Program::Bindings &uniformLocationBindings, + const sh::Uniform &uniform) +{ + int binding = uniformLocationBindings.getBinding(uniform.name); + if (uniform.isArray() && binding == -1) + { + // Bindings for array uniforms can be set either with or without [0] in the end. + ASSERT(angle::EndsWith(uniform.name, "[0]")); + std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u); + return uniformLocationBindings.getBinding(nameWithoutIndex); + } + return binding; +} + +} // anonymous namespace + +UniformLinker::UniformLinker(const ProgramState &state) : mState(state) +{ +} + +UniformLinker::~UniformLinker() = default; + +void UniformLinker::getResults(std::vector *uniforms, + std::vector *uniformLocations) +{ + uniforms->swap(mUniforms); + uniformLocations->swap(mUniformLocations); +} + +bool UniformLinker::link(const Context *context, + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings) +{ + if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader()) + { + ASSERT(mState.getAttachedComputeShader() == nullptr); + if (!validateVertexAndFragmentUniforms(context, infoLog)) + { + 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(context, infoLog)) + { + return false; + } + + if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog)) + { + return false; + } + + if (!indexUniforms(infoLog, uniformLocationBindings)) + { + return false; + } + + return true; +} + +bool UniformLinker::validateVertexAndFragmentUniforms(const Context *context, + InfoLog &infoLog) const +{ + // Check that uniforms defined in the vertex and fragment shaders are identical + std::map linkedUniforms; + const std::vector &vertexUniforms = + mState.getAttachedVertexShader()->getUniforms(context); + const std::vector &fragmentUniforms = + mState.getAttachedFragmentShader()->getUniforms(context); + + for (const sh::Uniform &vertexUniform : vertexUniforms) + { + linkedUniforms[vertexUniform.name] = vertexUniform; + } + + for (const sh::Uniform &fragmentUniform : fragmentUniforms) + { + auto entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &linkedUniform = entry->second; + const std::string &uniformName = "uniform '" + linkedUniform.name + "'"; + if (!linkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform)) + { + return false; + } + } + } + return true; +} + +// GLSL ES Spec 3.00.3, section 4.3.5. +bool UniformLinker::linkValidateUniforms(InfoLog &infoLog, + const std::string &uniformName, + const sh::Uniform &vertexUniform, + const sh::Uniform &fragmentUniform) +{ +#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED + const bool validatePrecision = true; +#else + const bool validatePrecision = false; +#endif + + if (!Program::linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, + validatePrecision)) + { + return false; + } + + // GLSL ES Spec 3.10.4, section 4.4.5. + if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 && + vertexUniform.binding != fragmentUniform.binding) + { + infoLog << "Binding layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + + // GLSL ES Spec 3.10.4, section 9.2.1. + if (vertexUniform.location != -1 && fragmentUniform.location != -1 && + vertexUniform.location != fragmentUniform.location) + { + infoLog << "Location layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + if (vertexUniform.offset != fragmentUniform.offset) + { + infoLog << "Offset layout qualifiers for " << uniformName + << " differ between vertex and fragment shaders."; + return false; + } + + return true; +} + +bool UniformLinker::indexUniforms(InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings) +{ + // All the locations where another uniform can't be located. + std::set reservedLocations; + // Locations which have been allocated for an unused uniform. + std::set ignoredLocations; + + int maxUniformLocation = -1; + + // Gather uniform locations that have been set either using the bindUniformLocation API or by + // using a location layout qualifier and check conflicts between them. + if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings, + &reservedLocations, &ignoredLocations, + &maxUniformLocation)) + { + return false; + } + + // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down + // the line relies on only having statically used uniforms in mUniforms. + pruneUnusedUniforms(); + + // Gather uniforms that have their location pre-set and uniforms that don't yet have a location. + std::vector unlocatedUniforms; + std::map preLocatedUniforms; + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const LinkedUniform &uniform = mUniforms[uniformIndex]; + + if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type)) + { + continue; + } + + int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform); + int shaderLocation = uniform.location; + + if (shaderLocation != -1) + { + preSetLocation = shaderLocation; + } + + unsigned int elementCount = uniform.getBasicTypeElementCount(); + for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++) + { + VariableLocation location(arrayIndex, static_cast(uniformIndex)); + + if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1) + { + int elementLocation = preSetLocation + arrayIndex; + preLocatedUniforms[elementLocation] = location; + } + else + { + unlocatedUniforms.push_back(location); + } + } + } + + // Make enough space for all uniforms, with pre-set locations or not. + mUniformLocations.resize( + std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(), + static_cast(maxUniformLocation + 1))); + + // Assign uniforms with pre-set locations + for (const auto &uniform : preLocatedUniforms) + { + mUniformLocations[uniform.first] = uniform.second; + } + + // Assign ignored uniforms + for (const auto &ignoredLocation : ignoredLocations) + { + mUniformLocations[ignoredLocation].markIgnored(); + } + + // Automatically assign locations for the rest of the uniforms + size_t nextUniformLocation = 0; + for (const auto &unlocatedUniform : unlocatedUniforms) + { + while (mUniformLocations[nextUniformLocation].used() || + mUniformLocations[nextUniformLocation].ignored) + { + nextUniformLocation++; + } + + ASSERT(nextUniformLocation < mUniformLocations.size()); + mUniformLocations[nextUniformLocation] = unlocatedUniform; + nextUniformLocation++; + } + + return true; +} + +bool UniformLinker::gatherUniformLocationsAndCheckConflicts( + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings, + std::set *reservedLocations, + std::set *ignoredLocations, + int *maxUniformLocation) +{ + for (const LinkedUniform &uniform : mUniforms) + { + if (uniform.isBuiltIn()) + { + continue; + } + + int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform); + int shaderLocation = uniform.location; + + if (shaderLocation != -1) + { + unsigned int elementCount = uniform.getBasicTypeElementCount(); + + for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++) + { + // GLSL ES 3.10 section 4.4.3 + int elementLocation = shaderLocation + arrayIndex; + *maxUniformLocation = std::max(*maxUniformLocation, elementLocation); + if (reservedLocations->find(elementLocation) != reservedLocations->end()) + { + infoLog << "Multiple uniforms bound to location " << elementLocation << "."; + return false; + } + reservedLocations->insert(elementLocation); + if (!uniform.staticUse) + { + ignoredLocations->insert(elementLocation); + } + } + } + else if (apiBoundLocation != -1 && uniform.staticUse) + { + // Only the first location is reserved even if the uniform is an array. + *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation); + if (reservedLocations->find(apiBoundLocation) != reservedLocations->end()) + { + infoLog << "Multiple uniforms bound to location " << apiBoundLocation << "."; + return false; + } + reservedLocations->insert(apiBoundLocation); + } + } + + // Record the uniform locations that were bound using the API for uniforms that were not found + // from the shader. Other uniforms should not be assigned to those locations. + for (const auto &locationBinding : uniformLocationBindings) + { + GLuint location = locationBinding.second; + if (reservedLocations->find(location) == reservedLocations->end()) + { + ignoredLocations->insert(location); + *maxUniformLocation = std::max(*maxUniformLocation, static_cast(location)); + } + } + + return true; +} + +void UniformLinker::pruneUnusedUniforms() +{ + auto uniformIter = mUniforms.begin(); + while (uniformIter != mUniforms.end()) + { + if (uniformIter->staticUse) + { + ++uniformIter; + } + else + { + uniformIter = mUniforms.erase(uniformIter); + } + } +} + +bool UniformLinker::flattenUniformsAndCheckCapsForShader( + const Context *context, + Shader *shader, + GLuint maxUniformComponents, + GLuint maxTextureImageUnits, + GLuint maxImageUnits, + GLuint maxAtomicCounters, + const std::string &componentsErrorMessage, + const std::string &samplerErrorMessage, + const std::string &imageErrorMessage, + const std::string &atomicCounterErrorMessage, + std::vector &samplerUniforms, + std::vector &imageUniforms, + std::vector &atomicCounterUniforms, + InfoLog &infoLog) +{ + ShaderUniformCount shaderUniformCount; + for (const sh::Uniform &uniform : shader->getUniforms(context)) + { + shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms, + &atomicCounterUniforms, shader->getType()); + } + + if (shaderUniformCount.vectorCount > maxUniformComponents) + { + infoLog << componentsErrorMessage << maxUniformComponents << ")."; + return false; + } + + if (shaderUniformCount.samplerCount > maxTextureImageUnits) + { + infoLog << samplerErrorMessage << maxTextureImageUnits << ")."; + return false; + } + + if (shaderUniformCount.imageCount > maxImageUnits) + { + infoLog << imageErrorMessage << maxImageUnits << ")."; + return false; + } + + if (shaderUniformCount.atomicCounterCount > maxAtomicCounters) + { + infoLog << atomicCounterErrorMessage << maxAtomicCounters << ")."; + return false; + } + + return true; +} + +bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog) +{ + std::vector samplerUniforms; + std::vector imageUniforms; + std::vector atomicCounterUniforms; + + const Caps &caps = context->getCaps(); + + if (mState.getAttachedComputeShader()) + { + Shader *computeShader = mState.getAttachedComputeShader(); + + // TODO (mradev): check whether we need finer-grained component counting + if (!flattenUniformsAndCheckCapsForShader( + context, computeShader, caps.maxComputeUniformComponents / 4, + caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms, + caps.maxComputeAtomicCounters, + "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (", + "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (", + "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (", + "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + } + else + { + Shader *vertexShader = mState.getAttachedVertexShader(); + + if (!flattenUniformsAndCheckCapsForShader( + context, vertexShader, caps.maxVertexUniformVectors, + caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms, + caps.maxVertexAtomicCounters, + "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (", + "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (", + "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (", + "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + + Shader *fragmentShader = mState.getAttachedFragmentShader(); + + if (!flattenUniformsAndCheckCapsForShader( + context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits, + caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters, + "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (", + "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", + "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (", + "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (", + samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog)) + { + return false; + } + } + + mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end()); + mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end()); + mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end()); + return true; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenUniform( + const sh::Uniform &uniform, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType) +{ + int location = uniform.location; + ShaderUniformCount shaderUniformCount = + flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse, + uniform.binding, uniform.offset, &location); + if (uniform.staticUse) + { + return shaderUniformCount; + } + return ShaderUniformCount(); +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform( + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + ShaderUniformCount shaderUniformCount; + const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string elementName = namePrefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < uniform.arraySizes.size()) + { + shaderUniformCount += flattenArrayOfStructsUniform( + uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset, + location); + } + else + { + shaderUniformCount += flattenStructUniform( + uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform( + const std::vector &fields, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ShaderUniformCount shaderUniformCount; + for (const sh::ShaderVariable &field : fields) + { + const std::string &fieldName = namePrefix + "." + field.name; + const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName; + + shaderUniformCount += + flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location); + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform( + const sh::ShaderVariable &uniform, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ShaderUniformCount shaderUniformCount; + + ASSERT(uniform.isArray()); + for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize(); + ++arrayElement) + { + sh::ShaderVariable uniformElement = uniform; + uniformElement.indexIntoArray(arrayElement); + const std::string elementName = namePrefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement); + + shaderUniformCount += flattenUniformImpl( + uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + return shaderUniformCount; +} + +UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl( + const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location) +{ + ASSERT(location); + ShaderUniformCount shaderUniformCount; + + if (uniform.isStruct()) + { + if (uniform.isArray()) + { + shaderUniformCount += flattenArrayOfStructsUniform( + uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + else + { + shaderUniformCount += flattenStructUniform( + uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms, + atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location); + } + return shaderUniformCount; + } + if (uniform.isArrayOfArrays()) + { + // GLES 3.1 November 2016 section 7.3.1 page 77: + // "For an active variable declared as an array of an aggregate data type (structures or + // arrays), a separate entry will be generated for each active array element" + return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms, + imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, + binding, offset, location); + } + + // Not a struct + bool isSampler = IsSamplerType(uniform.type); + bool isImage = IsImageType(uniform.type); + bool isAtomicCounter = IsAtomicCounterType(uniform.type); + std::vector *uniformList = &mUniforms; + if (isSampler) + { + uniformList = samplerUniforms; + } + else if (isImage) + { + uniformList = imageUniforms; + } + else if (isAtomicCounter) + { + uniformList = atomicCounterUniforms; + } + + std::string fullNameWithArrayIndex(fullName); + std::string fullMappedNameWithArrayIndex(fullMappedName); + + if (uniform.isArray()) + { + // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources + // and including [0] at the end of array variable names. + fullNameWithArrayIndex += "[0]"; + fullMappedNameWithArrayIndex += "[0]"; + } + + LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex); + if (existingUniform) + { + if (binding != -1) + { + existingUniform->binding = binding; + } + if (offset != -1) + { + existingUniform->offset = offset; + } + if (*location != -1) + { + existingUniform->location = *location; + } + if (markStaticUse) + { + existingUniform->staticUse = true; + existingUniform->setStaticUse(shaderType, true); + } + } + else + { + ASSERT(uniform.arraySizes.size() <= 1u); + LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex, + uniform.arraySizes, binding, offset, *location, -1, + sh::BlockMemberInfo::getDefaultBlockInfo()); + linkedUniform.mappedName = fullMappedNameWithArrayIndex; + linkedUniform.staticUse = markStaticUse; + linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays; + if (markStaticUse) + { + linkedUniform.setStaticUse(shaderType, true); + } + + uniformList->push_back(linkedUniform); + } + + // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount(). + unsigned int elementCount = uniform.getBasicTypeElementCount(); + + // Samplers and images aren't "real" uniforms, so they don't count towards register usage. + // Likewise, don't count "real" uniforms towards opaque count. + shaderUniformCount.vectorCount = + (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount)); + shaderUniformCount.samplerCount = (isSampler ? elementCount : 0); + shaderUniformCount.imageCount = (isImage ? elementCount : 0); + shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0); + + if (*location != -1) + { + *location += elementCount; + } + + return shaderUniformCount; +} + +bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog) +{ + unsigned int atomicCounterCount = 0; + for (const auto &uniform : mUniforms) + { + if (IsAtomicCounterType(uniform.type) && uniform.staticUse) + { + atomicCounterCount += uniform.getBasicTypeElementCount(); + if (atomicCounterCount > caps.maxCombinedAtomicCounters) + { + infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS" + << caps.maxCombinedAtomicCounters << ")."; + return false; + } + } + } + return true; +} + +// InterfaceBlockLinker implementation. +InterfaceBlockLinker::InterfaceBlockLinker(std::vector *blocksOut) + : mBlocksOut(blocksOut) +{ +} + +InterfaceBlockLinker::~InterfaceBlockLinker() +{ +} + +void InterfaceBlockLinker::addShaderBlocks(GLenum shader, + const std::vector *blocks) +{ + mShaderBlocks.push_back(std::make_pair(shader, blocks)); +} + +void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo) const +{ + ASSERT(mBlocksOut->empty()); + + std::set visitedList; + + for (const auto &shaderBlocks : mShaderBlocks) + { + const GLenum shaderType = shaderBlocks.first; + + for (const auto &block : *shaderBlocks.second) + { + // Only 'packed' blocks are allowed to be considered inactive. + if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (visitedList.count(block.name) > 0) + { + if (block.staticUse) + { + for (InterfaceBlock &priorBlock : *mBlocksOut) + { + if (block.name == priorBlock.name) + { + priorBlock.setStaticUse(shaderType, true); + // TODO(jiajia.qin@intel.com): update the block members static use. + } + } + } + } + else + { + defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType); + visitedList.insert(block.name); + } + } + } +} + +template +void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + unsigned int arrayNestingIndex, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex); + if (singleEntryForTopLevelArray) + { + entryGenerationArraySize = 1; + } + for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement) + { + const std::string elementName = prefix + ArrayString(arrayElement); + const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < field.arraySizes.size()) + { + defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u, + elementName, elementMappedName, blockIndex, false, + topLevelArraySize); + } + else + { + defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName, + blockIndex, false, topLevelArraySize); + } + } +} + +template +void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const std::vector &fields, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + for (const VarT &field : fields) + { + std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name); + std::string fullMappedName = + (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName); + + defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex, + singleEntryForTopLevelArray, topLevelArraySize); + } +} + +template +void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const +{ + int nextArraySize = topLevelArraySize; + if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) && + singleEntryForTopLevelArray) + { + // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block + // member declared as an array of an aggregate type, an entry will be generated only + // for the first array element, regardless of its type.' + nextArraySize = field.getOutermostArraySize(); + } + + if (field.isStruct()) + { + if (field.isArray()) + { + defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName, + blockIndex, singleEntryForTopLevelArray, + nextArraySize); + } + else + { + ASSERT(nextArraySize == topLevelArraySize); + defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex, + false, nextArraySize); + } + return; + } + if (field.isArrayOfArrays()) + { + unsigned int entryGenerationArraySize = field.getOutermostArraySize(); + if (singleEntryForTopLevelArray) + { + entryGenerationArraySize = 1u; + } + for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; + ++arrayElement) + { + VarT fieldElement = field; + fieldElement.indexIntoArray(arrayElement); + const std::string elementName = fullName + ArrayString(arrayElement); + const std::string elementMappedName = fullMappedName + ArrayString(arrayElement); + + defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName, + blockIndex, false, nextArraySize); + } + return; + } + + // If getBlockMemberInfo returns false, the variable is optimized out. + sh::BlockMemberInfo memberInfo; + if (!getMemberInfo(fullName, fullMappedName, &memberInfo)) + { + return; + } + + std::string fullNameWithArrayIndex = fullName; + std::string fullMappedNameWithArrayIndex = fullMappedName; + + if (field.isArray()) + { + fullNameWithArrayIndex += "[0]"; + fullMappedNameWithArrayIndex += "[0]"; + } + + ASSERT(nextArraySize == topLevelArraySize); + defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex, blockIndex, + memberInfo, nextArraySize); +} + +void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo, + const sh::InterfaceBlock &interfaceBlock, + GLenum shaderType) const +{ + size_t blockSize = 0; + std::vector blockIndexes; + + int blockIndex = static_cast(mBlocksOut->size()); + // Track the first and last block member index to determine the range of active block members in + // the block. + size_t firstBlockMemberIndex = getCurrentBlockMemberIndex(); + defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(), + interfaceBlock.fieldMappedPrefix(), blockIndex, + interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1); + size_t lastBlockMemberIndex = getCurrentBlockMemberIndex(); + + for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex; + ++blockMemberIndex) + { + blockIndexes.push_back(static_cast(blockMemberIndex)); + } + + // ESSL 3.10 section 4.4.4 page 58: + // Any uniform or shader storage block declared without a binding qualifier is initially + // assigned to block binding point zero. + int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding); + for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount(); + ++arrayElement) + { + std::string blockArrayName = interfaceBlock.name; + std::string blockMappedArrayName = interfaceBlock.mappedName; + if (interfaceBlock.isArray()) + { + blockArrayName += ArrayString(arrayElement); + blockMappedArrayName += ArrayString(arrayElement); + } + + // Don't define this block at all if it's not active in the implementation. + if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize)) + { + continue; + } + + InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, + interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement); + block.memberIndexes = blockIndexes; + block.setStaticUse(shaderType, interfaceBlock.staticUse); + + // Since all block elements in an array share the same active interface blocks, they + // will all be active once any block member is used. So, since interfaceBlock.name[0] + // was active, here we will add every block element in the array. + block.dataSize = static_cast(blockSize); + mBlocksOut->push_back(block); + } +} + +// UniformBlockLinker implementation. +UniformBlockLinker::UniformBlockLinker(std::vector *blocksOut, + std::vector *uniformsOut) + : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut) +{ +} + +UniformBlockLinker::~UniformBlockLinker() +{ +} + +void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int /*topLevelArraySize*/) const +{ + LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1, + blockIndex, memberInfo); + newUniform.mappedName = fullMappedName; + // TODO(jiajia.qin@intel.com): update the block memeber static use. + + // Since block uniforms have no location, we don't need to store them in the uniform locations + // list. + mUniformsOut->push_back(newUniform); +} + +size_t UniformBlockLinker::getCurrentBlockMemberIndex() const +{ + return mUniformsOut->size(); +} + +// ShaderStorageBlockLinker implementation. +ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector *blocksOut, + std::vector *bufferVariablesOut) + : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut) +{ +} + +ShaderStorageBlockLinker::~ShaderStorageBlockLinker() +{ +} + +void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const +{ + BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes, + blockIndex, memberInfo); + newBufferVariable.mappedName = fullMappedName; + // TODO(jiajia.qin@intel.com): update the block memeber static use. + + newBufferVariable.topLevelArraySize = topLevelArraySize; + + mBufferVariablesOut->push_back(newBufferVariable); +} + +size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const +{ + return mBufferVariablesOut->size(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h new file mode 100644 index 0000000000..1bf91b7f3b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramLinkedResources.h @@ -0,0 +1,274 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// UniformLinker.h: implements link-time checks for default block uniforms, and generates uniform +// locations. Populates data structures related to uniforms so that they can be stored in program +// state. + +#ifndef LIBANGLE_UNIFORMLINKER_H_ +#define LIBANGLE_UNIFORMLINKER_H_ + +#include "libANGLE/Program.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VaryingPacking.h" + +#include + +namespace gl +{ + +class UniformLinker +{ + public: + UniformLinker(const ProgramState &state); + ~UniformLinker(); + + bool link(const Context *context, + InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings); + + void getResults(std::vector *uniforms, + std::vector *uniformLocations); + + private: + struct ShaderUniformCount + { + ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0) + { + } + ShaderUniformCount(const ShaderUniformCount &other) = default; + ShaderUniformCount &operator=(const ShaderUniformCount &other) = default; + + ShaderUniformCount &operator+=(const ShaderUniformCount &other) + { + vectorCount += other.vectorCount; + samplerCount += other.samplerCount; + imageCount += other.imageCount; + atomicCounterCount += other.atomicCounterCount; + return *this; + } + + unsigned int vectorCount; + unsigned int samplerCount; + unsigned int imageCount; + unsigned int atomicCounterCount; + }; + + bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const; + + static bool linkValidateUniforms(InfoLog &infoLog, + const std::string &uniformName, + const sh::Uniform &vertexUniform, + const sh::Uniform &fragmentUniform); + + bool flattenUniformsAndCheckCapsForShader(const Context *context, + Shader *shader, + GLuint maxUniformComponents, + GLuint maxTextureImageUnits, + GLuint maxImageUnits, + GLuint maxAtomicCounters, + const std::string &componentsErrorMessage, + const std::string &samplerErrorMessage, + const std::string &imageErrorMessage, + const std::string &atomicCounterErrorMessage, + std::vector &samplerUniforms, + std::vector &imageUniforms, + std::vector &atomicCounterUniforms, + InfoLog &infoLog); + + bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog); + bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog); + + ShaderUniformCount flattenUniform(const sh::Uniform &uniform, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType); + + ShaderUniformCount flattenArrayOfStructsUniform( + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + ShaderUniformCount flattenStructUniform(const std::vector &fields, + const std::string &namePrefix, + const std::string &mappedNamePrefix, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + ShaderUniformCount flattenArrayUniform(const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + // markStaticUse is given as a separate parameter because it is tracked here at struct + // granularity. + ShaderUniformCount flattenUniformImpl(const sh::ShaderVariable &uniform, + const std::string &fullName, + const std::string &fullMappedName, + std::vector *samplerUniforms, + std::vector *imageUniforms, + std::vector *atomicCounterUniforms, + GLenum shaderType, + bool markStaticUse, + int binding, + int offset, + int *location); + + bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings); + bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog, + const Program::Bindings &uniformLocationBindings, + std::set *reservedLocations, + std::set *ignoredLocations, + int *maxUniformLocation); + void pruneUnusedUniforms(); + + const ProgramState &mState; + std::vector mUniforms; + std::vector mUniformLocations; +}; + +// This class is intended to be used during the link step to store interface block information. +// It is called by the Impl class during ProgramImpl::link so that it has access to the +// real block size and layout. +class InterfaceBlockLinker : angle::NonCopyable +{ + public: + virtual ~InterfaceBlockLinker(); + + using GetBlockSize = std::function< + bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>; + using GetBlockMemberInfo = std::function< + bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>; + + // This is called once per shader stage. It stores a pointer to the block vector, so it's + // important that this class does not persist longer than the duration of Program::link. + void addShaderBlocks(GLenum shader, const std::vector *blocks); + + // This is called once during a link operation, after all shader blocks are added. + void linkBlocks(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo) const; + + protected: + InterfaceBlockLinker(std::vector *blocksOut); + void defineInterfaceBlock(const GetBlockSize &getBlockSize, + const GetBlockMemberInfo &getMemberInfo, + const sh::InterfaceBlock &interfaceBlock, + GLenum shaderType) const; + + template + void defineBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const std::vector &fields, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; + template + void defineBlockMember(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; + + virtual void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const = 0; + virtual size_t getCurrentBlockMemberIndex() const = 0; + + using ShaderBlocks = std::pair *>; + std::vector mShaderBlocks; + + std::vector *mBlocksOut; + + private: + template + void defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo, + const VarT &field, + unsigned int arrayNestingIndex, + const std::string &prefix, + const std::string &mappedPrefix, + int blockIndex, + bool singleEntryForTopLevelArray, + int topLevelArraySize) const; +}; + +class UniformBlockLinker final : public InterfaceBlockLinker +{ + public: + UniformBlockLinker(std::vector *blocksOut, + std::vector *uniformsOut); + ~UniformBlockLinker() override; + + private: + void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const override; + size_t getCurrentBlockMemberIndex() const override; + std::vector *mUniformsOut; +}; + +class ShaderStorageBlockLinker final : public InterfaceBlockLinker +{ + public: + ShaderStorageBlockLinker(std::vector *blocksOut, + std::vector *bufferVariablesOut); + ~ShaderStorageBlockLinker() override; + + private: + void defineBlockMemberImpl(const sh::ShaderVariable &field, + const std::string &fullName, + const std::string &fullMappedName, + int blockIndex, + const sh::BlockMemberInfo &memberInfo, + int topLevelArraySize) const override; + size_t getCurrentBlockMemberIndex() const override; + std::vector *mBufferVariablesOut; +}; + +// The link operation is responsible for finishing the link of uniform and interface blocks. +// This way it can filter out unreferenced resources and still have access to the info. +// TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks. +struct ProgramLinkedResources +{ + VaryingPacking varyingPacking; + UniformBlockLinker uniformBlockLinker; + ShaderStorageBlockLinker shaderStorageBlockLinker; +}; + +} // namespace gl + +#endif // LIBANGLE_UNIFORMLINKER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp new file mode 100644 index 0000000000..0445512090 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.cpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramPipeline.cpp: Implements the gl::ProgramPipeline class. +// Implements GL program pipeline objects and related functionality. +// [OpenGL ES 3.1] section 7.4 page 105. + +#include "libANGLE/ProgramPipeline.h" + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ProgramPipelineImpl.h" + +namespace gl +{ + +ProgramPipelineState::ProgramPipelineState() : mLabel() +{ +} + +ProgramPipelineState::~ProgramPipelineState() +{ +} + +const std::string &ProgramPipelineState::getLabel() const +{ + return mLabel; +} + +ProgramPipeline::ProgramPipeline(rx::GLImplFactory *factory, GLuint handle) + : RefCountObject(handle), + mProgramPipeline(factory->createProgramPipeline(mState)) +{ + ASSERT(mProgramPipeline); +} + +ProgramPipeline::~ProgramPipeline() +{ + mProgramPipeline.release(); +} + +Error ProgramPipeline::onDestroy(const Context *context) +{ + return NoError(); +} + +void ProgramPipeline::setLabel(const std::string &label) +{ + mState.mLabel = label; +} + +const std::string &ProgramPipeline::getLabel() const +{ + return mState.mLabel; +} + +rx::ProgramPipelineImpl *ProgramPipeline::getImplementation() const +{ + return mProgramPipeline.get(); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h new file mode 100644 index 0000000000..2aac87c7b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ProgramPipeline.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramPipeline.h: Defines the gl::ProgramPipeline class. +// Implements GL program pipeline objects and related functionality. +// [OpenGL ES 3.1] section 7.4 page 105. + +#ifndef LIBANGLE_PROGRAMPIPELINE_H_ +#define LIBANGLE_PROGRAMPIPELINE_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Debug.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class GLImplFactory; +class ProgramPipelineImpl; +}; + +namespace gl +{ +class Context; +class ProgramPipeline; + +class ProgramPipelineState final : angle::NonCopyable +{ + public: + ProgramPipelineState(); + ~ProgramPipelineState(); + + const std::string &getLabel() const; + + private: + friend class ProgramPipeline; + + std::string mLabel; +}; + +class ProgramPipeline final : public RefCountObject, public LabeledObject +{ + public: + ProgramPipeline(rx::GLImplFactory *factory, GLuint handle); + ~ProgramPipeline() override; + + Error onDestroy(const Context *context) override; + + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; + + rx::ProgramPipelineImpl *getImplementation() const; + + private: + std::unique_ptr mProgramPipeline; + + ProgramPipelineState mState; +}; +} + +#endif // LIBANGLE_PROGRAMPIPELINE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Query.h b/src/3rdparty/angle/src/libANGLE/Query.h index 5486f983e7..c307eaaf08 100644 --- a/src/3rdparty/angle/src/libANGLE/Query.h +++ b/src/3rdparty/angle/src/libANGLE/Query.h @@ -29,7 +29,8 @@ class Query final : public RefCountObject, public LabeledObject { public: Query(rx::QueryImpl *impl, GLuint id); - virtual ~Query(); + void destroy(const gl::Context *context) {} + ~Query() override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp deleted file mode 100644 index b1210200cf..0000000000 --- a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// RefCountObject.cpp: Defines the gl::RefCountObject base class that provides -// lifecycle support for GL objects using the traditional BindObject scheme, but -// that need to be reference counted for correct cross-context deletion. -// (Concretely, textures, buffers and renderbuffers.) - -#include "RefCountObject.h" - -RefCountObject::RefCountObject(GLuint id) - : mId(id), - mRefCount(0) -{ -} - -RefCountObject::~RefCountObject() -{ - ASSERT(mRefCount == 0); -} - -void RefCountObject::addRef() const -{ - mRefCount++; -} - -void RefCountObject::release() const -{ - ASSERT(mRefCount > 0); - - if (--mRefCount == 0) - { - delete this; - } -} - diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.h b/src/3rdparty/angle/src/libANGLE/RefCountObject.h index 86e6d788b5..cb41cc27f4 100644 --- a/src/3rdparty/angle/src/libANGLE/RefCountObject.h +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.h @@ -12,16 +12,21 @@ #ifndef LIBANGLE_REFCOUNTOBJECT_H_ #define LIBANGLE_REFCOUNTOBJECT_H_ -#include "common/debug.h" - #include "angle_gl.h" +#include "common/debug.h" +#include "libANGLE/Error.h" #include -class RefCountObject : angle::NonCopyable +namespace gl +{ +class Context; + +class RefCountObjectNoID : angle::NonCopyable { public: - explicit RefCountObject(GLuint id) : mId(id), mRefCount(0) {} + RefCountObjectNoID() : mRefCount(0) {} + virtual Error onDestroy(const Context *context); void addRef() const { ++mRefCount; } @@ -35,17 +40,56 @@ class RefCountObject : angle::NonCopyable } } + size_t getRefCount() const { return mRefCount; } + + protected: + virtual ~RefCountObjectNoID(); + + // A specialized release method for objects which need a destroy context. + void release(const gl::Context *context) + { + ASSERT(mRefCount > 0); + if (--mRefCount == 0) + { + ANGLE_SWALLOW_ERR(onDestroy(context)); + delete this; + } + } + + template + friend class BindingPointer; + mutable std::size_t mRefCount; +}; + +inline RefCountObjectNoID::~RefCountObjectNoID() +{ + ASSERT(mRefCount == 0); +} + +inline Error RefCountObjectNoID::onDestroy(const Context *context) +{ + return NoError(); +} + +template +class BindingPointer; + +class RefCountObject : RefCountObjectNoID +{ + public: + explicit RefCountObject(GLuint id) : mId(id) {} + GLuint id() const { return mId; } - size_t getRefCount() const { return mRefCount; } + using RefCountObjectNoID::release; + using RefCountObjectNoID::addRef; + using RefCountObjectNoID::getRefCount; protected: - virtual ~RefCountObject() { ASSERT(mRefCount == 0); } + ~RefCountObject() override {} private: GLuint mId; - - mutable std::size_t mRefCount; }; template @@ -57,15 +101,17 @@ class BindingPointer { } - BindingPointer(const BindingPointer &other) - : mObject(nullptr) + BindingPointer(ObjectType *object) : mObject(object) { mObject->addRef(); } + + BindingPointer(const BindingPointer &other) : mObject(other.mObject) { - set(other.mObject); + mObject->addRef(); } - void operator=(const BindingPointer &other) + BindingPointer &operator=(BindingPointer &&other) { - set(other.mObject); + std::swap(mObject, other.mObject); + return *this; } virtual ~BindingPointer() @@ -74,11 +120,12 @@ class BindingPointer ASSERT(mObject == nullptr); } - virtual void set(ObjectType *newObject) + virtual void set(const Context *context, ObjectType *newObject) { // addRef first in case newObject == mObject and this is the last reference to it. - if (newObject != nullptr) reinterpret_cast(newObject)->addRef(); - if (mObject != nullptr) reinterpret_cast(mObject)->release(); + if (newObject != nullptr) reinterpret_cast(newObject)->addRef(); + if (mObject != nullptr) + reinterpret_cast(mObject)->release(context); mObject = newObject; } @@ -104,16 +151,16 @@ class OffsetBindingPointer : public BindingPointer public: OffsetBindingPointer() : mOffset(0), mSize(0) { } - void set(ObjectType *newObject) override + void set(const Context *context, ObjectType *newObject) override { - BindingPointer::set(newObject); + BindingPointer::set(context, newObject); mOffset = 0; mSize = 0; } - void set(ObjectType *newObject, GLintptr offset, GLsizeiptr size) + void set(const Context *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size) { - BindingPointer::set(newObject); + BindingPointer::set(context, newObject); mOffset = offset; mSize = size; } @@ -135,5 +182,6 @@ class OffsetBindingPointer : public BindingPointer GLintptr mOffset; GLsizeiptr mSize; }; +} // namespace gl #endif // LIBANGLE_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp index 161fbea797..8310f1abda 100644 --- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp @@ -25,11 +25,24 @@ Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) mLabel(), mWidth(0), mHeight(0), - mInternalFormat(GL_RGBA4), - mSamples(0) + mFormat(GL_RGBA4), + mSamples(0), + mInitState(InitState::MayNeedInit) { } +Error Renderbuffer::onDestroy(const Context *context) +{ + ANGLE_TRY(orphanImages(context)); + + if (mRenderbuffer) + { + ANGLE_TRY(mRenderbuffer->onDestroy(context)); + } + + return NoError(); +} + Renderbuffer::~Renderbuffer() { SafeDelete(mRenderbuffer); @@ -45,70 +58,70 @@ const std::string &Renderbuffer::getLabel() const return mLabel; } -Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height) +Error Renderbuffer::setStorage(const Context *context, + GLenum internalformat, + size_t width, + size_t height) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorage(internalformat, width, height); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderbuffer->setStorage(context, internalformat, width, height)); mWidth = static_cast(width); mHeight = static_cast(height); - mInternalFormat = internalformat; + mFormat = Format(internalformat); mSamples = 0; - return Error(GL_NO_ERROR); + mInitState = InitState::MayNeedInit; + mDirtyChannel.signal(mInitState); + + return NoError(); } -Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +Error Renderbuffer::setStorageMultisample(const Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mRenderbuffer->setStorageMultisample(context, samples, internalformat, width, height)); mWidth = static_cast(width); mHeight = static_cast(height); - mInternalFormat = internalformat; + mFormat = Format(internalformat); mSamples = static_cast(samples); - return Error(GL_NO_ERROR); + mInitState = InitState::MayNeedInit; + mDirtyChannel.signal(mInitState); + + return NoError(); } -Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image) +Error Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image *image) { - orphanImages(); + ANGLE_TRY(orphanImages(context)); - Error error = mRenderbuffer->setStorageEGLImageTarget(image); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderbuffer->setStorageEGLImageTarget(context, image)); - setTargetImage(image); + setTargetImage(context, image); mWidth = static_cast(image->getWidth()); mHeight = static_cast(image->getHeight()); - mInternalFormat = image->getInternalFormat(); + mFormat = Format(image->getFormat()); mSamples = 0; - return Error(GL_NO_ERROR); -} + mInitState = image->sourceInitState(); + mDirtyChannel.signal(mInitState); -rx::RenderbufferImpl *Renderbuffer::getImplementation() -{ - ASSERT(mRenderbuffer); - return mRenderbuffer; + return NoError(); } -const rx::RenderbufferImpl *Renderbuffer::getImplementation() const +rx::RenderbufferImpl *Renderbuffer::getImplementation() const { + ASSERT(mRenderbuffer); return mRenderbuffer; } @@ -122,9 +135,9 @@ GLsizei Renderbuffer::getHeight() const return mHeight; } -GLenum Renderbuffer::getInternalFormat() const +const Format &Renderbuffer::getFormat() const { - return mInternalFormat; + return mFormat; } GLsizei Renderbuffer::getSamples() const @@ -134,42 +147,42 @@ GLsizei Renderbuffer::getSamples() const GLuint Renderbuffer::getRedSize() const { - return GetInternalFormatInfo(mInternalFormat).redBits; + return mFormat.info->redBits; } GLuint Renderbuffer::getGreenSize() const { - return GetInternalFormatInfo(mInternalFormat).greenBits; + return mFormat.info->greenBits; } GLuint Renderbuffer::getBlueSize() const { - return GetInternalFormatInfo(mInternalFormat).blueBits; + return mFormat.info->blueBits; } GLuint Renderbuffer::getAlphaSize() const { - return GetInternalFormatInfo(mInternalFormat).alphaBits; + return mFormat.info->alphaBits; } GLuint Renderbuffer::getDepthSize() const { - return GetInternalFormatInfo(mInternalFormat).depthBits; + return mFormat.info->depthBits; } GLuint Renderbuffer::getStencilSize() const { - return GetInternalFormatInfo(mInternalFormat).stencilBits; + return mFormat.info->stencilBits; } -void Renderbuffer::onAttach() +void Renderbuffer::onAttach(const Context *context) { addRef(); } -void Renderbuffer::onDetach() +void Renderbuffer::onDetach(const Context *context) { - release(); + release(context); } GLuint Renderbuffer::getId() const @@ -177,8 +190,46 @@ GLuint Renderbuffer::getId() const return id(); } -Extents Renderbuffer::getAttachmentSize(const FramebufferAttachment::Target & /*target*/) const +Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) const { return Extents(mWidth, mHeight, 1); } + +const Format &Renderbuffer::getAttachmentFormat(GLenum /*binding*/, + const ImageIndex & /*imageIndex*/) const +{ + return getFormat(); +} +GLsizei Renderbuffer::getAttachmentSamples(const ImageIndex & /*imageIndex*/) const +{ + return getSamples(); } + +InitState Renderbuffer::initState(const gl::ImageIndex & /*imageIndex*/) const +{ + if (isEGLImageTarget()) + { + return sourceEGLImageInitState(); + } + + return mInitState; +} + +void Renderbuffer::setInitState(const gl::ImageIndex & /*imageIndex*/, InitState initState) +{ + if (isEGLImageTarget()) + { + setSourceEGLImageInitState(initState); + } + else + { + mInitState = initState; + } +} + +rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const +{ + return mRenderbuffer; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h index 04af03e879..def18e6ff7 100644 --- a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h @@ -17,6 +17,7 @@ #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Image.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/RenderbufferImpl.h" namespace gl @@ -27,26 +28,30 @@ namespace gl // attachment point. class Renderbuffer final : public egl::ImageSibling, - public gl::FramebufferAttachmentObject, public LabeledObject { public: Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); - virtual ~Renderbuffer(); + ~Renderbuffer() override; + + Error onDestroy(const Context *context) override; 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); + Error setStorage(const Context *context, GLenum internalformat, size_t width, size_t height); + Error setStorageMultisample(const Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height); + Error setStorageEGLImageTarget(const Context *context, egl::Image *imageTarget); - rx::RenderbufferImpl *getImplementation(); - const rx::RenderbufferImpl *getImplementation() const; + rx::RenderbufferImpl *getImplementation() const; GLsizei getWidth() const; GLsizei getHeight() const; - GLenum getInternalFormat() const; + const Format &getFormat() const; GLsizei getSamples() const; GLuint getRedSize() const; GLuint getGreenSize() const; @@ -56,16 +61,19 @@ class Renderbuffer final : public egl::ImageSibling, 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(); } + Extents getAttachmentSize(const ImageIndex &imageIndex) const override; + const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; - void onAttach() override; - void onDetach() override; + void onAttach(const Context *context) override; + void onDetach(const Context *context) override; GLuint getId() const override; + InitState initState(const ImageIndex &imageIndex) const override; + void setInitState(const ImageIndex &imageIndex, InitState initState) override; + private: - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mRenderbuffer; } + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; rx::RenderbufferImpl *mRenderbuffer; @@ -73,10 +81,13 @@ class Renderbuffer final : public egl::ImageSibling, GLsizei mWidth; GLsizei mHeight; - GLenum mInternalFormat; + Format mFormat; GLsizei mSamples; + + // For robust resource init. + InitState mInitState; }; -} +} // namespace gl #endif // LIBANGLE_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp index dc9dad1e9f..79eb7e5f42 100644 --- a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp @@ -1,456 +1,483 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and -// retrieves objects which may be shared by multiple Contexts. +// ResourceManager.cpp: Implements the the ResourceManager classes, which handle allocation and +// lifetime of GL objects. #include "libANGLE/ResourceManager.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Path.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Sampler.h" #include "libANGLE/Shader.h" #include "libANGLE/Texture.h" -#include "libANGLE/Sampler.h" -#include "libANGLE/Fence.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" namespace gl { -ResourceManager::ResourceManager(rx::ImplFactory *factory) - : mFactory(factory), - mRefCount(1) + +namespace +{ + +template +GLuint AllocateEmptyObject(HandleAllocator *handleAllocator, ResourceMap *objectMap) { + GLuint handle = handleAllocator->allocate(); + objectMap->assign(handle, nullptr); + return handle; } -ResourceManager::~ResourceManager() +} // anonymous namespace + +template +ResourceManagerBase::ResourceManagerBase() : mRefCount(1) { - while (!mBufferMap.empty()) - { - deleteBuffer(mBufferMap.begin()->first); - } +} - while (!mProgramMap.empty()) - { - deleteProgram(mProgramMap.begin()->first); - } +template +void ResourceManagerBase::addRef() +{ + mRefCount++; +} - while (!mShaderMap.empty()) +template +void ResourceManagerBase::release(const Context *context) +{ + if (--mRefCount == 0) { - deleteShader(mShaderMap.begin()->first); + reset(context); + delete this; } +} - while (!mRenderbufferMap.empty()) - { - deleteRenderbuffer(mRenderbufferMap.begin()->first); - } +template +TypedResourceManager::~TypedResourceManager() +{ + ASSERT(mObjectMap.empty()); +} - while (!mTextureMap.empty()) +template +void TypedResourceManager::reset(const Context *context) +{ + this->mHandleAllocator.reset(); + for (const auto &resource : mObjectMap) { - deleteTexture(mTextureMap.begin()->first); + if (resource.second) + { + ImplT::DeleteObject(context, resource.second); + } } + mObjectMap.clear(); +} - while (!mSamplerMap.empty()) +template +void TypedResourceManager::deleteObject( + const Context *context, + GLuint handle) +{ + ResourceType *resource = nullptr; + if (!mObjectMap.erase(handle, &resource)) { - deleteSampler(mSamplerMap.begin()->first); + return; } - while (!mFenceSyncMap.empty()) + // Requires an explicit this-> because of C++ template rules. + this->mHandleAllocator.release(handle); + + if (resource) { - deleteFenceSync(mFenceSyncMap.begin()->first); + ImplT::DeleteObject(context, resource); } } -void ResourceManager::addRef() +template class ResourceManagerBase; +template class ResourceManagerBase; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; +template class TypedResourceManager; + +// BufferManager Implementation. + +// static +Buffer *BufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) { - mRefCount++; + Buffer *buffer = new Buffer(factory, handle); + buffer->addRef(); + return buffer; } -void ResourceManager::release() +// static +void BufferManager::DeleteObject(const Context *context, Buffer *buffer) { - if (--mRefCount == 0) - { - delete this; - } + buffer->release(context); } -// Returns an unused buffer name -GLuint ResourceManager::createBuffer() +GLuint BufferManager::createBuffer() { - GLuint handle = mBufferHandleAllocator.allocate(); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} - mBufferMap[handle] = NULL; +Buffer *BufferManager::getBuffer(GLuint handle) const +{ + return mObjectMap.query(handle); +} - return handle; +// ShaderProgramManager Implementation. + +ShaderProgramManager::ShaderProgramManager() +{ } -// Returns an unused shader/program name -GLuint ResourceManager::createShader(const gl::Limitations &rendererLimitations, GLenum type) +ShaderProgramManager::~ShaderProgramManager() { - GLuint handle = mProgramShaderHandleAllocator.allocate(); + ASSERT(mPrograms.empty()); + ASSERT(mShaders.empty()); +} - if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) +void ShaderProgramManager::reset(const Context *context) +{ + while (!mPrograms.empty()) { - mShaderMap[handle] = new Shader(this, mFactory, rendererLimitations, type, handle); + deleteProgram(context, mPrograms.begin()->first); } - else UNREACHABLE(); - - return handle; + mPrograms.clear(); + while (!mShaders.empty()) + { + deleteShader(context, mShaders.begin()->first); + } + mShaders.clear(); } -// Returns an unused program/shader name -GLuint ResourceManager::createProgram() +GLuint ShaderProgramManager::createShader(rx::GLImplFactory *factory, + const gl::Limitations &rendererLimitations, + GLenum type) { - GLuint handle = mProgramShaderHandleAllocator.allocate(); - - mProgramMap[handle] = new Program(mFactory, this, handle); - + ASSERT(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER || type == GL_COMPUTE_SHADER || + type == GL_GEOMETRY_SHADER_EXT); + GLuint handle = mHandleAllocator.allocate(); + mShaders.assign(handle, new Shader(this, factory, rendererLimitations, type, handle)); return handle; } -// Returns an unused texture name -GLuint ResourceManager::createTexture() +void ShaderProgramManager::deleteShader(const Context *context, GLuint shader) { - GLuint handle = mTextureHandleAllocator.allocate(); - - mTextureMap[handle] = NULL; - - return handle; + deleteObject(context, &mShaders, shader); } -// Returns an unused renderbuffer name -GLuint ResourceManager::createRenderbuffer() +Shader *ShaderProgramManager::getShader(GLuint handle) const { - GLuint handle = mRenderbufferHandleAllocator.allocate(); - - mRenderbufferMap[handle] = NULL; - - return handle; + return mShaders.query(handle); } -// Returns an unused sampler name -GLuint ResourceManager::createSampler() +GLuint ShaderProgramManager::createProgram(rx::GLImplFactory *factory) { - GLuint handle = mSamplerHandleAllocator.allocate(); - - mSamplerMap[handle] = NULL; - + GLuint handle = mHandleAllocator.allocate(); + mPrograms.assign(handle, new Program(factory, this, handle)); return handle; } -// Returns the next unused fence name, and allocates the fence -GLuint ResourceManager::createFenceSync() +void ShaderProgramManager::deleteProgram(const gl::Context *context, GLuint program) { - GLuint handle = mFenceSyncHandleAllocator.allocate(); - - FenceSync *fenceSync = new FenceSync(mFactory->createFenceSync(), handle); - fenceSync->addRef(); - mFenceSyncMap[handle] = fenceSync; + deleteObject(context, &mPrograms, program); +} - return handle; +Program *ShaderProgramManager::getProgram(GLuint handle) const +{ + return mPrograms.query(handle); } -void ResourceManager::deleteBuffer(GLuint buffer) +template +void ShaderProgramManager::deleteObject(const Context *context, + ResourceMap *objectMap, + GLuint id) { - BufferMap::iterator bufferObject = mBufferMap.find(buffer); + ObjectType *object = objectMap->query(id); + if (!object) + { + return; + } - if (bufferObject != mBufferMap.end()) + if (object->getRefCount() == 0) + { + mHandleAllocator.release(id); + object->onDestroy(context); + objectMap->erase(id, &object); + } + else { - mBufferHandleAllocator.release(bufferObject->first); - if (bufferObject->second) bufferObject->second->release(); - mBufferMap.erase(bufferObject); + object->flagForDeletion(); } } -void ResourceManager::deleteShader(GLuint shader) +// TextureManager Implementation. + +// static +Texture *TextureManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle, GLenum target) { - ShaderMap::iterator shaderObject = mShaderMap.find(shader); + Texture *texture = new Texture(factory, handle, target); + texture->addRef(); + return texture; +} - if (shaderObject != mShaderMap.end()) - { - if (shaderObject->second->getRefCount() == 0) - { - mProgramShaderHandleAllocator.release(shaderObject->first); - delete shaderObject->second; - mShaderMap.erase(shaderObject); - } - else - { - shaderObject->second->flagForDeletion(); - } - } +// static +void TextureManager::DeleteObject(const Context *context, Texture *texture) +{ + texture->release(context); } -void ResourceManager::deleteProgram(GLuint program) +GLuint TextureManager::createTexture() { - ProgramMap::iterator programObject = mProgramMap.find(program); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} + +Texture *TextureManager::getTexture(GLuint handle) const +{ + ASSERT(mObjectMap.query(0) == nullptr); + return mObjectMap.query(handle); +} - if (programObject != mProgramMap.end()) +void TextureManager::signalAllTexturesDirty() const +{ + for (const auto &texture : mObjectMap) { - if (programObject->second->getRefCount() == 0) + if (texture.second) { - mProgramShaderHandleAllocator.release(programObject->first); - delete programObject->second; - mProgramMap.erase(programObject); - } - else - { - programObject->second->flagForDeletion(); + // We don't know if the Texture needs init, but that's ok, since it will only force + // a re-check, and will not initialize the pixels if it's not needed. + texture.second->signalDirty(InitState::MayNeedInit); } } } -void ResourceManager::deleteTexture(GLuint texture) -{ - TextureMap::iterator textureObject = mTextureMap.find(texture); +// RenderbufferManager Implementation. - if (textureObject != mTextureMap.end()) - { - mTextureHandleAllocator.release(textureObject->first); - if (textureObject->second) textureObject->second->release(); - mTextureMap.erase(textureObject); - } +// static +Renderbuffer *RenderbufferManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) +{ + Renderbuffer *renderbuffer = new Renderbuffer(factory->createRenderbuffer(), handle); + renderbuffer->addRef(); + return renderbuffer; } -void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) +// static +void RenderbufferManager::DeleteObject(const Context *context, Renderbuffer *renderbuffer) { - RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + renderbuffer->release(context); +} - if (renderbufferObject != mRenderbufferMap.end()) - { - mRenderbufferHandleAllocator.release(renderbufferObject->first); - if (renderbufferObject->second) renderbufferObject->second->release(); - mRenderbufferMap.erase(renderbufferObject); - } +GLuint RenderbufferManager::createRenderbuffer() +{ + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } -void ResourceManager::deleteSampler(GLuint sampler) +Renderbuffer *RenderbufferManager::getRenderbuffer(GLuint handle) const { - auto samplerObject = mSamplerMap.find(sampler); + return mObjectMap.query(handle); +} - if (samplerObject != mSamplerMap.end()) - { - mSamplerHandleAllocator.release(samplerObject->first); - if (samplerObject->second) samplerObject->second->release(); - mSamplerMap.erase(samplerObject); - } +// SamplerManager Implementation. + +// static +Sampler *SamplerManager::AllocateNewObject(rx::GLImplFactory *factory, GLuint handle) +{ + Sampler *sampler = new Sampler(factory, handle); + sampler->addRef(); + return sampler; } -void ResourceManager::deleteFenceSync(GLuint fenceSync) +// static +void SamplerManager::DeleteObject(const Context *context, Sampler *sampler) { - auto fenceObjectIt = mFenceSyncMap.find(fenceSync); + sampler->release(context); +} - if (fenceObjectIt != mFenceSyncMap.end()) - { - mFenceSyncHandleAllocator.release(fenceObjectIt->first); - if (fenceObjectIt->second) fenceObjectIt->second->release(); - mFenceSyncMap.erase(fenceObjectIt); - } +GLuint SamplerManager::createSampler() +{ + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } -Buffer *ResourceManager::getBuffer(unsigned int handle) +Sampler *SamplerManager::getSampler(GLuint handle) const { - BufferMap::iterator buffer = mBufferMap.find(handle); + return mObjectMap.query(handle); +} - if (buffer == mBufferMap.end()) - { - return NULL; - } - else - { - return buffer->second; - } +bool SamplerManager::isSampler(GLuint sampler) const +{ + return mObjectMap.contains(sampler); } -Shader *ResourceManager::getShader(unsigned int handle) +// SyncManager Implementation. + +// static +void SyncManager::DeleteObject(const Context *context, Sync *sync) { - ShaderMap::iterator shader = mShaderMap.find(handle); + sync->release(context); +} - if (shader == mShaderMap.end()) - { - return NULL; - } - else - { - return shader->second; - } +GLuint SyncManager::createSync(rx::GLImplFactory *factory) +{ + GLuint handle = mHandleAllocator.allocate(); + Sync *sync = new Sync(factory->createSync(), handle); + sync->addRef(); + mObjectMap.assign(handle, sync); + return handle; } -Texture *ResourceManager::getTexture(unsigned int handle) +Sync *SyncManager::getSync(GLuint handle) const { - if (handle == 0) return NULL; + return mObjectMap.query(handle); +} - TextureMap::iterator texture = mTextureMap.find(handle); +// PathManager Implementation. - if (texture == mTextureMap.end()) - { - return NULL; - } - else - { - return texture->second; - } +PathManager::PathManager() +{ } -Program *ResourceManager::getProgram(unsigned int handle) const +ErrorOrResult PathManager::createPaths(rx::GLImplFactory *factory, GLsizei range) { - ProgramMap::const_iterator program = mProgramMap.find(handle); + // Allocate client side handles. + const GLuint client = mHandleAllocator.allocateRange(static_cast(range)); + if (client == HandleRangeAllocator::kInvalidHandle) + return OutOfMemory() << "Failed to allocate path handle range."; - if (program == mProgramMap.end()) + const auto &paths = factory->createPaths(range); + if (paths.empty()) { - return NULL; + mHandleAllocator.releaseRange(client, range); + return OutOfMemory() << "Failed to allocate path objects."; } - else + + for (GLsizei i = 0; i < range; ++i) { - return program->second; + rx::PathImpl *impl = paths[static_cast(i)]; + const auto id = client + i; + mPaths.assign(id, new Path(impl)); } + return client; } -Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) +void PathManager::deletePaths(GLuint first, GLsizei range) { - RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); - - if (renderbuffer == mRenderbufferMap.end()) + for (GLsizei i = 0; i < range; ++i) { - return NULL; - } - else - { - return renderbuffer->second; + const auto id = first + i; + Path *p = nullptr; + if (!mPaths.erase(id, &p)) + continue; + delete p; } + mHandleAllocator.releaseRange(first, static_cast(range)); } -Sampler *ResourceManager::getSampler(unsigned int handle) +Path *PathManager::getPath(GLuint handle) const { - auto sampler = mSamplerMap.find(handle); + return mPaths.query(handle); +} - if (sampler == mSamplerMap.end()) - { - return NULL; - } - else - { - return sampler->second; - } +bool PathManager::hasPath(GLuint handle) const +{ + return mHandleAllocator.isUsed(handle); } -FenceSync *ResourceManager::getFenceSync(unsigned int handle) +PathManager::~PathManager() { - auto fenceObjectIt = mFenceSyncMap.find(handle); + ASSERT(mPaths.empty()); +} - if (fenceObjectIt == mFenceSyncMap.end()) - { - return NULL; - } - else +void PathManager::reset(const Context *context) +{ + for (auto path : mPaths) { - return fenceObjectIt->second; + SafeDelete(path.second); } + mPaths.clear(); } -void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +// FramebufferManager Implementation. + +// static +Framebuffer *FramebufferManager::AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle, + const Caps &caps) { - mRenderbufferMap[handle] = buffer; + return new Framebuffer(caps, factory, handle); } -void ResourceManager::checkBufferAllocation(GLuint handle) +// static +void FramebufferManager::DeleteObject(const Context *context, Framebuffer *framebuffer) { - if (handle != 0) + // Default framebuffer are owned by their respective Surface + if (framebuffer->id() != 0) { - auto bufferMapIt = mBufferMap.find(handle); - bool handleAllocated = (bufferMapIt != mBufferMap.end()); - - if (handleAllocated && bufferMapIt->second != nullptr) - { - return; - } - - Buffer *buffer = new Buffer(mFactory->createBuffer(), handle); - buffer->addRef(); - - if (handleAllocated) - { - bufferMapIt->second = buffer; - } - else - { - mBufferHandleAllocator.reserve(handle); - mBufferMap[handle] = buffer; - } + framebuffer->onDestroy(context); + delete framebuffer; } } -void ResourceManager::checkTextureAllocation(GLuint handle, GLenum type) +GLuint FramebufferManager::createFramebuffer() { - if (handle != 0) - { - auto textureMapIt = mTextureMap.find(handle); - bool handleAllocated = (textureMapIt != mTextureMap.end()); - - if (handleAllocated && textureMapIt->second != nullptr) - { - return; - } + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); +} - Texture *texture = new Texture(mFactory->createTexture(type), handle, type); - texture->addRef(); +Framebuffer *FramebufferManager::getFramebuffer(GLuint handle) const +{ + return mObjectMap.query(handle); +} - if (handleAllocated) - { - textureMapIt->second = texture; - } - else - { - mTextureHandleAllocator.reserve(handle); - mTextureMap[handle] = texture; - } - } +void FramebufferManager::setDefaultFramebuffer(Framebuffer *framebuffer) +{ + ASSERT(framebuffer == nullptr || framebuffer->id() == 0); + mObjectMap.assign(0, framebuffer); } -void ResourceManager::checkRenderbufferAllocation(GLuint handle) +void FramebufferManager::invalidateFramebufferComplenessCache() const { - if (handle != 0) + for (const auto &framebuffer : mObjectMap) { - auto renderbufferMapIt = mRenderbufferMap.find(handle); - bool handleAllocated = (renderbufferMapIt != mRenderbufferMap.end()); - - if (handleAllocated && renderbufferMapIt->second != nullptr) + if (framebuffer.second) { - return; + framebuffer.second->invalidateCompletenessCache(); } + } +} - Renderbuffer *renderbuffer = new Renderbuffer(mFactory->createRenderbuffer(), handle); - renderbuffer->addRef(); +// ProgramPipelineManager Implementation. - if (handleAllocated) - { - renderbufferMapIt->second = renderbuffer; - } - else - { - mRenderbufferHandleAllocator.reserve(handle); - mRenderbufferMap[handle] = renderbuffer; - } - } +// static +ProgramPipeline *ProgramPipelineManager::AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle) +{ + ProgramPipeline *pipeline = new ProgramPipeline(factory, handle); + pipeline->addRef(); + return pipeline; } -void ResourceManager::checkSamplerAllocation(GLuint sampler) +// static +void ProgramPipelineManager::DeleteObject(const Context *context, ProgramPipeline *pipeline) { - if (sampler != 0 && !getSampler(sampler)) - { - Sampler *samplerObject = new Sampler(mFactory, sampler); - mSamplerMap[sampler] = samplerObject; - samplerObject->addRef(); - // Samplers cannot be created via Bind - } + pipeline->release(context); } -bool ResourceManager::isSampler(GLuint sampler) +GLuint ProgramPipelineManager::createProgramPipeline() { - return mSamplerMap.find(sampler) != mSamplerMap.end(); + return AllocateEmptyObject(&mHandleAllocator, &mObjectMap); } +ProgramPipeline *ProgramPipelineManager::getProgramPipeline(GLuint handle) const +{ + return mObjectMap.query(handle); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.h b/src/3rdparty/angle/src/libANGLE/ResourceManager.h index 2073e9d728..2dfeff5234 100644 --- a/src/3rdparty/angle/src/libANGLE/ResourceManager.h +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.h @@ -1,115 +1,289 @@ // -// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// ResourceManager.h : Defines the ResourceManager class, which tracks objects -// shared by multiple GL contexts. +// ResourceManager.h : Defines the ResourceManager classes, which handle allocation and lifetime of +// GL objects. #ifndef LIBANGLE_RESOURCEMANAGER_H_ #define LIBANGLE_RESOURCEMANAGER_H_ #include "angle_gl.h" #include "common/angleutils.h" -#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" #include "libANGLE/HandleAllocator.h" - -#include +#include "libANGLE/HandleRangeAllocator.h" +#include "libANGLE/ResourceMap.h" namespace rx { -class ImplFactory; +class GLImplFactory; } namespace gl { class Buffer; -struct Data; -class FenceSync; +struct Caps; +class Context; +class Sync; +class Framebuffer; struct Limitations; +class Path; class Program; +class ProgramPipeline; class Renderbuffer; class Sampler; class Shader; class Texture; -class ResourceManager : angle::NonCopyable +template +class ResourceManagerBase : angle::NonCopyable { public: - explicit ResourceManager(rx::ImplFactory *factory); - ~ResourceManager(); + ResourceManagerBase(); void addRef(); - void release(); + void release(const Context *context); + + protected: + virtual void reset(const Context *context) = 0; + virtual ~ResourceManagerBase() {} + + HandleAllocatorType mHandleAllocator; + + private: + size_t mRefCount; +}; + +template +class TypedResourceManager : public ResourceManagerBase +{ + public: + TypedResourceManager() {} + + void deleteObject(const Context *context, GLuint handle); + bool isHandleGenerated(GLuint handle) const + { + // Zero is always assumed to have been generated implicitly. + return handle == 0 || mObjectMap.contains(handle); + } + + protected: + ~TypedResourceManager() override; + + // Inlined in the header for performance. + template + ResourceType *checkObjectAllocation(rx::GLImplFactory *factory, GLuint handle, ArgTypes... args) + { + ResourceType *value = mObjectMap.query(handle); + if (value) + { + return value; + } + + if (handle == 0) + { + return nullptr; + } + + ResourceType *object = ImplT::AllocateNewObject(factory, handle, args...); + + if (!mObjectMap.contains(handle)) + { + this->mHandleAllocator.reserve(handle); + } + mObjectMap.assign(handle, object); + + return object; + } + + void reset(const Context *context) override; + + ResourceMap mObjectMap; +}; +class BufferManager : public TypedResourceManager +{ + public: GLuint createBuffer(); - GLuint createShader(const gl::Limitations &rendererLimitations, GLenum type); - GLuint createProgram(); + Buffer *getBuffer(GLuint handle) const; + + Buffer *checkBufferAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } + + // TODO(jmadill): Investigate design which doesn't expose these methods publicly. + static Buffer *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Buffer *buffer); + + protected: + ~BufferManager() override {} +}; + +class ShaderProgramManager : public ResourceManagerBase +{ + public: + ShaderProgramManager(); + + GLuint createShader(rx::GLImplFactory *factory, + const Limitations &rendererLimitations, + GLenum type); + void deleteShader(const Context *context, GLuint shader); + Shader *getShader(GLuint handle) const; + + GLuint createProgram(rx::GLImplFactory *factory); + void deleteProgram(const Context *context, GLuint program); + Program *getProgram(GLuint handle) const; + + protected: + ~ShaderProgramManager() override; + + private: + template + void deleteObject(const Context *context, ResourceMap *objectMap, GLuint id); + + void reset(const Context *context) override; + + ResourceMap mShaders; + ResourceMap mPrograms; +}; + +class TextureManager : public TypedResourceManager +{ + public: GLuint createTexture(); + Texture *getTexture(GLuint handle) const; + + void signalAllTexturesDirty() const; + + Texture *checkTextureAllocation(rx::GLImplFactory *factory, GLuint handle, GLenum target) + { + return checkObjectAllocation(factory, handle, target); + } + + static Texture *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle, GLenum target); + static void DeleteObject(const Context *context, Texture *texture); + + protected: + ~TextureManager() override {} +}; + +class RenderbufferManager + : public TypedResourceManager +{ + public: GLuint createRenderbuffer(); + Renderbuffer *getRenderbuffer(GLuint handle) const; + + Renderbuffer *checkRenderbufferAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } + + static Renderbuffer *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Renderbuffer *renderbuffer); + + protected: + ~RenderbufferManager() override {} +}; + +class SamplerManager : public TypedResourceManager +{ + public: GLuint createSampler(); - GLuint createFenceSync(); - - void deleteBuffer(GLuint buffer); - void deleteShader(GLuint shader); - void deleteProgram(GLuint program); - void deleteTexture(GLuint texture); - void deleteRenderbuffer(GLuint renderbuffer); - void deleteSampler(GLuint sampler); - void deleteFenceSync(GLuint fenceSync); - - Buffer *getBuffer(GLuint handle); - Shader *getShader(GLuint handle); - Program *getProgram(GLuint handle) const; - Texture *getTexture(GLuint handle); - Renderbuffer *getRenderbuffer(GLuint handle); - Sampler *getSampler(GLuint handle); - FenceSync *getFenceSync(GLuint handle); + Sampler *getSampler(GLuint handle) const; + bool isSampler(GLuint sampler) const; + + Sampler *checkSamplerAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } - void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + static Sampler *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, Sampler *sampler); - void checkBufferAllocation(GLuint handle); - void checkTextureAllocation(GLuint handle, GLenum type); - void checkRenderbufferAllocation(GLuint handle); - void checkSamplerAllocation(GLuint sampler); + protected: + ~SamplerManager() override {} +}; + +class SyncManager : public TypedResourceManager +{ + public: + GLuint createSync(rx::GLImplFactory *factory); + Sync *getSync(GLuint handle) const; + + static void DeleteObject(const Context *context, Sync *sync); + + protected: + ~SyncManager() override {} +}; + +class PathManager : public ResourceManagerBase +{ + public: + PathManager(); - bool isSampler(GLuint sampler); + ErrorOrResult createPaths(rx::GLImplFactory *factory, GLsizei range); + void deletePaths(GLuint first, GLsizei range); + Path *getPath(GLuint handle) const; + bool hasPath(GLuint handle) const; + + protected: + ~PathManager() override; + void reset(const Context *context) override; private: - void createTextureInternal(GLuint handle); + ResourceMap mPaths; +}; - rx::ImplFactory *mFactory; - std::size_t mRefCount; +class FramebufferManager + : public TypedResourceManager +{ + public: + GLuint createFramebuffer(); + Framebuffer *getFramebuffer(GLuint handle) const; + void setDefaultFramebuffer(Framebuffer *framebuffer); - typedef std::map BufferMap; - BufferMap mBufferMap; - HandleAllocator mBufferHandleAllocator; + void invalidateFramebufferComplenessCache() const; - typedef std::map ShaderMap; - ShaderMap mShaderMap; + Framebuffer *checkFramebufferAllocation(rx::GLImplFactory *factory, + const Caps &caps, + GLuint handle) + { + return checkObjectAllocation(factory, handle, caps); + } - typedef std::map ProgramMap; - ProgramMap mProgramMap; - HandleAllocator mProgramShaderHandleAllocator; + static Framebuffer *AllocateNewObject(rx::GLImplFactory *factory, + GLuint handle, + const Caps &caps); + static void DeleteObject(const Context *context, Framebuffer *framebuffer); - typedef std::map TextureMap; - TextureMap mTextureMap; - HandleAllocator mTextureHandleAllocator; + protected: + ~FramebufferManager() override {} +}; - typedef std::map RenderbufferMap; - RenderbufferMap mRenderbufferMap; - HandleAllocator mRenderbufferHandleAllocator; +class ProgramPipelineManager + : public TypedResourceManager +{ + public: + GLuint createProgramPipeline(); + ProgramPipeline *getProgramPipeline(GLuint handle) const; - typedef std::map SamplerMap; - SamplerMap mSamplerMap; - HandleAllocator mSamplerHandleAllocator; + ProgramPipeline *checkProgramPipelineAllocation(rx::GLImplFactory *factory, GLuint handle) + { + return checkObjectAllocation(factory, handle); + } - typedef std::map FenceMap; - FenceMap mFenceSyncMap; - HandleAllocator mFenceSyncHandleAllocator; + static ProgramPipeline *AllocateNewObject(rx::GLImplFactory *factory, GLuint handle); + static void DeleteObject(const Context *context, ProgramPipeline *pipeline); + + protected: + ~ProgramPipelineManager() override {} }; -} +} // namespace gl #endif // LIBANGLE_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceMap.h b/src/3rdparty/angle/src/libANGLE/ResourceMap.h new file mode 100644 index 0000000000..b00da68612 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceMap.h @@ -0,0 +1,305 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ResourceMap: +// An optimized resource map which packs the first set of allocated objects into a +// flat array, and then falls back to an unordered map for the higher handle values. +// + +#ifndef LIBANGLE_RESOURCE_MAP_H_ +#define LIBANGLE_RESOURCE_MAP_H_ + +#include "libANGLE/angletypes.h" + +namespace gl +{ + +template +class ResourceMap final : angle::NonCopyable +{ + public: + ResourceMap(); + ~ResourceMap(); + + ResourceType *query(GLuint handle) const; + + // Returns true if the handle was reserved. Not necessarily if the resource is created. + bool contains(GLuint handle) const; + + // Returns the element that was at this location. + bool erase(GLuint handle, ResourceType **resourceOut); + + void assign(GLuint handle, ResourceType *resource); + + // Clears the map. + void clear(); + + using IndexAndResource = std::pair; + using HashMap = std::unordered_map; + + class Iterator final + { + public: + bool operator==(const Iterator &other) const; + bool operator!=(const Iterator &other) const; + Iterator &operator++(); + const IndexAndResource *operator->() const; + const IndexAndResource &operator*() const; + + private: + friend class ResourceMap; + Iterator(const ResourceMap &origin, + GLuint flatIndex, + typename HashMap::const_iterator hashIndex); + void updateValue(); + + const ResourceMap &mOrigin; + GLuint mFlatIndex; + typename HashMap::const_iterator mHashIndex; + IndexAndResource mValue; + }; + + // null values represent reserved handles. + Iterator begin() const; + Iterator end() const; + Iterator find(GLuint handle) const; + + // Not a constant-time operation, should only be used for verification. + bool empty() const; + + private: + friend class Iterator; + + GLuint nextNonNullResource(size_t flatIndex) const; + + // constexpr methods cannot contain reinterpret_cast, so we need a static method. + static ResourceType *InvalidPointer(); + static constexpr intptr_t kInvalidPointer = static_cast(-1); + + // Start with 32 maximum elements in the map, which can grow. + static constexpr size_t kInitialFlatResourcesSize = 0x20; + + // Experimental testing suggests that 16k is a reasonable upper limit. + static constexpr size_t kFlatResourcesLimit = 0x4000; + + std::vector mFlatResources; + + // A map of GL objects indexed by object ID. + HashMap mHashedResources; +}; + +template +ResourceMap::ResourceMap() + : mFlatResources(kInitialFlatResourcesSize, InvalidPointer()), mHashedResources() +{ +} + +template +ResourceMap::~ResourceMap() +{ + ASSERT(empty()); +} + +template +ResourceType *ResourceMap::query(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + auto value = mFlatResources[handle]; + return (value == InvalidPointer() ? nullptr : value); + } + auto it = mHashedResources.find(handle); + return (it == mHashedResources.end() ? nullptr : it->second); +} + +template +bool ResourceMap::contains(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + return (mFlatResources[handle] != InvalidPointer()); + } + return (mHashedResources.find(handle) != mHashedResources.end()); +} + +template +bool ResourceMap::erase(GLuint handle, ResourceType **resourceOut) +{ + if (handle < mFlatResources.size()) + { + auto &value = mFlatResources[handle]; + if (value == InvalidPointer()) + { + return false; + } + *resourceOut = value; + value = InvalidPointer(); + } + else + { + auto it = mHashedResources.find(handle); + if (it == mHashedResources.end()) + { + return false; + } + *resourceOut = it->second; + mHashedResources.erase(it); + } + return true; +} + +template +void ResourceMap::assign(GLuint handle, ResourceType *resource) +{ + if (handle < kFlatResourcesLimit) + { + if (handle >= mFlatResources.size()) + { + // Use power-of-two. + size_t newSize = mFlatResources.size(); + while (newSize <= handle) + { + newSize *= 2; + } + mFlatResources.resize(newSize, nullptr); + } + ASSERT(mFlatResources.size() > handle); + mFlatResources[handle] = resource; + } + else + { + mHashedResources[handle] = resource; + } +} + +template +typename ResourceMap::Iterator ResourceMap::begin() const +{ + return Iterator(*this, nextNonNullResource(0), mHashedResources.begin()); +} + +template +typename ResourceMap::Iterator ResourceMap::end() const +{ + return Iterator(*this, static_cast(mFlatResources.size()), mHashedResources.end()); +} + +template +typename ResourceMap::Iterator ResourceMap::find(GLuint handle) const +{ + if (handle < mFlatResources.size()) + { + return (mFlatResources[handle] != InvalidPointer() + ? Iterator(handle, mHashedResources.begin()) + : end()); + } + else + { + return mHashedResources.find(handle); + } +} + +template +bool ResourceMap::empty() const +{ + return (begin() == end()); +} + +template +void ResourceMap::clear() +{ + mFlatResources.assign(kInitialFlatResourcesSize, InvalidPointer()); + mHashedResources.clear(); +} + +template +GLuint ResourceMap::nextNonNullResource(size_t flatIndex) const +{ + for (size_t index = flatIndex; index < mFlatResources.size(); index++) + { + if (mFlatResources[index] != nullptr && mFlatResources[index] != InvalidPointer()) + { + return static_cast(index); + } + } + return static_cast(mFlatResources.size()); +} + +template +// static +ResourceType *ResourceMap::InvalidPointer() +{ + return reinterpret_cast(kInvalidPointer); +} + +template +ResourceMap::Iterator::Iterator( + const ResourceMap &origin, + GLuint flatIndex, + typename ResourceMap::HashMap::const_iterator hashIndex) + : mOrigin(origin), mFlatIndex(flatIndex), mHashIndex(hashIndex), mValue() +{ + updateValue(); +} + +template +bool ResourceMap::Iterator::operator==(const Iterator &other) const +{ + return (mFlatIndex == other.mFlatIndex && mHashIndex == other.mHashIndex); +} + +template +bool ResourceMap::Iterator::operator!=(const Iterator &other) const +{ + return !(*this == other); +} + +template +typename ResourceMap::Iterator &ResourceMap::Iterator::operator++() +{ + if (mFlatIndex < static_cast(mOrigin.mFlatResources.size())) + { + mFlatIndex = mOrigin.nextNonNullResource(mFlatIndex + 1); + } + else + { + mHashIndex++; + } + updateValue(); + return *this; +} + +template +const typename ResourceMap::IndexAndResource + *ResourceMap::Iterator::operator->() const +{ + return &mValue; +} + +template +const typename ResourceMap::IndexAndResource + &ResourceMap::Iterator::operator*() const +{ + return mValue; +} + +template +void ResourceMap::Iterator::updateValue() +{ + if (mFlatIndex < static_cast(mOrigin.mFlatResources.size())) + { + mValue.first = mFlatIndex; + mValue.second = mOrigin.mFlatResources[mFlatIndex]; + } + else if (mHashIndex != mOrigin.mHashedResources.end()) + { + mValue.first = mHashIndex->first; + mValue.second = mHashIndex->second; + } +} + +} // namespace gl + +#endif // LIBANGLE_RESOURCE_MAP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.cpp b/src/3rdparty/angle/src/libANGLE/Sampler.cpp index d8d606a46f..0f05b697a2 100644 --- a/src/3rdparty/angle/src/libANGLE/Sampler.cpp +++ b/src/3rdparty/angle/src/libANGLE/Sampler.cpp @@ -9,14 +9,14 @@ #include "libANGLE/Sampler.h" #include "libANGLE/angletypes.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/SamplerImpl.h" namespace gl { -Sampler::Sampler(rx::ImplFactory *factory, GLuint id) - : RefCountObject(id), mImpl(factory->createSampler()), mLabel(), mSamplerState() +Sampler::Sampler(rx::GLImplFactory *factory, GLuint id) + : RefCountObject(id), mState(), mImpl(factory->createSampler(mState)), mLabel() { } @@ -25,6 +25,11 @@ Sampler::~Sampler() SafeDelete(mImpl); } +Error Sampler::onDestroy(const Context *context) +{ + return NoError(); +} + void Sampler::setLabel(const std::string &label) { mLabel = label; @@ -37,116 +42,128 @@ const std::string &Sampler::getLabel() const void Sampler::setMinFilter(GLenum minFilter) { - mSamplerState.minFilter = minFilter; + mState.minFilter = minFilter; } GLenum Sampler::getMinFilter() const { - return mSamplerState.minFilter; + return mState.minFilter; } void Sampler::setMagFilter(GLenum magFilter) { - mSamplerState.magFilter = magFilter; + mState.magFilter = magFilter; } GLenum Sampler::getMagFilter() const { - return mSamplerState.magFilter; + return mState.magFilter; } void Sampler::setWrapS(GLenum wrapS) { - mSamplerState.wrapS = wrapS; + mState.wrapS = wrapS; } GLenum Sampler::getWrapS() const { - return mSamplerState.wrapS; + return mState.wrapS; } void Sampler::setWrapT(GLenum wrapT) { - mSamplerState.wrapT = wrapT; + mState.wrapT = wrapT; } GLenum Sampler::getWrapT() const { - return mSamplerState.wrapT; + return mState.wrapT; } void Sampler::setWrapR(GLenum wrapR) { - mSamplerState.wrapR = wrapR; + mState.wrapR = wrapR; } GLenum Sampler::getWrapR() const { - return mSamplerState.wrapR; + return mState.wrapR; } void Sampler::setMaxAnisotropy(float maxAnisotropy) { - mSamplerState.maxAnisotropy = maxAnisotropy; + mState.maxAnisotropy = maxAnisotropy; } float Sampler::getMaxAnisotropy() const { - return mSamplerState.maxAnisotropy; + return mState.maxAnisotropy; } void Sampler::setMinLod(GLfloat minLod) { - mSamplerState.minLod = minLod; + mState.minLod = minLod; } GLfloat Sampler::getMinLod() const { - return mSamplerState.minLod; + return mState.minLod; } void Sampler::setMaxLod(GLfloat maxLod) { - mSamplerState.maxLod = maxLod; + mState.maxLod = maxLod; } GLfloat Sampler::getMaxLod() const { - return mSamplerState.maxLod; + return mState.maxLod; } void Sampler::setCompareMode(GLenum compareMode) { - mSamplerState.compareMode = compareMode; + mState.compareMode = compareMode; } GLenum Sampler::getCompareMode() const { - return mSamplerState.compareMode; + return mState.compareMode; } void Sampler::setCompareFunc(GLenum compareFunc) { - mSamplerState.compareFunc = compareFunc; + mState.compareFunc = compareFunc; } GLenum Sampler::getCompareFunc() const { - return mSamplerState.compareFunc; + return mState.compareFunc; } -const SamplerState &Sampler::getSamplerState() const +void Sampler::setSRGBDecode(GLenum sRGBDecode) { - return mSamplerState; + mState.sRGBDecode = sRGBDecode; } -const rx::SamplerImpl *Sampler::getImplementation() const +GLenum Sampler::getSRGBDecode() const { - return mImpl; + return mState.sRGBDecode; +} + +const SamplerState &Sampler::getSamplerState() const +{ + return mState; } -rx::SamplerImpl *Sampler::getImplementation() +rx::SamplerImpl *Sampler::getImplementation() const { return mImpl; } + +void Sampler::syncState(const Context *context) +{ + // TODO(jmadill): Use actual dirty bits for sampler. + mImpl->syncState(context); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.h b/src/3rdparty/angle/src/libANGLE/Sampler.h index a40b1655fc..cd34273b44 100644 --- a/src/3rdparty/angle/src/libANGLE/Sampler.h +++ b/src/3rdparty/angle/src/libANGLE/Sampler.h @@ -16,7 +16,7 @@ namespace rx { -class ImplFactory; +class GLImplFactory; class SamplerImpl; } @@ -26,9 +26,11 @@ namespace gl class Sampler final : public RefCountObject, public LabeledObject { public: - Sampler(rx::ImplFactory *factory, GLuint id); + Sampler(rx::GLImplFactory *factory, GLuint id); ~Sampler() override; + Error onDestroy(const Context *context) override; + void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -62,19 +64,22 @@ class Sampler final : public RefCountObject, public LabeledObject void setCompareFunc(GLenum compareFunc); GLenum getCompareFunc() const; + void setSRGBDecode(GLenum sRGBDecode); + GLenum getSRGBDecode() const; + const SamplerState &getSamplerState() const; - const rx::SamplerImpl *getImplementation() const; - rx::SamplerImpl *getImplementation(); + rx::SamplerImpl *getImplementation() const; + + void syncState(const Context *context); private: + SamplerState mState; rx::SamplerImpl *mImpl; std::string mLabel; - - SamplerState mSamplerState; }; -} +} // namespace gl #endif // LIBANGLE_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Shader.cpp b/src/3rdparty/angle/src/libANGLE/Shader.cpp index bbe9077fc9..94c4f3c705 100644 --- a/src/3rdparty/angle/src/libANGLE/Shader.cpp +++ b/src/3rdparty/angle/src/libANGLE/Shader.cpp @@ -14,11 +14,13 @@ #include "common/utilities.h" #include "GLSLANG/ShaderLang.h" +#include "libANGLE/Caps.h" #include "libANGLE/Compiler.h" #include "libANGLE/Constants.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/ShaderImpl.h" #include "libANGLE/ResourceManager.h" +#include "libANGLE/Context.h" namespace gl { @@ -55,16 +57,16 @@ bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) { if (x.type == y.type) { - return x.arraySize > y.arraySize; + return x.getArraySizeProduct() > y.getArraySizeProduct(); } // Special case for handling structs: we sort these to the end of the list - if (x.type == GL_STRUCT_ANGLEX) + if (x.type == GL_NONE) { return false; } - if (y.type == GL_STRUCT_ANGLEX) + if (y.type == GL_NONE) { return true; } @@ -72,45 +74,61 @@ bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); } -Shader::Data::Data(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100) +ShaderState::ShaderState(GLenum shaderType) + : mLabel(), + mShaderType(shaderType), + mShaderVersion(100), + mNumViews(-1), + mGeometryShaderInputPrimitiveType(GL_INVALID_VALUE), + mGeometryShaderOutputPrimitiveType(GL_INVALID_VALUE), + mGeometryShaderInvocations(1), + mGeometryShaderMaxVertices(-1), + mCompileStatus(CompileStatus::NOT_COMPILED) { + mLocalSize.fill(-1); } -Shader::Data::~Data() +ShaderState::~ShaderState() { } -Shader::Shader(ResourceManager *manager, - rx::ImplFactory *implFactory, +Shader::Shader(ShaderProgramManager *manager, + rx::GLImplFactory *implFactory, const gl::Limitations &rendererLimitations, GLenum type, GLuint handle) - : mData(type), - mImplementation(implFactory->createShader(mData)), + : mState(type), + mImplementation(implFactory->createShader(mState)), mRendererLimitations(rendererLimitations), mHandle(handle), mType(type), mRefCount(0), mDeleteStatus(false), - mCompiled(false), mResourceManager(manager) { ASSERT(mImplementation); } +void Shader::onDestroy(const gl::Context *context) +{ + mBoundCompiler.set(context, nullptr); + mImplementation.reset(nullptr); + delete this; +} + Shader::~Shader() { - SafeDelete(mImplementation); + ASSERT(!mImplementation); } void Shader::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &Shader::getLabel() const { - return mData.mLabel; + return mState.mLabel; } GLuint Shader::getHandle() const @@ -134,11 +152,12 @@ void Shader::setSource(GLsizei count, const char *const *string, const GLint *le } } - mData.mSource = stream.str(); + mState.mSource = stream.str(); } -int Shader::getInfoLogLength() const +int Shader::getInfoLogLength(const Context *context) { + resolveCompile(context); if (mInfoLog.empty()) { return 0; @@ -147,8 +166,10 @@ int Shader::getInfoLogLength() const return (static_cast(mInfoLog.length()) + 1); } -void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const +void Shader::getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog) { + resolveCompile(context); + int index = 0; if (bufSize > 0) @@ -167,21 +188,25 @@ void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const int Shader::getSourceLength() const { - return mData.mSource.empty() ? 0 : (static_cast(mData.mSource.length()) + 1); + return mState.mSource.empty() ? 0 : (static_cast(mState.mSource.length()) + 1); } -int Shader::getTranslatedSourceLength() const +int Shader::getTranslatedSourceLength(const Context *context) { - if (mData.mTranslatedSource.empty()) + resolveCompile(context); + + if (mState.mTranslatedSource.empty()) { return 0; } - return (static_cast(mData.mTranslatedSource.length()) + 1); + return (static_cast(mState.mTranslatedSource.length()) + 1); } -int Shader::getTranslatedSourceWithDebugInfoLength() const +int Shader::getTranslatedSourceWithDebugInfoLength(const Context *context) { + resolveCompile(context); + const std::string &debugInfo = mImplementation->getDebugInfo(); if (debugInfo.empty()) { @@ -191,7 +216,11 @@ int Shader::getTranslatedSourceWithDebugInfoLength() const return (static_cast(debugInfo.length()) + 1); } -void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) +// static +void Shader::GetSourceImpl(const std::string &source, + GLsizei bufSize, + GLsizei *length, + char *buffer) { int index = 0; @@ -211,117 +240,186 @@ void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei * void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const { - getSourceImpl(mData.mSource, bufSize, length, buffer); + GetSourceImpl(mState.mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) +{ + GetSourceImpl(getTranslatedSource(context), bufSize, length, buffer); } -void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const +const std::string &Shader::getTranslatedSource(const Context *context) { - getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer); + resolveCompile(context); + return mState.mTranslatedSource; } -void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const +void Shader::getTranslatedSourceWithDebugInfo(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) { + resolveCompile(context); const std::string &debugInfo = mImplementation->getDebugInfo(); - getSourceImpl(debugInfo, bufSize, length, buffer); + GetSourceImpl(debugInfo, bufSize, length, buffer); } -void Shader::compile(Compiler *compiler) +void Shader::compile(const Context *context) { - mData.mTranslatedSource.clear(); + mState.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); + mState.mShaderVersion = 100; + mState.mInputVaryings.clear(); + mState.mOutputVaryings.clear(); + mState.mUniforms.clear(); + mState.mUniformBlocks.clear(); + mState.mShaderStorageBlocks.clear(); + mState.mActiveAttributes.clear(); + mState.mActiveOutputVariables.clear(); + mState.mNumViews = -1; + mState.mGeometryShaderInputPrimitiveType = GL_INVALID_VALUE; + mState.mGeometryShaderOutputPrimitiveType = GL_INVALID_VALUE; + mState.mGeometryShaderInvocations = 1; + mState.mGeometryShaderMaxVertices = -1; + + mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED; + mBoundCompiler.set(context, context->getCompiler()); + + // Cache the compile source and options for compilation. Must be done now, since the source + // can change before the link call or another call that resolves the compile. std::stringstream sourceStream; - std::string sourcePath; - int additionalOptions = - mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath); - int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions); + mLastCompileOptions = + mImplementation->prepareSourceAndReturnOptions(&sourceStream, &mLastCompiledSourcePath); + mLastCompileOptions |= (SH_OBJECT_CODE | SH_VARIABLES); + mLastCompiledSource = sourceStream.str(); + + // Add default options to WebGL shaders to prevent unexpected behavior during compilation. + if (context->getExtensions().webglCompatibility) + { + mLastCompileOptions |= SH_INIT_GL_POSITION; + mLastCompileOptions |= SH_LIMIT_CALL_STACK_DEPTH; + mLastCompileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY; + mLastCompileOptions |= SH_ENFORCE_PACKING_RESTRICTIONS; + } // 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; + mLastCompileOptions |= SH_VALIDATE_LOOP_INDEXING; } +} - std::string sourceString = sourceStream.str(); - std::vector sourceCStrings; - - if (!sourcePath.empty()) +void Shader::resolveCompile(const Context *context) +{ + if (!mState.compilePending()) { - sourceCStrings.push_back(sourcePath.c_str()); + return; } - sourceCStrings.push_back(sourceString.c_str()); + ASSERT(mBoundCompiler.get()); + ShHandle compilerHandle = mBoundCompiler->getCompilerHandle(mState.mShaderType); + + std::vector srcStrings; + + if (!mLastCompiledSourcePath.empty()) + { + srcStrings.push_back(mLastCompiledSourcePath.c_str()); + } - bool result = - ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions); + srcStrings.push_back(mLastCompiledSource.c_str()); - if (!result) + if (!sh::Compile(compilerHandle, &srcStrings[0], srcStrings.size(), mLastCompileOptions)) { - mInfoLog = ShGetInfoLog(compilerHandle); - TRACE("\n%s", mInfoLog.c_str()); - mCompiled = false; + mInfoLog = sh::GetInfoLog(compilerHandle); + WARN() << std::endl << mInfoLog; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; return; } - mData.mTranslatedSource = ShGetObjectCode(compilerHandle); + mState.mTranslatedSource = sh::GetObjectCode(compilerHandle); -#ifndef NDEBUG +#if !defined(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) + std::istringstream inputSourceStream(mState.mSource); + std::string line; + while (std::getline(inputSourceStream, line)) { - 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); + // Remove null characters from the source line + line.erase(std::remove(line.begin(), line.end(), '\0'), line.end()); - curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + shaderStream << "// " << line << std::endl; } shaderStream << "\n\n"; - shaderStream << mData.mTranslatedSource; - mData.mTranslatedSource = shaderStream.str(); -#endif + shaderStream << mState.mTranslatedSource; + mState.mTranslatedSource = shaderStream.str(); +#endif // !defined(NDEBUG) // Gather the shader information - mData.mShaderVersion = ShGetShaderVersion(compilerHandle); + mState.mShaderVersion = sh::GetShaderVersion(compilerHandle); - mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle)); - mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle)); - mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle)); + mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle)); + mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle)); + mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle)); - if (mData.mShaderType == GL_VERTEX_SHADER) + switch (mState.mShaderType) { - 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)); + case GL_COMPUTE_SHADER: + { + mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle); + break; + } + case GL_VERTEX_SHADER: + { + { + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + mState.mActiveAttributes = + GetActiveShaderVariables(sh::GetAttributes(compilerHandle)); + mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle); + } + break; + } + case GL_FRAGMENT_SHADER: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. + std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); + mState.mActiveOutputVariables = + GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + + mState.mGeometryShaderInputPrimitiveType = + sh::GetGeometryShaderInputPrimitiveType(compilerHandle); + mState.mGeometryShaderOutputPrimitiveType = + sh::GetGeometryShaderOutputPrimitiveType(compilerHandle); + mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle); + mState.mGeometryShaderMaxVertices = sh::GetGeometryShaderMaxVertices(compilerHandle); + break; + } + default: + UNREACHABLE(); } - ASSERT(!mData.mTranslatedSource.empty()); + ASSERT(!mState.mTranslatedSource.empty()); - mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog); + bool success = mImplementation->postTranslateCompile(mBoundCompiler.get(), &mInfoLog); + mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED; } void Shader::addRef() @@ -329,13 +427,13 @@ void Shader::addRef() mRefCount++; } -void Shader::release() +void Shader::release(const Context *context) { mRefCount--; if (mRefCount == 0 && mDeleteStatus) { - mResourceManager->deleteShader(mHandle); + mResourceManager->deleteShader(context, mHandle); } } @@ -354,57 +452,110 @@ void Shader::flagForDeletion() mDeleteStatus = true; } -int Shader::getShaderVersion() const +bool Shader::isCompiled(const Context *context) { - return mData.mShaderVersion; + resolveCompile(context); + return mState.mCompileStatus == CompileStatus::COMPILED; } -const std::vector &Shader::getVaryings() const +int Shader::getShaderVersion(const Context *context) { - return mData.getVaryings(); + resolveCompile(context); + return mState.mShaderVersion; } -const std::vector &Shader::getUniforms() const +const std::vector &Shader::getInputVaryings(const Context *context) { - return mData.getUniforms(); + resolveCompile(context); + return mState.getInputVaryings(); } -const std::vector &Shader::getInterfaceBlocks() const +const std::vector &Shader::getOutputVaryings(const Context *context) { - return mData.getInterfaceBlocks(); + resolveCompile(context); + return mState.getOutputVaryings(); } -const std::vector &Shader::getActiveAttributes() const +const std::vector &Shader::getUniforms(const Context *context) { - return mData.getActiveAttributes(); + resolveCompile(context); + return mState.getUniforms(); } -const std::vector &Shader::getActiveOutputVariables() const +const std::vector &Shader::getUniformBlocks(const Context *context) { - return mData.getActiveOutputVariables(); + resolveCompile(context); + return mState.getUniformBlocks(); } -int Shader::getSemanticIndex(const std::string &attributeName) const +const std::vector &Shader::getShaderStorageBlocks(const Context *context) { - if (!attributeName.empty()) - { - const auto &activeAttributes = mData.getActiveAttributes(); + resolveCompile(context); + return mState.getShaderStorageBlocks(); +} - int semanticIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) - { - const sh::ShaderVariable &attribute = activeAttributes[attributeIndex]; +const std::vector &Shader::getActiveAttributes(const Context *context) +{ + resolveCompile(context); + return mState.getActiveAttributes(); +} + +const std::vector &Shader::getActiveOutputVariables(const Context *context) +{ + resolveCompile(context); + return mState.getActiveOutputVariables(); +} - if (attribute.name == attributeName) +std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName, + const Context *context) +{ + // TODO(jiawei.shao@intel.com): support transform feedback on geometry shader. + ASSERT(mState.getShaderType() == GL_VERTEX_SHADER); + const auto &varyings = getOutputVaryings(context); + auto bracketPos = tfVaryingName.find("["); + if (bracketPos != std::string::npos) + { + auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos); + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingBaseName) { - return semanticIndex; + std::string mappedNameWithArrayIndex = + varying.mappedName + tfVaryingName.substr(bracketPos); + return mappedNameWithArrayIndex; + } + } + } + else + { + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingName) + { + return varying.mappedName; } - - semanticIndex += gl::VariableRegisterCount(attribute.type); } } + UNREACHABLE(); + return std::string(); +} - return -1; +const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context) +{ + resolveCompile(context); + return mState.mLocalSize; } +int Shader::getNumViews(const Context *context) +{ + resolveCompile(context); + return mState.mNumViews; } + +const std::string &Shader::getCompilerResourcesString() const +{ + ASSERT(mBoundCompiler.get()); + return mBoundCompiler->getBuiltinResourcesString(mState.mShaderType); +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Shader.h b/src/3rdparty/angle/src/libANGLE/Shader.h index 997977c87b..4b6be4696d 100644 --- a/src/3rdparty/angle/src/libANGLE/Shader.h +++ b/src/3rdparty/angle/src/libANGLE/Shader.h @@ -12,20 +12,22 @@ #ifndef LIBANGLE_SHADER_H_ #define LIBANGLE_SHADER_H_ -#include #include +#include +#include #include #include "angle_gl.h" #include +#include "common/Optional.h" #include "common/angleutils.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Debug.h" +#include "libANGLE/angletypes.h" namespace rx { -class ImplFactory; +class GLImplFactory; class ShaderImpl; class ShaderSh; } @@ -33,63 +35,92 @@ class ShaderSh; namespace gl { class Compiler; +class ContextState; struct Limitations; -class ResourceManager; -struct Data; +class ShaderProgramManager; +class Context; -class Shader final : angle::NonCopyable, public LabeledObject +// We defer the compile until link time, or until properties are queried. +enum class CompileStatus +{ + NOT_COMPILED, + COMPILE_REQUESTED, + COMPILED, +}; + +class ShaderState final : angle::NonCopyable { public: - class Data final : angle::NonCopyable + ShaderState(GLenum shaderType); + ~ShaderState(); + + 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 &getInputVaryings() const { return mInputVaryings; } + const std::vector &getOutputVaryings() const { return mOutputVaryings; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getShaderStorageBlocks() const { - 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, + return mShaderStorageBlocks; + } + const std::vector &getActiveAttributes() const { return mActiveAttributes; } + const std::vector &getActiveOutputVariables() const + { + return mActiveOutputVariables; + } + + bool compilePending() const { return mCompileStatus == CompileStatus::COMPILE_REQUESTED; } + + private: + friend class Shader; + + std::string mLabel; + + GLenum mShaderType; + int mShaderVersion; + std::string mTranslatedSource; + std::string mSource; + + sh::WorkGroupSize mLocalSize; + + std::vector mInputVaryings; + std::vector mOutputVaryings; + std::vector mUniforms; + std::vector mUniformBlocks; + std::vector mShaderStorageBlocks; + std::vector mActiveAttributes; + std::vector mActiveOutputVariables; + + // ANGLE_multiview. + int mNumViews; + + // Geometry Shader. + GLenum mGeometryShaderInputPrimitiveType; + GLenum mGeometryShaderOutputPrimitiveType; + int mGeometryShaderInvocations; + int mGeometryShaderMaxVertices; + + // Indicates if this shader has been successfully compiled + CompileStatus mCompileStatus; +}; + +class Shader final : angle::NonCopyable, public LabeledObject +{ + public: + Shader(ShaderProgramManager *manager, + rx::GLImplFactory *implFactory, const gl::Limitations &rendererLimitations, GLenum type, GLuint handle); - virtual ~Shader(); + void onDestroy(const Context *context); void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -97,56 +128,85 @@ class Shader final : angle::NonCopyable, public LabeledObject GLenum getType() const { return mType; } GLuint getHandle() const; - const rx::ShaderImpl *getImplementation() const { return mImplementation; } + rx::ShaderImpl *getImplementation() const { return mImplementation.get(); } - void deleteSource(); void setSource(GLsizei count, const char *const *string, const GLint *length); - int getInfoLogLength() const; - void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; + int getInfoLogLength(const Context *context); + void getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog); int getSourceLength() const; + const std::string &getSourceString() const { return mState.getSource(); } 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; - - void compile(Compiler *compiler); - bool isCompiled() const { return mCompiled; } + int getTranslatedSourceLength(const Context *context); + int getTranslatedSourceWithDebugInfoLength(const Context *context); + const std::string &getTranslatedSource(const Context *context); + void getTranslatedSource(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer); + void getTranslatedSourceWithDebugInfo(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer); + + void compile(const Context *context); + bool isCompiled(const Context *context); void addRef(); - void release(); + void release(const Context *context); unsigned int getRefCount() const; bool isFlaggedForDeletion() const; void flagForDeletion(); - int getShaderVersion() const; + int getShaderVersion(const Context *context); - 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; + const std::vector &getInputVaryings(const Context *context); + const std::vector &getOutputVaryings(const Context *context); + const std::vector &getUniforms(const Context *context); + const std::vector &getUniformBlocks(const Context *context); + const std::vector &getShaderStorageBlocks(const Context *context); + const std::vector &getActiveAttributes(const Context *context); + const std::vector &getActiveOutputVariables(const Context *context); - int getSemanticIndex(const std::string &attributeName) const; + // Returns mapped name of a transform feedback varying. The original name may contain array + // brackets with an index inside, which will get copied to the mapped name. The varying must be + // known to be declared in the shader. + std::string getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName, + const Context *context); - private: - static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer); + const sh::WorkGroupSize &getWorkGroupSize(const Context *context); + + int getNumViews(const Context *context); - Data mData; - rx::ShaderImpl *mImplementation; + const std::string &getCompilerResourcesString() const; + + private: + ~Shader() override; + static void GetSourceImpl(const std::string &source, + GLsizei bufSize, + GLsizei *length, + char *buffer); + + void resolveCompile(const Context *context); + + ShaderState mState; + std::string mLastCompiledSource; + std::string mLastCompiledSourcePath; + ShCompileOptions mLastCompileOptions; + std::unique_ptr mImplementation; const gl::Limitations &mRendererLimitations; const GLuint mHandle; const GLenum mType; 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; + // We keep a reference to the translator in order to defer compiles while preserving settings. + BindingPointer mBoundCompiler; + + ShaderProgramManager *mResourceManager; }; bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y); -} +} // namespace gl #endif // LIBANGLE_SHADER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h b/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h new file mode 100644 index 0000000000..6a608a697e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/SizedMRUCache.h @@ -0,0 +1,174 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SizedMRUCache.h: A hashing map that stores blobs of sized, untyped data. + +#ifndef LIBANGLE_SIZED_MRU_CACHE_H_ +#define LIBANGLE_SIZED_MRU_CACHE_H_ + +#include +#include "common/third_party/smhasher/src/PMurHash.h" + +namespace angle +{ + +template +class SizedMRUCache final : angle::NonCopyable +{ + public: + SizedMRUCache(size_t maximumTotalSize) + : mMaximumTotalSize(maximumTotalSize), + mCurrentSize(0), + mStore(SizedMRUCacheStore::NO_AUTO_EVICT) + { + } + + // Returns nullptr on failure. + const Value *put(const Key &key, Value &&value, size_t size) + { + if (size > mMaximumTotalSize) + { + return nullptr; + } + + // Check for existing key. + eraseByKey(key); + + auto retVal = mStore.Put(key, ValueAndSize(std::move(value), size)); + mCurrentSize += size; + + shrinkToSize(mMaximumTotalSize); + + return &retVal->second.value; + } + + bool get(const Key &key, const Value **valueOut) + { + const auto &iter = mStore.Get(key); + if (iter == mStore.end()) + { + return false; + } + *valueOut = &iter->second.value; + return true; + } + + bool getAt(size_t index, Key *keyOut, const Value **valueOut) + { + if (index < mStore.size()) + { + auto it = mStore.begin(); + std::advance(it, index); + *keyOut = it->first; + *valueOut = &it->second.value; + return true; + } + *valueOut = nullptr; + return false; + } + + bool empty() const { return mStore.empty(); } + + void clear() + { + mStore.Clear(); + mCurrentSize = 0; + } + + bool eraseByKey(const Key &key) + { + // Check for existing key. + auto existing = mStore.Peek(key); + if (existing != mStore.end()) + { + mCurrentSize -= existing->second.size; + mStore.Erase(existing); + return true; + } + + return false; + } + + size_t entryCount() const { return mStore.size(); } + + size_t size() const { return mCurrentSize; } + + // Also discards the cache contents. + void resize(size_t maximumTotalSize) + { + clear(); + mMaximumTotalSize = maximumTotalSize; + } + + // Reduce current memory usage. + size_t shrinkToSize(size_t limit) + { + size_t initialSize = mCurrentSize; + + while (mCurrentSize > limit) + { + ASSERT(!mStore.empty()); + auto iter = mStore.rbegin(); + mCurrentSize -= iter->second.size; + mStore.Erase(iter); + } + + return (initialSize - mCurrentSize); + } + + size_t maxSize() const { return mMaximumTotalSize; } + + private: + struct ValueAndSize + { + ValueAndSize() : value(), size(0) {} + ValueAndSize(Value &&value, size_t size) : value(std::move(value)), size(size) {} + ValueAndSize(ValueAndSize &&other) : ValueAndSize() { *this = std::move(other); } + ValueAndSize &operator=(ValueAndSize &&other) + { + std::swap(value, other.value); + std::swap(size, other.size); + return *this; + } + + Value value; + size_t size; + }; + + using SizedMRUCacheStore = base::HashingMRUCache; + + size_t mMaximumTotalSize; + size_t mCurrentSize; + SizedMRUCacheStore mStore; +}; + +// Helper function used in a few places. +template +void TrimCache(size_t maxStates, size_t gcLimit, const char *name, T *cache) +{ + const size_t kGarbageCollectionLimit = maxStates / 2 + gcLimit; + + if (cache->size() >= kGarbageCollectionLimit) + { + WARN() << "Overflowed the " << name << " cache limit of " << (maxStates / 2) + << " elements, removing the least recently used to make room."; + cache->ShrinkToSize(maxStates / 2); + } +} + +// Computes a hash of struct "key". Any structs passed to this function must be multiples of +// 4 bytes, since the PMurhHas32 method can only operate increments of 4-byte words. +template +std::size_t ComputeGenericHash(const T &key) +{ + static const unsigned int seed = 0xABCDEF98; + + // We can't support "odd" alignments. + static_assert(sizeof(key) % 4 == 0, "ComputeGenericHash requires aligned types"); + return PMurHash32(seed, &key, sizeof(T)); +} + +} // namespace angle +#endif // LIBANGLE_SIZED_MRU_CACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp index a1437b838b..f87e963710 100644 --- a/src/3rdparty/angle/src/libANGLE/State.cpp +++ b/src/3rdparty/angle/src/libANGLE/State.cpp @@ -8,15 +8,32 @@ #include "libANGLE/State.h" -#include "common/BitSetIterator.h" -#include "libANGLE/Context.h" +#include +#include + +#include "common/bitset_utils.h" +#include "common/mathutil.h" +#include "common/matrix_utils.h" #include "libANGLE/Caps.h" +#include "libANGLE/Context.h" #include "libANGLE/Debug.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Query.h" #include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/ContextImpl.h" + +namespace +{ + +GLenum ActiveQueryType(const GLenum type) +{ + return (type == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) ? GL_ANY_SAMPLES_PASSED : type; +} + +} // anonymous namepace namespace gl { @@ -30,11 +47,15 @@ State::State() mSampleCoverage(false), mSampleCoverageValue(0), mSampleCoverageInvert(false), + mSampleMask(false), + mMaxSampleMaskWords(0), mStencilRef(0), mStencilBackRef(0), mLineWidth(0), mGenerateMipmapHint(GL_NONE), mFragmentShaderDerivativeHint(GL_NONE), + mBindGeneratesResource(true), + mClientArraysEnabled(true), mNearZ(0), mFarZ(0), mReadFramebuffer(nullptr), @@ -42,49 +63,31 @@ State::State() 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); + mPrimitiveRestart(false), + mMultiSampling(false), + mSampleAlphaToOne(false), + mFramebufferSRGB(true), + mRobustResourceInit(false), + mProgramBinaryCacheEnabled(false) +{ } State::~State() { - reset(); } -void State::initialize(const Caps &caps, - const Extensions &extensions, - GLuint clientVersion, - bool debug) +void State::initialize(const Context *context, + bool debug, + bool bindGeneratesResource, + bool clientArraysEnabled, + bool robustResourceInit, + bool programBinaryCacheEnabled) { + const Caps &caps = context->getCaps(); + const Extensions &extensions = context->getExtensions(); + const Extensions &nativeExtensions = context->getImplementation()->getNativeExtensions(); + const Version &clientVersion = context->getClientVersion(); + mMaxDrawBuffers = caps.maxDrawBuffers; mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; @@ -93,62 +96,34 @@ void State::initialize(const Caps &caps, mDepthClearValue = 1.0f; mStencilClearValue = 0; - mRasterizer.rasterizerDiscard = false; - mRasterizer.cullFace = false; - mRasterizer.cullMode = GL_BACK; - mRasterizer.frontFace = GL_CCW; - mRasterizer.polygonOffsetFill = false; - mRasterizer.polygonOffsetFactor = 0.0f; - mRasterizer.polygonOffsetUnits = 0.0f; - mRasterizer.pointDrawMode = false; - mRasterizer.multiSample = false; mScissorTest = false; mScissor.x = 0; mScissor.y = 0; mScissor.width = 0; mScissor.height = 0; - mBlend.blend = false; - mBlend.sourceBlendRGB = GL_ONE; - mBlend.sourceBlendAlpha = GL_ONE; - mBlend.destBlendRGB = GL_ZERO; - mBlend.destBlendAlpha = GL_ZERO; - mBlend.blendEquationRGB = GL_FUNC_ADD; - mBlend.blendEquationAlpha = GL_FUNC_ADD; - mBlend.sampleAlphaToCoverage = false; - mBlend.dither = true; - mBlendColor.red = 0; mBlendColor.green = 0; mBlendColor.blue = 0; mBlendColor.alpha = 0; - mDepthStencil.depthTest = false; - mDepthStencil.depthFunc = GL_LESS; - mDepthStencil.depthMask = true; - mDepthStencil.stencilTest = false; - mDepthStencil.stencilFunc = GL_ALWAYS; - mDepthStencil.stencilMask = static_cast(-1); - mDepthStencil.stencilWritemask = static_cast(-1); - mDepthStencil.stencilBackFunc = GL_ALWAYS; - mDepthStencil.stencilBackMask = static_cast(-1); - mDepthStencil.stencilBackWritemask = static_cast(-1); - mDepthStencil.stencilFail = GL_KEEP; - mDepthStencil.stencilPassDepthFail = GL_KEEP; - mDepthStencil.stencilPassDepthPass = GL_KEEP; - mDepthStencil.stencilBackFail = GL_KEEP; - mDepthStencil.stencilBackPassDepthFail = GL_KEEP; - mDepthStencil.stencilBackPassDepthPass = GL_KEEP; - mStencilRef = 0; mStencilBackRef = 0; mSampleCoverage = false; mSampleCoverageValue = 1.0f; mSampleCoverageInvert = false; + + mMaxSampleMaskWords = caps.maxSampleMaskWords; + mSampleMask = false; + mSampleMaskValues.fill(~GLbitfield(0)); + mGenerateMipmapHint = GL_DONT_CARE; mFragmentShaderDerivativeHint = GL_DONT_CARE; + mBindGeneratesResource = bindGeneratesResource; + mClientArraysEnabled = clientArraysEnabled; + mLineWidth = 1.0f; mViewport.x = 0; @@ -167,23 +142,48 @@ void State::initialize(const Caps &caps, mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); - mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mUniformBuffers.resize(caps.maxUniformBufferBindings); mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); - if (clientVersion >= 3) + if (clientVersion >= Version(3, 0)) { // TODO: These could also be enabled via extension mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); } + if (clientVersion >= Version(3, 1)) + { + mSamplerTextures[GL_TEXTURE_2D_MULTISAMPLE].resize(caps.maxCombinedTextureImageUnits); + + mAtomicCounterBuffers.resize(caps.maxAtomicCounterBufferBindings); + mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings); + mImageUnits.resize(caps.maxImageUnits); + } + if (nativeExtensions.textureRectangle) + { + mSamplerTextures[GL_TEXTURE_RECTANGLE_ANGLE].resize(caps.maxCombinedTextureImageUnits); + } + if (nativeExtensions.eglImageExternal || nativeExtensions.eglStreamConsumerExternal) + { + mSamplerTextures[GL_TEXTURE_EXTERNAL_OES].resize(caps.maxCombinedTextureImageUnits); + } + mCompleteTextureCache.resize(caps.maxCombinedTextureImageUnits, nullptr); + mCompleteTextureBindings.reserve(caps.maxCombinedTextureImageUnits); + mCachedTexturesInitState = InitState::MayNeedInit; + for (uint32_t textureIndex = 0; textureIndex < caps.maxCombinedTextureImageUnits; + ++textureIndex) + { + mCompleteTextureBindings.emplace_back(OnAttachmentDirtyBinding(this, textureIndex)); + } mSamplers.resize(caps.maxCombinedTextureImageUnits); - 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); + mActiveQueries[GL_ANY_SAMPLES_PASSED].set(context, nullptr); + mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(context, nullptr); + mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(context, nullptr); + mActiveQueries[GL_TIME_ELAPSED_EXT].set(context, nullptr); + mActiveQueries[GL_COMMANDS_COMPLETED_CHROMIUM].set(context, nullptr); mProgram = nullptr; @@ -194,52 +194,89 @@ void State::initialize(const Caps &caps, mDebug.setOutputEnabled(debug); mDebug.setMaxLoggedMessages(extensions.maxDebugLoggedMessages); + + mMultiSampling = true; + mSampleAlphaToOne = false; + + mCoverageModulation = GL_NONE; + + angle::Matrix::setToIdentity(mPathMatrixProj); + angle::Matrix::setToIdentity(mPathMatrixMV); + mPathStencilFunc = GL_ALWAYS; + mPathStencilRef = 0; + mPathStencilMask = std::numeric_limits::max(); + + mRobustResourceInit = robustResourceInit; + mProgramBinaryCacheEnabled = programBinaryCacheEnabled; } -void State::reset() +void State::reset(const Context *context) { - for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + for (auto &bindingVec : mSamplerTextures) { - TextureBindingVector &textureVector = bindingVec->second; + TextureBindingVector &textureVector = bindingVec.second; for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) { - textureVector[textureIdx].set(NULL); + textureVector[textureIdx].set(context, nullptr); } } for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) { - mSamplers[samplerIdx].set(NULL); + mSamplers[samplerIdx].set(context, nullptr); } - mArrayBuffer.set(NULL); - mRenderbuffer.set(NULL); + for (auto &imageUnit : mImageUnits) + { + imageUnit.texture.set(context, nullptr); + imageUnit.level = 0; + imageUnit.layered = false; + imageUnit.layer = 0; + imageUnit.access = GL_READ_ONLY; + imageUnit.format = GL_R32UI; + } + + mRenderbuffer.set(context, nullptr); + + for (auto type : angle::AllEnums()) + { + mBoundBuffers[type].set(context, nullptr); + } if (mProgram) { - mProgram->release(); + mProgram->release(context); } - mProgram = NULL; + mProgram = nullptr; + + mProgramPipeline.set(context, nullptr); - mTransformFeedback.set(NULL); + mTransformFeedback.set(context, nullptr); for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) { - i->second.set(NULL); + i->second.set(context, nullptr); } - mGenericUniformBuffer.set(NULL); - for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) + for (auto &buf : mUniformBuffers) { - bufItr->set(NULL); + buf.set(context, nullptr); } - mCopyReadBuffer.set(NULL); - mCopyWriteBuffer.set(NULL); + for (auto &buf : mAtomicCounterBuffers) + { + buf.set(context, nullptr); + } - mPack.pixelBuffer.set(NULL); - mUnpack.pixelBuffer.set(NULL); + for (auto &buf : mShaderStorageBuffers) + { + buf.set(context, nullptr); + } - mProgram = NULL; + angle::Matrix::setToIdentity(mPathMatrixProj); + angle::Matrix::setToIdentity(mPathMatrixMV); + mPathStencilFunc = GL_ALWAYS; + mPathStencilRef = 0; + mPathStencilMask = std::numeric_limits::max(); // TODO(jmadill): Is this necessary? setAllDirtyBits(); @@ -318,7 +355,7 @@ void State::setCullFace(bool enabled) mDirtyBits.set(DIRTY_BIT_CULL_FACE_ENABLED); } -void State::setCullMode(GLenum mode) +void State::setCullMode(CullFaceMode mode) { mRasterizer.cullMode = mode; mDirtyBits.set(DIRTY_BIT_CULL_FACE); @@ -528,6 +565,58 @@ bool State::getSampleCoverageInvert() const return mSampleCoverageInvert; } +bool State::isSampleMaskEnabled() const +{ + return mSampleMask; +} + +void State::setSampleMaskEnabled(bool enabled) +{ + mSampleMask = enabled; + mDirtyBits.set(DIRTY_BIT_SAMPLE_MASK_ENABLED); +} + +void State::setSampleMaskParams(GLuint maskNumber, GLbitfield mask) +{ + ASSERT(maskNumber < mMaxSampleMaskWords); + mSampleMaskValues[maskNumber] = mask; + // TODO(jmadill): Use a child dirty bit if we ever use more than two words. + mDirtyBits.set(DIRTY_BIT_SAMPLE_MASK); +} + +GLbitfield State::getSampleMaskWord(GLuint maskNumber) const +{ + ASSERT(maskNumber < mMaxSampleMaskWords); + return mSampleMaskValues[maskNumber]; +} + +GLuint State::getMaxSampleMaskWords() const +{ + return mMaxSampleMaskWords; +} + +void State::setSampleAlphaToOne(bool enabled) +{ + mSampleAlphaToOne = enabled; + mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_ONE); +} + +bool State::isSampleAlphaToOneEnabled() const +{ + return mSampleAlphaToOne; +} + +void State::setMultisampling(bool enabled) +{ + mMultiSampling = enabled; + mDirtyBits.set(DIRTY_BIT_MULTISAMPLING); +} + +bool State::isMultisamplingEnabled() const +{ + return mMultiSampling; +} + bool State::isScissorTestEnabled() const { return mScissorTest; @@ -579,6 +668,8 @@ void State::setEnableFeature(GLenum feature, bool enabled) { switch (feature) { + case GL_MULTISAMPLE_EXT: setMultisampling(enabled); break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: setSampleAlphaToOne(enabled); break; case GL_CULL_FACE: setCullFace(enabled); break; case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; @@ -590,20 +681,28 @@ 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_SAMPLE_MASK: + setSampleMaskEnabled(enabled); + break; case GL_DEBUG_OUTPUT_SYNCHRONOUS: mDebug.setOutputSynchronous(enabled); break; case GL_DEBUG_OUTPUT: mDebug.setOutputEnabled(enabled); break; + case GL_FRAMEBUFFER_SRGB_EXT: + setFramebufferSRGB(enabled); + break; default: UNREACHABLE(); } } -bool State::getEnableFeature(GLenum feature) +bool State::getEnableFeature(GLenum feature) const { switch (feature) { + case GL_MULTISAMPLE_EXT: return isMultisamplingEnabled(); + case GL_SAMPLE_ALPHA_TO_ONE_EXT: return isSampleAlphaToOneEnabled(); case GL_CULL_FACE: return isCullFaceEnabled(); case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); @@ -615,11 +714,26 @@ 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_SAMPLE_MASK: + return isSampleMaskEnabled(); case GL_DEBUG_OUTPUT_SYNCHRONOUS: return mDebug.isOutputSynchronous(); case GL_DEBUG_OUTPUT: return mDebug.isOutputEnabled(); - default: UNREACHABLE(); return false; + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + return isBindGeneratesResourceEnabled(); + case GL_CLIENT_ARRAYS_ANGLE: + return areClientArraysEnabled(); + case GL_FRAMEBUFFER_SRGB_EXT: + return getFramebufferSRGB(); + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + return mRobustResourceInit; + case GL_PROGRAM_CACHE_ENABLED_ANGLE: + return mProgramBinaryCacheEnabled; + + default: + UNREACHABLE(); + return false; } } @@ -649,6 +763,16 @@ void State::setFragmentShaderDerivativeHint(GLenum hint) // Ignore for now. It is valid for implementations to ignore hint. } +bool State::isBindGeneratesResourceEnabled() const +{ + return mBindGeneratesResource; +} + +bool State::areClientArraysEnabled() const +{ + return mClientArraysEnabled; +} + void State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) { mViewport.x = x; @@ -673,9 +797,11 @@ unsigned int State::getActiveSampler() const return static_cast(mActiveSampler); } -void State::setSamplerTexture(GLenum type, Texture *texture) +void State::setSamplerTexture(const Context *context, GLenum type, Texture *texture) { - mSamplerTextures[type][mActiveSampler].set(texture); + mSamplerTextures[type][mActiveSampler].set(context, texture); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } Texture *State::getTargetTexture(GLenum target) const @@ -699,7 +825,7 @@ GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const return it->second[sampler].id(); } -void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) +void State::detachTexture(const Context *context, const TextureMap &zeroTextures, GLuint texture) { // Textures have a detach method on State rather than a simple // removeBinding, because the zero/null texture objects are managed @@ -710,40 +836,54 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) // If a texture object is deleted, it is as if all texture units which are bound to that texture object are // rebound to texture object zero - for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + for (auto &bindingVec : mSamplerTextures) { - GLenum textureType = bindingVec->first; - TextureBindingVector &textureVector = bindingVec->second; - for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + GLenum textureType = bindingVec.first; + TextureBindingVector &textureVector = bindingVec.second; + for (BindingPointer &binding : textureVector) { - BindingPointer &binding = textureVector[textureIdx]; if (binding.id() == texture) { auto it = zeroTextures.find(textureType); ASSERT(it != zeroTextures.end()); // Zero textures are the "default" textures instead of NULL - binding.set(it->second.get()); + binding.set(context, it->second.get()); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); } } } + for (auto &bindingImageUnit : mImageUnits) + { + if (bindingImageUnit.texture.id() == texture) + { + bindingImageUnit.texture.set(context, nullptr); + bindingImageUnit.level = 0; + bindingImageUnit.layered = false; + bindingImageUnit.layer = 0; + bindingImageUnit.access = GL_READ_ONLY; + bindingImageUnit.format = GL_R32UI; + break; + } + } + // [OpenGL ES 2.0.24] section 4.4 page 112: // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is // as if Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this // image was attached in the currently bound framebuffer. - if (mReadFramebuffer) + if (mReadFramebuffer && mReadFramebuffer->detachTexture(context, texture)) { - mReadFramebuffer->detachTexture(texture); + mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER); } - if (mDrawFramebuffer) + if (mDrawFramebuffer && mDrawFramebuffer->detachTexture(context, texture)) { - mDrawFramebuffer->detachTexture(texture); + mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER); } } -void State::initializeZeroTextures(const TextureMap &zeroTextures) +void State::initializeZeroTextures(const Context *context, const TextureMap &zeroTextures) { for (const auto &zeroTexture : zeroTextures) { @@ -751,14 +891,16 @@ void State::initializeZeroTextures(const TextureMap &zeroTextures) for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) { - samplerTextureArray[textureUnit].set(zeroTexture.second.get()); + samplerTextureArray[textureUnit].set(context, zeroTexture.second.get()); } } } -void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) +void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler) { - mSamplers[textureUnit].set(sampler); + mSamplers[textureUnit].set(context, sampler); + mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } GLuint State::getSamplerId(GLuint textureUnit) const @@ -772,25 +914,26 @@ Sampler *State::getSampler(GLuint textureUnit) const return mSamplers[textureUnit].get(); } -void State::detachSampler(GLuint sampler) +void State::detachSampler(const Context *context, GLuint sampler) { // [OpenGL ES 3.0.2] section 3.8.2 pages 123-124: // If a sampler object that is currently bound to one or more texture units is // deleted, it is as though BindSampler is called once for each texture unit to // which the sampler is bound, with unit set to the texture unit and sampler set to zero. - for (size_t textureUnit = 0; textureUnit < mSamplers.size(); textureUnit++) + for (BindingPointer &samplerBinding : mSamplers) { - BindingPointer &samplerBinding = mSamplers[textureUnit]; if (samplerBinding.id() == sampler) { - samplerBinding.set(NULL); + samplerBinding.set(context, nullptr); + mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS); } } } -void State::setRenderbufferBinding(Renderbuffer *renderbuffer) +void State::setRenderbufferBinding(const Context *context, Renderbuffer *renderbuffer) { - mRenderbuffer.set(renderbuffer); + mRenderbuffer.set(context, renderbuffer); + mDirtyBits.set(DIRTY_BIT_RENDERBUFFER_BINDING); } GLuint State::getRenderbufferId() const @@ -798,12 +941,12 @@ GLuint State::getRenderbufferId() const return mRenderbuffer.id(); } -Renderbuffer *State::getCurrentRenderbuffer() +Renderbuffer *State::getCurrentRenderbuffer() const { return mRenderbuffer.get(); } -void State::detachRenderbuffer(GLuint renderbuffer) +void State::detachRenderbuffer(const Context *context, GLuint renderbuffer) { // [OpenGL ES 2.0.24] section 4.4 page 109: // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer @@ -811,7 +954,7 @@ void State::detachRenderbuffer(GLuint renderbuffer) if (mRenderbuffer.id() == renderbuffer) { - mRenderbuffer.set(NULL); + setRenderbufferBinding(context, nullptr); } // [OpenGL ES 2.0.24] section 4.4 page 111: @@ -822,14 +965,17 @@ void State::detachRenderbuffer(GLuint renderbuffer) Framebuffer *readFramebuffer = mReadFramebuffer; Framebuffer *drawFramebuffer = mDrawFramebuffer; - if (readFramebuffer) + if (readFramebuffer && readFramebuffer->detachRenderbuffer(context, renderbuffer)) { - readFramebuffer->detachRenderbuffer(renderbuffer); + mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER); } if (drawFramebuffer && drawFramebuffer != readFramebuffer) { - drawFramebuffer->detachRenderbuffer(renderbuffer); + if (drawFramebuffer->detachRenderbuffer(context, renderbuffer)) + { + mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER); + } } } @@ -873,26 +1019,16 @@ Framebuffer *State::getTargetFramebuffer(GLenum target) const return mDrawFramebuffer; default: UNREACHABLE(); - return NULL; + return nullptr; } } -Framebuffer *State::getReadFramebuffer() +Framebuffer *State::getReadFramebuffer() const { return mReadFramebuffer; } -Framebuffer *State::getDrawFramebuffer() -{ - return mDrawFramebuffer; -} - -const Framebuffer *State::getReadFramebuffer() const -{ - return mReadFramebuffer; -} - -const Framebuffer *State::getDrawFramebuffer() const +Framebuffer *State::getDrawFramebuffer() const { return mDrawFramebuffer; } @@ -934,13 +1070,13 @@ void State::setVertexArrayBinding(VertexArray *vertexArray) GLuint State::getVertexArrayId() const { - ASSERT(mVertexArray != NULL); + ASSERT(mVertexArray != nullptr); return mVertexArray->id(); } VertexArray *State::getVertexArray() const { - ASSERT(mVertexArray != NULL); + ASSERT(mVertexArray != nullptr); return mVertexArray; } @@ -948,7 +1084,7 @@ bool State::removeVertexArrayBinding(GLuint vertexArray) { if (mVertexArray->id() == vertexArray) { - mVertexArray = NULL; + mVertexArray = nullptr; mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING); mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); return true; @@ -957,13 +1093,47 @@ bool State::removeVertexArrayBinding(GLuint vertexArray) return false; } -void State::setProgram(Program *newProgram) +void State::bindVertexBuffer(const Context *context, + GLuint bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + getVertexArray()->bindVertexBuffer(context, bindingIndex, boundBuffer, offset, stride); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexAttribBinding(const Context *context, GLuint attribIndex, GLuint bindingIndex) +{ + getVertexArray()->setVertexAttribBinding(context, attribIndex, bindingIndex); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) +{ + getVertexArray()->setVertexAttribFormat(attribIndex, size, type, normalized, pureInteger, + relativeOffset); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + getVertexArray()->setVertexBindingDivisor(bindingIndex, divisor); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); +} + +void State::setProgram(const Context *context, Program *newProgram) { if (mProgram != newProgram) { if (mProgram) { - mProgram->release(); + mProgram->release(context); } mProgram = newProgram; @@ -971,7 +1141,10 @@ void State::setProgram(Program *newProgram) if (mProgram) { newProgram->addRef(); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); } + mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE); + mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING); } } @@ -980,9 +1153,10 @@ Program *State::getProgram() const return mProgram; } -void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) +void State::setTransformFeedbackBinding(const Context *context, + TransformFeedback *transformFeedback) { - mTransformFeedback.set(transformFeedback); + mTransformFeedback.set(context, transformFeedback); } TransformFeedback *State::getCurrentTransformFeedback() const @@ -992,23 +1166,37 @@ TransformFeedback *State::getCurrentTransformFeedback() const bool State::isTransformFeedbackActiveUnpaused() const { - gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); + TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); return curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused(); } -void State::detachTransformFeedback(GLuint transformFeedback) +bool State::removeTransformFeedbackBinding(const Context *context, GLuint transformFeedback) { if (mTransformFeedback.id() == transformFeedback) { - mTransformFeedback.set(NULL); + mTransformFeedback.set(context, nullptr); + return true; } + + return false; +} + +void State::setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline) +{ + mProgramPipeline.set(context, pipeline); +} + +void State::detachProgramPipeline(const Context *context, GLuint pipeline) +{ + mProgramPipeline.set(context, nullptr); } -bool State::isQueryActive() const +bool State::isQueryActive(const GLenum type) const { for (auto &iter : mActiveQueries) { - if (iter.second.get() != NULL) + const Query *query = iter.second.get(); + if (query != nullptr && ActiveQueryType(query->getType()) == ActiveQueryType(type)) { return true; } @@ -1030,9 +1218,9 @@ bool State::isQueryActive(Query *query) const return false; } -void State::setActiveQuery(GLenum target, Query *query) +void State::setActiveQuery(const Context *context, GLenum target, Query *query) { - mActiveQueries[target].set(query); + mActiveQueries[target].set(context, query); } GLuint State::getActiveQueryId(GLenum target) const @@ -1051,24 +1239,64 @@ Query *State::getActiveQuery(GLenum target) const return it->second.get(); } -void State::setArrayBufferBinding(Buffer *buffer) +void State::setBufferBinding(const Context *context, BufferBinding target, Buffer *buffer) { - mArrayBuffer.set(buffer); -} - -GLuint State::getArrayBufferId() const -{ - return mArrayBuffer.id(); + switch (target) + { + case BufferBinding::PixelPack: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_PACK_BUFFER_BINDING); + break; + case BufferBinding::PixelUnpack: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_UNPACK_BUFFER_BINDING); + break; + case BufferBinding::DrawIndirect: + mBoundBuffers[target].set(context, buffer); + mDirtyBits.set(DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING); + break; + case BufferBinding::TransformFeedback: + if (mTransformFeedback.get() != nullptr) + { + mTransformFeedback->bindGenericBuffer(context, buffer); + } + break; + case BufferBinding::ElementArray: + getVertexArray()->setElementArrayBuffer(context, buffer); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); + break; + default: + mBoundBuffers[target].set(context, buffer); + break; + } } - -void State::setGenericUniformBufferBinding(Buffer *buffer) +void State::setIndexedBufferBinding(const Context *context, + BufferBinding target, + GLuint index, + Buffer *buffer, + GLintptr offset, + GLsizeiptr size) { - mGenericUniformBuffer.set(buffer); -} + setBufferBinding(context, target, buffer); -void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) -{ - mUniformBuffers[index].set(buffer, offset, size); + switch (target) + { + case BufferBinding::TransformFeedback: + mTransformFeedback->bindIndexedBuffer(context, index, buffer, offset, size); + break; + case BufferBinding::Uniform: + mUniformBuffers[index].set(context, buffer, offset, size); + break; + case BufferBinding::AtomicCounter: + mAtomicCounterBuffers[index].set(context, buffer, offset, size); + break; + case BufferBinding::ShaderStorage: + mShaderStorageBuffers[index].set(context, buffer, offset, size); + break; + default: + UNREACHABLE(); + break; + } } const OffsetBindingPointer &State::getIndexedUniformBuffer(size_t index) const @@ -1077,62 +1305,48 @@ const OffsetBindingPointer &State::getIndexedUniformBuffer(size_t index) return mUniformBuffers[index]; } -void State::setCopyReadBufferBinding(Buffer *buffer) +const OffsetBindingPointer &State::getIndexedAtomicCounterBuffer(size_t index) const { - mCopyReadBuffer.set(buffer); + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + return mAtomicCounterBuffers[index]; } -void State::setCopyWriteBufferBinding(Buffer *buffer) +const OffsetBindingPointer &State::getIndexedShaderStorageBuffer(size_t index) const { - mCopyWriteBuffer.set(buffer); + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + return mShaderStorageBuffers[index]; } -void State::setPixelPackBufferBinding(Buffer *buffer) -{ - mPack.pixelBuffer.set(buffer); -} - -void State::setPixelUnpackBufferBinding(Buffer *buffer) -{ - mUnpack.pixelBuffer.set(buffer); -} - -Buffer *State::getTargetBuffer(GLenum target) const +Buffer *State::getTargetBuffer(BufferBinding target) const { switch (target) { - 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().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 mTransformFeedback->getGenericBuffer().get(); - case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); - default: UNREACHABLE(); return NULL; + case BufferBinding::ElementArray: + return getVertexArray()->getElementArrayBuffer().get(); + case BufferBinding::TransformFeedback: + return mTransformFeedback->getGenericBuffer().get(); + default: + return mBoundBuffers[target].get(); } } -void State::detachBuffer(GLuint bufferName) +void State::detachBuffer(const Context *context, GLuint bufferName) { - BindingPointer *buffers[] = {&mArrayBuffer, &mCopyReadBuffer, - &mCopyWriteBuffer, &mPack.pixelBuffer, - &mUnpack.pixelBuffer, &mGenericUniformBuffer}; - for (auto buffer : buffers) + for (auto &buffer : mBoundBuffers) { - if (buffer->id() == bufferName) + if (buffer.id() == bufferName) { - buffer->set(nullptr); + buffer.set(context, nullptr); } } TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); if (curTransformFeedback) { - curTransformFeedback->detachBuffer(bufferName); + curTransformFeedback->detachBuffer(context, bufferName); } - getVertexArray()->detachBuffer(bufferName); + getVertexArray()->detachBuffer(context, bufferName); } void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) @@ -1145,46 +1359,56 @@ 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); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(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); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(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); + mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); + mDirtyCurrentValues.set(index); +} + +void State::setVertexAttribPointer(const Context *context, + unsigned int attribNum, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer) +{ + getVertexArray()->setVertexAttribPointer(context, attribNum, boundBuffer, size, type, + normalized, pureInteger, stride, pointer); + mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); } -void State::setVertexAttribState(unsigned int attribNum, - Buffer *boundBuffer, - GLint size, - GLenum type, - bool normalized, - bool pureInteger, - GLsizei stride, - const void *pointer) +void State::setVertexAttribDivisor(const Context *context, GLuint index, GLuint divisor) { - getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); + getVertexArray()->setVertexAttribDivisor(context, index, divisor); mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); } -void State::setVertexAttribDivisor(GLuint index, GLuint divisor) +const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(size_t attribNum) const { - getVertexArray()->setVertexAttribDivisor(index, divisor); - mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); + ASSERT(attribNum < mVertexAttribCurrentValues.size()); + return mVertexAttribCurrentValues[attribNum]; } -const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const +const std::vector &State::getVertexAttribCurrentValues() const { - ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); - return mVertexAttribCurrentValues[attribNum]; + return mVertexAttribCurrentValues; } const void *State::getVertexAttribPointer(unsigned int attribNum) const @@ -1195,7 +1419,7 @@ const void *State::getVertexAttribPointer(unsigned int attribNum) const void State::setPackAlignment(GLint alignment) { mPack.alignment = alignment; - mDirtyBits.set(DIRTY_BIT_PACK_ALIGNMENT); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackAlignment() const @@ -1206,7 +1430,7 @@ GLint State::getPackAlignment() const void State::setPackReverseRowOrder(bool reverseRowOrder) { mPack.reverseRowOrder = reverseRowOrder; - mDirtyBits.set(DIRTY_BIT_PACK_REVERSE_ROW_ORDER); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } bool State::getPackReverseRowOrder() const @@ -1217,7 +1441,7 @@ bool State::getPackReverseRowOrder() const void State::setPackRowLength(GLint rowLength) { mPack.rowLength = rowLength; - mDirtyBits.set(DIRTY_BIT_PACK_ROW_LENGTH); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackRowLength() const @@ -1228,7 +1452,7 @@ GLint State::getPackRowLength() const void State::setPackSkipRows(GLint skipRows) { mPack.skipRows = skipRows; - mDirtyBits.set(DIRTY_BIT_PACK_SKIP_ROWS); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackSkipRows() const @@ -1239,7 +1463,7 @@ GLint State::getPackSkipRows() const void State::setPackSkipPixels(GLint skipPixels) { mPack.skipPixels = skipPixels; - mDirtyBits.set(DIRTY_BIT_PACK_SKIP_PIXELS); + mDirtyBits.set(DIRTY_BIT_PACK_STATE); } GLint State::getPackSkipPixels() const @@ -1260,7 +1484,7 @@ PixelPackState &State::getPackState() void State::setUnpackAlignment(GLint alignment) { mUnpack.alignment = alignment; - mDirtyBits.set(DIRTY_BIT_UNPACK_ALIGNMENT); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackAlignment() const @@ -1271,7 +1495,7 @@ GLint State::getUnpackAlignment() const void State::setUnpackRowLength(GLint rowLength) { mUnpack.rowLength = rowLength; - mDirtyBits.set(DIRTY_BIT_UNPACK_ROW_LENGTH); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackRowLength() const @@ -1282,7 +1506,7 @@ GLint State::getUnpackRowLength() const void State::setUnpackImageHeight(GLint imageHeight) { mUnpack.imageHeight = imageHeight; - mDirtyBits.set(DIRTY_BIT_UNPACK_IMAGE_HEIGHT); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackImageHeight() const @@ -1293,7 +1517,7 @@ GLint State::getUnpackImageHeight() const void State::setUnpackSkipImages(GLint skipImages) { mUnpack.skipImages = skipImages; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_IMAGES); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipImages() const @@ -1304,7 +1528,7 @@ GLint State::getUnpackSkipImages() const void State::setUnpackSkipRows(GLint skipRows) { mUnpack.skipRows = skipRows; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_ROWS); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipRows() const @@ -1315,7 +1539,7 @@ GLint State::getUnpackSkipRows() const void State::setUnpackSkipPixels(GLint skipPixels) { mUnpack.skipPixels = skipPixels; - mDirtyBits.set(DIRTY_BIT_UNPACK_SKIP_PIXELS); + mDirtyBits.set(DIRTY_BIT_UNPACK_STATE); } GLint State::getUnpackSkipPixels() const @@ -1343,6 +1567,84 @@ Debug &State::getDebug() return mDebug; } +void State::setCoverageModulation(GLenum components) +{ + mCoverageModulation = components; + mDirtyBits.set(DIRTY_BIT_COVERAGE_MODULATION); +} + +GLenum State::getCoverageModulation() const +{ + return mCoverageModulation; +} + +void State::loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix) +{ + if (matrixMode == GL_PATH_MODELVIEW_CHROMIUM) + { + memcpy(mPathMatrixMV, matrix, 16 * sizeof(GLfloat)); + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_MATRIX_MV); + } + else if (matrixMode == GL_PATH_PROJECTION_CHROMIUM) + { + memcpy(mPathMatrixProj, matrix, 16 * sizeof(GLfloat)); + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ); + } + else + { + UNREACHABLE(); + } +} + +const GLfloat *State::getPathRenderingMatrix(GLenum which) const +{ + if (which == GL_PATH_MODELVIEW_MATRIX_CHROMIUM) + { + return mPathMatrixMV; + } + else if (which == GL_PATH_PROJECTION_MATRIX_CHROMIUM) + { + return mPathMatrixProj; + } + + UNREACHABLE(); + return nullptr; +} + +void State::setPathStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + mPathStencilFunc = func; + mPathStencilRef = ref; + mPathStencilMask = mask; + mDirtyBits.set(DIRTY_BIT_PATH_RENDERING_STENCIL_STATE); +} + +GLenum State::getPathStencilFunc() const +{ + return mPathStencilFunc; +} + +GLint State::getPathStencilRef() const +{ + return mPathStencilRef; +} + +GLuint State::getPathStencilMask() const +{ + return mPathStencilMask; +} + +void State::setFramebufferSRGB(bool sRGB) +{ + mFramebufferSRGB = sRGB; + mDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_SRGB); +} + +bool State::getFramebufferSRGB() const +{ + return mFramebufferSRGB; +} + void State::getBooleanv(GLenum pname, GLboolean *params) { switch (pname) @@ -1355,10 +1657,15 @@ void State::getBooleanv(GLenum pname, GLboolean *params) params[2] = mBlend.colorMaskBlue; params[3] = mBlend.colorMaskAlpha; break; - case GL_CULL_FACE: *params = mRasterizer.cullFace; break; + case GL_CULL_FACE: + *params = mRasterizer.cullFace; + break; case GL_POLYGON_OFFSET_FILL: *params = mRasterizer.polygonOffsetFill; break; case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mBlend.sampleAlphaToCoverage; break; case GL_SAMPLE_COVERAGE: *params = mSampleCoverage; break; + case GL_SAMPLE_MASK: + *params = mSampleMask; + break; case GL_SCISSOR_TEST: *params = mScissorTest; break; case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; @@ -1378,6 +1685,28 @@ void State::getBooleanv(GLenum pname, GLboolean *params) case GL_DEBUG_OUTPUT: *params = mDebug.isOutputEnabled() ? GL_TRUE : GL_FALSE; break; + case GL_MULTISAMPLE_EXT: + *params = mMultiSampling; + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = mSampleAlphaToOne; + break; + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + *params = isBindGeneratesResourceEnabled() ? GL_TRUE : GL_FALSE; + break; + case GL_CLIENT_ARRAYS_ANGLE: + *params = areClientArraysEnabled() ? GL_TRUE : GL_FALSE; + break; + case GL_FRAMEBUFFER_SRGB_EXT: + *params = getFramebufferSRGB() ? GL_TRUE : GL_FALSE; + break; + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *params = mRobustResourceInit ? GL_TRUE : GL_FALSE; + break; + case GL_PROGRAM_CACHE_ENABLED_ANGLE: + *params = mProgramBinaryCacheEnabled ? GL_TRUE : GL_FALSE; + break; + default: UNREACHABLE(); break; @@ -1413,13 +1742,21 @@ void State::getFloatv(GLenum pname, GLfloat *params) params[2] = mBlendColor.blue; params[3] = mBlendColor.alpha; break; + case GL_MULTISAMPLE_EXT: + *params = static_cast(mMultiSampling); + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = static_cast(mSampleAlphaToOne); + case GL_COVERAGE_MODULATION_CHROMIUM: + params[0] = static_cast(mCoverageModulation); + break; default: UNREACHABLE(); break; } } -void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) +void State::getIntegerv(const Context *context, GLenum pname, GLint *params) { if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) { @@ -1437,8 +1774,15 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) // State::getFloatv. switch (pname) { - case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBuffer().id(); break; + case GL_ARRAY_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::Array].id(); + break; + case GL_DRAW_INDIRECT_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::DrawIndirect].id(); + 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; @@ -1477,10 +1821,14 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) 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; + case GL_STENCIL_VALUE_MASK: + *params = CastMaskValue(context, mDepthStencil.stencilMask); + break; case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break; case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break; - case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break; + case GL_STENCIL_BACK_VALUE_MASK: + *params = CastMaskValue(context, mDepthStencil.stencilBackMask); + break; case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break; case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break; case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break; @@ -1494,32 +1842,40 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break; case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break; case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break; - case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break; - case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break; + case GL_STENCIL_WRITEMASK: + *params = CastMaskValue(context, mDepthStencil.stencilWritemask); + break; + case GL_STENCIL_BACK_WRITEMASK: + *params = CastMaskValue(context, mDepthStencil.stencilBackWritemask); + break; case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break; - case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = mReadFramebuffer->getImplementationColorReadType(); break; - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = mReadFramebuffer->getImplementationColorReadFormat(); break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + *params = mReadFramebuffer->getImplementationColorReadType(context); + break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + *params = mReadFramebuffer->getImplementationColorReadFormat(context); + break; case GL_SAMPLE_BUFFERS: case GL_SAMPLES: { - gl::Framebuffer *framebuffer = mDrawFramebuffer; - if (framebuffer->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + Framebuffer *framebuffer = mDrawFramebuffer; + if (framebuffer->checkStatus(context) == GL_FRAMEBUFFER_COMPLETE) { switch (pname) { - case GL_SAMPLE_BUFFERS: - if (framebuffer->getSamples(data) != 0) - { - *params = 1; - } - else - { - *params = 0; - } - break; - case GL_SAMPLES: - *params = framebuffer->getSamples(data); - break; + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples(context) != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(context); + break; } } else @@ -1540,15 +1896,19 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) params[2] = mScissor.width; params[3] = mScissor.height; break; - case GL_CULL_FACE_MODE: *params = mRasterizer.cullMode; break; - case GL_FRONT_FACE: *params = mRasterizer.frontFace; break; + case GL_CULL_FACE_MODE: + *params = ToGLenum(mRasterizer.cullMode); + break; + case GL_FRONT_FACE: + *params = mRasterizer.frontFace; + break; case GL_RED_BITS: case GL_GREEN_BITS: case GL_BLUE_BITS: case GL_ALPHA_BITS: { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - const gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); + Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); if (colorbuffer) { @@ -1568,8 +1928,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) break; case GL_DEPTH_BITS: { - const gl::Framebuffer *framebuffer = getDrawFramebuffer(); - const gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); + const Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { @@ -1583,8 +1943,8 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) break; case GL_STENCIL_BITS: { - const gl::Framebuffer *framebuffer = getDrawFramebuffer(); - const gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); + const Framebuffer *framebuffer = getDrawFramebuffer(); + const FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { @@ -1600,6 +1960,11 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = getSamplerTextureId(static_cast(mActiveSampler), GL_TEXTURE_2D); break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_RECTANGLE_ANGLE); + break; case GL_TEXTURE_BINDING_CUBE_MAP: ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = @@ -1614,27 +1979,45 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) *params = getSamplerTextureId(static_cast(mActiveSampler), GL_TEXTURE_2D_ARRAY); break; + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_2D_MULTISAMPLE); + break; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_EXTERNAL_OES); + break; case GL_UNIFORM_BUFFER_BINDING: - *params = mGenericUniformBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::Uniform].id(); + break; case GL_TRANSFORM_FEEDBACK_BINDING: *params = mTransformFeedback.id(); break; case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - *params = mTransformFeedback->getGenericBuffer().id(); - break; + ASSERT(mTransformFeedback.get() != nullptr); + *params = mTransformFeedback->getGenericBuffer().id(); + break; case GL_COPY_READ_BUFFER_BINDING: - *params = mCopyReadBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::CopyRead].id(); + break; case GL_COPY_WRITE_BUFFER_BINDING: - *params = mCopyWriteBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::CopyWrite].id(); + break; case GL_PIXEL_PACK_BUFFER_BINDING: - *params = mPack.pixelBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::PixelPack].id(); + break; case GL_PIXEL_UNPACK_BUFFER_BINDING: - *params = mUnpack.pixelBuffer.id(); - break; + *params = mBoundBuffers[BufferBinding::PixelUnpack].id(); + break; + case GL_READ_BUFFER: + *params = mReadFramebuffer->getReadBufferState(); + break; + case GL_SAMPLER_BINDING: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerId(static_cast(mActiveSampler)); + break; case GL_DEBUG_LOGGED_MESSAGES: *params = static_cast(mDebug.getMessageCount()); break; @@ -1644,6 +2027,20 @@ void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) case GL_DEBUG_GROUP_STACK_DEPTH: *params = static_cast(mDebug.getGroupStackDepth()); break; + case GL_MULTISAMPLE_EXT: + *params = static_cast(mMultiSampling); + break; + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + *params = static_cast(mSampleAlphaToOne); + case GL_COVERAGE_MODULATION_CHROMIUM: + *params = static_cast(mCoverageModulation); + break; + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::AtomicCounter].id(); + break; + case GL_SHADER_STORAGE_BUFFER_BINDING: + *params = mBoundBuffers[BufferBinding::ShaderStorage].id(); + break; default: UNREACHABLE(); break; @@ -1666,75 +2063,111 @@ void State::getPointerv(GLenum pname, void **params) const } } -bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +void State::getIntegeri_v(GLenum target, GLuint index, GLint *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).id(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).id(); + break; case GL_UNIFORM_BUFFER_BINDING: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].id(); - } - break; + ASSERT(static_cast(index) < mUniformBuffers.size()); + *data = mUniformBuffers[index].id(); + break; + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].id(); + break; + case GL_SHADER_STORAGE_BUFFER_BINDING: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].id(); + break; + case GL_VERTEX_BINDING_BUFFER: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getBuffer().id(); + break; + case GL_VERTEX_BINDING_DIVISOR: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getDivisor(); + break; + case GL_VERTEX_BINDING_OFFSET: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = static_cast(mVertexArray->getVertexBinding(index).getOffset()); + break; + case GL_VERTEX_BINDING_STRIDE: + ASSERT(static_cast(index) < mVertexArray->getMaxBindings()); + *data = mVertexArray->getVertexBinding(index).getStride(); + break; + case GL_SAMPLE_MASK_VALUE: + ASSERT(static_cast(index) < mSampleMaskValues.size()); + *data = mSampleMaskValues[index]; + break; default: - return false; + UNREACHABLE(); + break; } - - return true; } -bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +void State::getInteger64i_v(GLenum target, GLuint index, GLint64 *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).getOffset(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).getOffset(); + break; case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (static_cast(index) < mTransformFeedback->getIndexedBufferCount()) - { - *data = mTransformFeedback->getIndexedBuffer(index).getSize(); - } - break; + ASSERT(static_cast(index) < mTransformFeedback->getIndexedBufferCount()); + *data = mTransformFeedback->getIndexedBuffer(index).getSize(); + break; case GL_UNIFORM_BUFFER_START: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].getOffset(); - } - break; + ASSERT(static_cast(index) < mUniformBuffers.size()); + *data = mUniformBuffers[index].getOffset(); + break; case GL_UNIFORM_BUFFER_SIZE: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].getSize(); - } - break; + ASSERT(static_cast(index) < mUniformBuffers.size()); + *data = mUniformBuffers[index].getSize(); + break; + case GL_ATOMIC_COUNTER_BUFFER_START: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].getOffset(); + break; + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + ASSERT(static_cast(index) < mAtomicCounterBuffers.size()); + *data = mAtomicCounterBuffers[index].getSize(); + break; + case GL_SHADER_STORAGE_BUFFER_START: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].getOffset(); + break; + case GL_SHADER_STORAGE_BUFFER_SIZE: + ASSERT(static_cast(index) < mShaderStorageBuffers.size()); + *data = mShaderStorageBuffers[index].getSize(); + break; default: - return false; + UNREACHABLE(); + break; } +} - return true; +void State::getBooleani_v(GLenum target, GLuint index, GLboolean *data) +{ + UNREACHABLE(); } -bool State::hasMappedBuffer(GLenum target) const +bool State::hasMappedBuffer(BufferBinding target) const { - if (target == GL_ARRAY_BUFFER) + if (target == BufferBinding::Array) { - const VertexArray *vao = getVertexArray(); + const VertexArray *vao = getVertexArray(); const auto &vertexAttribs = vao->getVertexAttributes(); + const auto &vertexBindings = vao->getVertexBindings(); size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); for (size_t attribIndex = 0; attribIndex < maxEnabledAttrib; attribIndex++) { - const gl::VertexAttribute &vertexAttrib = vertexAttribs[attribIndex]; - gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + const VertexAttribute &vertexAttrib = vertexAttribs[attribIndex]; + auto *boundBuffer = vertexBindings[vertexAttrib.bindingIndex].getBuffer().get(); if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { return true; @@ -1750,35 +2183,36 @@ bool State::hasMappedBuffer(GLenum target) const } } -void State::syncDirtyObjects() +void State::syncDirtyObjects(const Context *context) { if (!mDirtyObjects.any()) return; - syncDirtyObjects(mDirtyObjects); + syncDirtyObjects(context, mDirtyObjects); } -void State::syncDirtyObjects(const DirtyObjects &bitset) +void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset) { - for (auto dirtyObject : angle::IterateBitSet(bitset)) + for (auto dirtyObject : bitset) { switch (dirtyObject) { case DIRTY_OBJECT_READ_FRAMEBUFFER: ASSERT(mReadFramebuffer); - mReadFramebuffer->syncState(); + mReadFramebuffer->syncState(context); break; case DIRTY_OBJECT_DRAW_FRAMEBUFFER: ASSERT(mDrawFramebuffer); - mDrawFramebuffer->syncState(); + mDrawFramebuffer->syncState(context); break; case DIRTY_OBJECT_VERTEX_ARRAY: ASSERT(mVertexArray); - mVertexArray->syncImplState(); + mVertexArray->syncState(context); break; - case DIRTY_OBJECT_PROGRAM: - // TODO(jmadill): implement this + case DIRTY_OBJECT_PROGRAM_TEXTURES: + syncProgramTextures(context); break; + default: UNREACHABLE(); break; @@ -1788,7 +2222,82 @@ void State::syncDirtyObjects(const DirtyObjects &bitset) mDirtyObjects &= ~bitset; } -void State::syncDirtyObject(GLenum target) +void State::syncProgramTextures(const Context *context) +{ + // TODO(jmadill): Fine-grained updates. + if (!mProgram) + { + return; + } + + ASSERT(mDirtyObjects[DIRTY_OBJECT_PROGRAM_TEXTURES]); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); + + ActiveTextureMask newActiveTextures; + + // Initialize to the 'Initialized' state and set to 'MayNeedInit' if any texture is not + // initialized. + mCachedTexturesInitState = InitState::Initialized; + + for (const SamplerBinding &samplerBinding : mProgram->getSamplerBindings()) + { + if (samplerBinding.unreferenced) + continue; + + GLenum textureType = samplerBinding.textureType; + for (GLuint textureUnitIndex : samplerBinding.boundTextureUnits) + { + Texture *texture = getSamplerTexture(textureUnitIndex, textureType); + Sampler *sampler = getSampler(textureUnitIndex); + ASSERT(static_cast(textureUnitIndex) < mCompleteTextureCache.size()); + ASSERT(static_cast(textureUnitIndex) < newActiveTextures.size()); + + ASSERT(texture); + + // Mark the texture binding bit as dirty if the texture completeness changes. + // TODO(jmadill): Use specific dirty bit for completeness change. + if (texture->isSamplerComplete(context, sampler) && + !mDrawFramebuffer->hasTextureAttachment(texture)) + { + texture->syncState(); + mCompleteTextureCache[textureUnitIndex] = texture; + } + else + { + mCompleteTextureCache[textureUnitIndex] = nullptr; + } + + // Bind the texture unconditionally, to recieve completeness change notifications. + mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel()); + mActiveTexturesMask.set(textureUnitIndex); + newActiveTextures.set(textureUnitIndex); + + if (sampler != nullptr) + { + sampler->syncState(context); + } + + if (texture->initState() == InitState::MayNeedInit) + { + mCachedTexturesInitState = InitState::MayNeedInit; + } + } + } + + // Unset now missing textures. + ActiveTextureMask negativeMask = mActiveTexturesMask & ~newActiveTextures; + if (negativeMask.any()) + { + for (auto textureIndex : negativeMask) + { + mCompleteTextureBindings[textureIndex].reset(); + mCompleteTextureCache[textureIndex] = nullptr; + mActiveTexturesMask.reset(textureIndex); + } + } +} + +void State::syncDirtyObject(const Context *context, GLenum target) { DirtyObjects localSet; @@ -1807,12 +2316,14 @@ void State::syncDirtyObject(GLenum target) case GL_VERTEX_ARRAY: localSet.set(DIRTY_OBJECT_VERTEX_ARRAY); break; + case GL_TEXTURE: + case GL_SAMPLER: case GL_PROGRAM: - localSet.set(DIRTY_OBJECT_PROGRAM); + localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES); break; } - syncDirtyObjects(localSet); + syncDirtyObjects(context, localSet); } void State::setObjectDirty(GLenum target) @@ -1832,10 +2343,91 @@ void State::setObjectDirty(GLenum target) case GL_VERTEX_ARRAY: mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); break; + case GL_TEXTURE: + case GL_SAMPLER: case GL_PROGRAM: - mDirtyObjects.set(DIRTY_OBJECT_PROGRAM); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS); break; } } +void State::onProgramExecutableChange(Program *program) +{ + // OpenGL Spec: + // "If LinkProgram or ProgramBinary successfully re-links a program object + // that was already in use as a result of a previous call to UseProgram, then the + // generated executable code will be installed as part of the current rendering state." + if (program->isLinked() && mProgram == program) + { + mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE); + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + } +} + +void State::setImageUnit(const Context *context, + GLuint unit, + Texture *texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + mImageUnits[unit].texture.set(context, texture); + mImageUnits[unit].level = level; + mImageUnits[unit].layered = layered; + mImageUnits[unit].layer = layer; + mImageUnits[unit].access = access; + mImageUnits[unit].format = format; +} + +const ImageUnit &State::getImageUnit(GLuint unit) const +{ + return mImageUnits[unit]; +} + +// Handle a dirty texture event. +void State::signal(size_t textureIndex, InitState initState) +{ + // Conservatively assume all textures are dirty. + // TODO(jmadill): More fine-grained update. + mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); + + if (initState == InitState::MayNeedInit) + { + mCachedTexturesInitState = InitState::MayNeedInit; + } +} + +Error State::clearUnclearedActiveTextures(const Context *context) +{ + ASSERT(mRobustResourceInit); + + if (mCachedTexturesInitState == InitState::Initialized) + { + return NoError(); + } + + for (auto textureIndex : mActiveTexturesMask) + { + Texture *texture = mCompleteTextureCache[textureIndex]; + if (texture) + { + ANGLE_TRY(texture->ensureInitialized(context)); + } + } + + mCachedTexturesInitState = InitState::Initialized; + + return NoError(); +} + +AttributesMask State::getAndResetDirtyCurrentValues() const +{ + AttributesMask retVal = mDirtyCurrentValues; + mDirtyCurrentValues.reset(); + return retVal; +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/State.h b/src/3rdparty/angle/src/libANGLE/State.h index e822d7e679..52e1d78382 100644 --- a/src/3rdparty/angle/src/libANGLE/State.h +++ b/src/3rdparty/angle/src/libANGLE/State.h @@ -12,14 +12,18 @@ #include #include +#include "common/Color.h" #include "common/angleutils.h" +#include "common/bitset_utils.h" #include "libANGLE/Debug.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" #include "libANGLE/RefCountObject.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Sampler.h" #include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" +#include "libANGLE/Version.h" #include "libANGLE/VertexAttribute.h" #include "libANGLE/angletypes.h" @@ -29,21 +33,20 @@ class Query; class VertexArray; class Context; struct Caps; -struct Data; -typedef std::map> TextureMap; - -class State : angle::NonCopyable +class State : public OnAttachmentDirtyReceiver, angle::NonCopyable { public: State(); - ~State(); + ~State() override; - void initialize(const Caps &caps, - const Extensions &extensions, - GLuint clientVersion, - bool debug); - void reset(); + void initialize(const Context *context, + bool debug, + bool bindGeneratesResource, + bool clientArraysEnabled, + bool robustResourceInit, + bool programBinaryCacheEnabled); + void reset(const Context *context); // State chunk getters const RasterizerState &getRasterizerState() const; @@ -74,7 +77,7 @@ class State : angle::NonCopyable // Face culling state manipulation bool isCullFaceEnabled() const; void setCullFace(bool enabled); - void setCullMode(GLenum mode); + void setCullMode(CullFaceMode mode); void setFrontFace(GLenum front); // Depth test state manipulation @@ -100,8 +103,12 @@ class State : angle::NonCopyable void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); void setStencilWritemask(GLuint stencilWritemask); void setStencilBackWritemask(GLuint stencilBackWritemask); - void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); - void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); + void setStencilOperations(GLenum stencilFail, + GLenum stencilPassDepthFail, + GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, + GLenum stencilBackPassDepthFail, + GLenum stencilBackPassDepthPass); GLint getStencilRef() const; GLint getStencilBackRef() const; @@ -116,9 +123,22 @@ class State : angle::NonCopyable bool isSampleCoverageEnabled() const; void setSampleCoverage(bool enabled); void setSampleCoverageParams(GLclampf value, bool invert); - GLclampf getSampleCoverageValue() const; + GLfloat getSampleCoverageValue() const; bool getSampleCoverageInvert() const; + // Multisample mask state manipulation. + bool isSampleMaskEnabled() const; + void setSampleMaskEnabled(bool enabled); + void setSampleMaskParams(GLuint maskNumber, GLbitfield mask); + GLbitfield getSampleMaskWord(GLuint maskNumber) const; + GLuint getMaxSampleMaskWords() const; + + // Multisampling/alpha to one manipulation. + void setSampleAlphaToOne(bool enabled); + bool isSampleAlphaToOneEnabled() const; + void setMultisampling(bool enabled); + bool isMultisamplingEnabled() const; + // Scissor test state toggle & query bool isScissorTestEnabled() const; void setScissorTest(bool enabled); @@ -131,7 +151,7 @@ class State : angle::NonCopyable // Generic state toggle & query void setEnableFeature(GLenum feature, bool enabled); - bool getEnableFeature(GLenum feature); + bool getEnableFeature(GLenum feature) const; // Line width state setter void setLineWidth(GLfloat width); @@ -141,6 +161,12 @@ class State : angle::NonCopyable void setGenerateMipmapHint(GLenum hint); void setFragmentShaderDerivativeHint(GLenum hint); + // GL_CHROMIUM_bind_generates_resource + bool isBindGeneratesResourceEnabled() const; + + // GL_ANGLE_client_arrays + bool areClientArraysEnabled() const; + // Viewport state setter/getter void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); const Rectangle &getViewport() const; @@ -148,33 +174,31 @@ class State : angle::NonCopyable // Texture binding & active texture unit manipulation void setActiveSampler(unsigned int active); unsigned int getActiveSampler() const; - void setSamplerTexture(GLenum type, Texture *texture); + void setSamplerTexture(const Context *context, 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); - void initializeZeroTextures(const TextureMap &zeroTextures); + void detachTexture(const Context *context, const TextureMap &zeroTextures, GLuint texture); + void initializeZeroTextures(const Context *context, const TextureMap &zeroTextures); // Sampler object binding manipulation - void setSamplerBinding(GLuint textureUnit, Sampler *sampler); + void setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler); GLuint getSamplerId(GLuint textureUnit) const; Sampler *getSampler(GLuint textureUnit) const; - void detachSampler(GLuint sampler); + void detachSampler(const Context *context, GLuint sampler); // Renderbuffer binding manipulation - void setRenderbufferBinding(Renderbuffer *renderbuffer); + void setRenderbufferBinding(const Context *context, Renderbuffer *renderbuffer); GLuint getRenderbufferId() const; - Renderbuffer *getCurrentRenderbuffer(); - void detachRenderbuffer(GLuint renderbuffer); + Renderbuffer *getCurrentRenderbuffer() const; + void detachRenderbuffer(const Context *context, GLuint renderbuffer); // Framebuffer binding manipulation void setReadFramebufferBinding(Framebuffer *framebuffer); void setDrawFramebufferBinding(Framebuffer *framebuffer); Framebuffer *getTargetFramebuffer(GLenum target) const; - Framebuffer *getReadFramebuffer(); - Framebuffer *getDrawFramebuffer(); - const Framebuffer *getReadFramebuffer() const; - const Framebuffer *getDrawFramebuffer() const; + Framebuffer *getReadFramebuffer() const; + Framebuffer *getDrawFramebuffer() const; bool removeReadFramebufferBinding(GLuint framebuffer); bool removeDrawFramebufferBinding(GLuint framebuffer); @@ -185,55 +209,75 @@ class State : angle::NonCopyable bool removeVertexArrayBinding(GLuint vertexArray); // Program binding manipulation - void setProgram(Program *newProgram); + void setProgram(const Context *context, Program *newProgram); Program *getProgram() const; // Transform feedback object (not buffer) binding manipulation - void setTransformFeedbackBinding(TransformFeedback *transformFeedback); + void setTransformFeedbackBinding(const Context *context, TransformFeedback *transformFeedback); TransformFeedback *getCurrentTransformFeedback() const; bool isTransformFeedbackActiveUnpaused() const; - void detachTransformFeedback(GLuint transformFeedback); + bool removeTransformFeedbackBinding(const Context *context, GLuint transformFeedback); // Query binding manipulation - bool isQueryActive() const; + bool isQueryActive(const GLenum type) const; bool isQueryActive(Query *query) const; - void setActiveQuery(GLenum target, Query *query); + void setActiveQuery(const Context *context, GLenum target, Query *query); GLuint getActiveQueryId(GLenum target) const; Query *getActiveQuery(GLenum target) const; + // Program Pipeline binding manipulation + void setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline); + void detachProgramPipeline(const Context *context, GLuint pipeline); + //// Typed buffer binding point manipulation //// - // GL_ARRAY_BUFFER - void setArrayBufferBinding(Buffer *buffer); - GLuint getArrayBufferId() const; + void setBufferBinding(const Context *context, BufferBinding target, Buffer *buffer); + Buffer *getTargetBuffer(BufferBinding target) const; + void setIndexedBufferBinding(const Context *context, + BufferBinding target, + GLuint index, + Buffer *buffer, + GLintptr offset, + GLsizeiptr size); - // GL_UNIFORM_BUFFER - Both indexed and generic targets - void setGenericUniformBufferBinding(Buffer *buffer); - void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); const OffsetBindingPointer &getIndexedUniformBuffer(size_t index) const; + const OffsetBindingPointer &getIndexedAtomicCounterBuffer(size_t index) const; + const OffsetBindingPointer &getIndexedShaderStorageBuffer(size_t index) const; - // GL_COPY_[READ/WRITE]_BUFFER - void setCopyReadBufferBinding(Buffer *buffer); - void setCopyWriteBufferBinding(Buffer *buffer); - - // GL_PIXEL[PACK/UNPACK]_BUFFER - void setPixelPackBufferBinding(Buffer *buffer); - void setPixelUnpackBufferBinding(Buffer *buffer); - - // Retrieve typed buffer by target (non-indexed) - Buffer *getTargetBuffer(GLenum target) const; // Detach a buffer from all bindings - void detachBuffer(GLuint bufferName); + void detachBuffer(const Context *context, GLuint bufferName); // Vertex attrib manipulation void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + void setElementArrayBuffer(const Context *context, Buffer *buffer); void setVertexAttribf(GLuint index, const GLfloat values[4]); void setVertexAttribu(GLuint index, const GLuint values[4]); 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; + void setVertexAttribPointer(const Context *context, + unsigned int attribNum, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer); + void setVertexAttribDivisor(const Context *context, GLuint index, GLuint divisor); + const VertexAttribCurrentValueData &getVertexAttribCurrentValue(size_t attribNum) const; + const std::vector &getVertexAttribCurrentValues() const; const void *getVertexAttribPointer(unsigned int attribNum) const; + void bindVertexBuffer(const Context *context, + GLuint bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + void setVertexAttribFormat(GLuint attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void setVertexAttribBinding(const Context *context, GLuint attribIndex, GLuint bindingIndex); + void setVertexBindingDivisor(GLuint bindingIndex, GLuint divisor); // Pixel pack state manipulation void setPackAlignment(GLint alignment); @@ -269,15 +313,37 @@ class State : angle::NonCopyable const Debug &getDebug() const; Debug &getDebug(); + // CHROMIUM_framebuffer_mixed_samples coverage modulation + void setCoverageModulation(GLenum components); + GLenum getCoverageModulation() const; + + // CHROMIUM_path_rendering + void loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix); + const GLfloat *getPathRenderingMatrix(GLenum which) const; + void setPathStencilFunc(GLenum func, GLint ref, GLuint mask); + + GLenum getPathStencilFunc() const; + GLint getPathStencilRef() const; + GLuint getPathStencilMask() const; + + // GL_EXT_sRGB_write_control + void setFramebufferSRGB(bool sRGB); + bool getFramebufferSRGB() const; + // 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 getIntegerv(const Context *context, 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); + void getIntegeri_v(GLenum target, GLuint index, GLint *data); + void getInteger64i_v(GLenum target, GLuint index, GLint64 *data); + void getBooleani_v(GLenum target, GLuint index, GLboolean *data); - bool hasMappedBuffer(GLenum target) const; + bool hasMappedBuffer(BufferBinding target) const; + bool isRobustResourceInitEnabled() const { return mRobustResourceInit; } + + // Sets the dirty bit for the program executable. + void onProgramExecutableChange(Program *program); enum DirtyBitType { @@ -293,6 +359,8 @@ class State : angle::NonCopyable DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED, DIRTY_BIT_SAMPLE_COVERAGE_ENABLED, DIRTY_BIT_SAMPLE_COVERAGE, + DIRTY_BIT_SAMPLE_MASK_ENABLED, + DIRTY_BIT_SAMPLE_MASK, DIRTY_BIT_DEPTH_TEST_ENABLED, DIRTY_BIT_DEPTH_FUNC, DIRTY_BIT_DEPTH_MASK, @@ -314,17 +382,10 @@ class State : angle::NonCopyable 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_UNPACK_STATE, + DIRTY_BIT_UNPACK_BUFFER_BINDING, + DIRTY_BIT_PACK_STATE, + DIRTY_BIT_PACK_BUFFER_BINDING, DIRTY_BIT_DITHER_ENABLED, DIRTY_BIT_GENERATE_MIPMAP_HINT, DIRTY_BIT_SHADER_DERIVATIVE_HINT, @@ -332,51 +393,83 @@ class State : angle::NonCopyable DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING, DIRTY_BIT_RENDERBUFFER_BINDING, DIRTY_BIT_VERTEX_ARRAY_BINDING, + DIRTY_BIT_DRAW_INDIRECT_BUFFER_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, + DIRTY_BIT_PROGRAM_EXECUTABLE, + // TODO(jmadill): Fine-grained dirty bits for each texture/sampler. + DIRTY_BIT_TEXTURE_BINDINGS, + DIRTY_BIT_SAMPLER_BINDINGS, + DIRTY_BIT_MULTISAMPLING, + DIRTY_BIT_SAMPLE_ALPHA_TO_ONE, + DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples + DIRTY_BIT_PATH_RENDERING_MATRIX_MV, // CHROMIUM_path_rendering path model view matrix + DIRTY_BIT_PATH_RENDERING_MATRIX_PROJ, // CHROMIUM_path_rendering path projection matrix + DIRTY_BIT_PATH_RENDERING_STENCIL_STATE, + DIRTY_BIT_FRAMEBUFFER_SRGB, // GL_EXT_sRGB_write_control + DIRTY_BIT_CURRENT_VALUES, + DIRTY_BIT_INVALID, + DIRTY_BIT_MAX = DIRTY_BIT_INVALID, }; + static_assert(DIRTY_BIT_MAX <= 64, "State dirty bits must be capped at 64"); + // 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, + // Use a very coarse bit for any program or texture change. + // TODO(jmadill): Fine-grained dirty bits for each texture/sampler. + DIRTY_OBJECT_PROGRAM_TEXTURES, DIRTY_OBJECT_UNKNOWN, DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN, }; - typedef std::bitset DirtyBits; + typedef angle::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; + typedef angle::BitSet DirtyObjects; void clearDirtyObjects() { mDirtyObjects.reset(); } void setAllDirtyObjects() { mDirtyObjects.set(); } - void syncDirtyObjects(); - void syncDirtyObjects(const DirtyObjects &bitset); - void syncDirtyObject(GLenum target); + void syncDirtyObjects(const Context *context); + void syncDirtyObjects(const Context *context, const DirtyObjects &bitset); + void syncDirtyObject(const Context *context, 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; } + // This actually clears the current value dirty bits. + // TODO(jmadill): Pass mutable dirty bits into Impl. + AttributesMask getAndResetDirtyCurrentValues() const; + + void setImageUnit(const Context *context, + GLuint unit, + Texture *texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); + + const ImageUnit &getImageUnit(GLuint unit) const; + const std::vector &getCompleteTextureCache() const { return mCompleteTextureCache; } + + // Handle a dirty texture event. + void signal(size_t textureIndex, InitState initState) override; + + Error clearUnclearedActiveTextures(const Context *context); private: + void syncProgramTextures(const Context *context); + // Cached values from Context's caps GLuint mMaxDrawBuffers; GLuint mMaxCombinedTextureImageUnits; ColorF mColorClearValue; - GLclampf mDepthClearValue; + GLfloat mDepthClearValue; int mStencilClearValue; RasterizerState mRasterizer; @@ -386,8 +479,11 @@ class State : angle::NonCopyable BlendState mBlend; ColorF mBlendColor; bool mSampleCoverage; - GLclampf mSampleCoverageValue; + GLfloat mSampleCoverageValue; bool mSampleCoverageInvert; + bool mSampleMask; + GLuint mMaxSampleMaskWords; + std::array mSampleMaskValues; DepthStencilState mDepthStencil; GLint mStencilRef; @@ -398,59 +494,109 @@ class State : angle::NonCopyable GLenum mGenerateMipmapHint; GLenum mFragmentShaderDerivativeHint; + bool mBindGeneratesResource; + bool mClientArraysEnabled; + Rectangle mViewport; float mNearZ; float mFarZ; - BindingPointer mArrayBuffer; Framebuffer *mReadFramebuffer; Framebuffer *mDrawFramebuffer; BindingPointer mRenderbuffer; Program *mProgram; + BindingPointer mProgramPipeline; typedef std::vector VertexAttribVector; - VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib VertexArray *mVertexArray; // Texture and sampler bindings - size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 + size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 typedef std::vector> TextureBindingVector; typedef std::map TextureBindingMap; TextureBindingMap mSamplerTextures; + // Texture Completeness Caching + // ---------------------------- + // The texture completeness cache uses dirty bits to avoid having to scan the list + // of textures each draw call. This gl::State class implements OnAttachmentDirtyReceiver, + // and keeps an array of bindings to the Texture class. When the Textures are marked dirty, + // they send messages to the State class (and any Framebuffers they're attached to) via the + // State::signal method (see above). Internally this then invalidates the completeness cache. + // + // Note this requires that we also invalidate the completeness cache manually on events like + // re-binding textures/samplers or a change in the program. For more information see the + // signal_utils.h header and the design doc linked there. + + // A cache of complete textures. nullptr indicates unbound or incomplete. + // Don't use BindingPointer because this cache is only valid within a draw call. + // Also stores a notification channel to the texture itself to handle texture change events. + std::vector mCompleteTextureCache; + std::vector mCompleteTextureBindings; + InitState mCachedTexturesInitState; + using ActiveTextureMask = angle::BitSet; + ActiveTextureMask mActiveTexturesMask; + typedef std::vector> SamplerBindingVector; SamplerBindingVector mSamplers; + typedef std::vector ImageUnitVector; + ImageUnitVector mImageUnits; + typedef std::map> ActiveQueryMap; ActiveQueryMap mActiveQueries; - BindingPointer mGenericUniformBuffer; - typedef std::vector> BufferVector; + // Stores the currently bound buffer for each binding point. It has entries for the element + // array buffer and the transform feedback buffer but these should not be used. Instead these + // bind points are respectively owned by current the vertex array object and the current + // transform feedback object. + using BoundBufferMap = angle::PackedEnumMap>; + BoundBufferMap mBoundBuffers; + + using BufferVector = std::vector>; BufferVector mUniformBuffers; + BufferVector mAtomicCounterBuffers; + BufferVector mShaderStorageBuffers; BindingPointer mTransformFeedback; - BindingPointer mCopyReadBuffer; - BindingPointer mCopyWriteBuffer; - + BindingPointer mPixelUnpackBuffer; PixelUnpackState mUnpack; + BindingPointer mPixelPackBuffer; PixelPackState mPack; bool mPrimitiveRestart; Debug mDebug; - DirtyBits mDirtyBits; - DirtyBits mUnpackStateBitMask; - DirtyBits mPackStateBitMask; - DirtyBits mClearStateBitMask; - DirtyBits mBlitStateBitMask; + bool mMultiSampling; + bool mSampleAlphaToOne; + + GLenum mCoverageModulation; + + // CHROMIUM_path_rendering + GLfloat mPathMatrixMV[16]; + GLfloat mPathMatrixProj[16]; + GLenum mPathStencilFunc; + GLint mPathStencilRef; + GLuint mPathStencilMask; + + // GL_EXT_sRGB_write_control + bool mFramebufferSRGB; + // GL_ANGLE_robust_resource_intialization + bool mRobustResourceInit; + + // GL_ANGLE_program_cache_control + bool mProgramBinaryCacheEnabled; + + DirtyBits mDirtyBits; DirtyObjects mDirtyObjects; + mutable AttributesMask mDirtyCurrentValues; }; -} - -#endif // LIBANGLE_STATE_H_ +} // namespace gl +#endif // LIBANGLE_STATE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Stream.cpp b/src/3rdparty/angle/src/libANGLE/Stream.cpp new file mode 100644 index 0000000000..68279976b7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Stream.cpp @@ -0,0 +1,271 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Stream.cpp: Implements the egl::Stream class, representing the stream +// where frames are streamed in. Implements EGLStreanKHR. + +#include "libANGLE/Stream.h" + +#include +#include + +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/renderer/DisplayImpl.h" +#include "libANGLE/renderer/StreamProducerImpl.h" + +namespace egl +{ + +Stream::Stream(Display *display, const AttributeMap &attribs) + : mDisplay(display), + mProducerImplementation(nullptr), + mState(EGL_STREAM_STATE_CREATED_KHR), + mProducerFrame(0), + mConsumerFrame(0), + mConsumerLatency(attribs.getAsInt(EGL_CONSUMER_LATENCY_USEC_KHR, 0)), + mConsumerAcquireTimeout(attribs.getAsInt(EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0)), + mPlaneCount(0), + mConsumerType(ConsumerType::NoConsumer), + mProducerType(ProducerType::NoProducer) +{ + for (auto &plane : mPlanes) + { + plane.textureUnit = -1; + plane.texture = nullptr; + } +} + +Stream::~Stream() +{ + SafeDelete(mProducerImplementation); + for (auto &plane : mPlanes) + { + if (plane.texture != nullptr) + { + plane.texture->releaseStream(); + } + } +} + +void Stream::setConsumerLatency(EGLint latency) +{ + mConsumerLatency = latency; +} + +EGLint Stream::getConsumerLatency() const +{ + return mConsumerLatency; +} + +EGLuint64KHR Stream::getProducerFrame() const +{ + return mProducerFrame; +} + +EGLuint64KHR Stream::getConsumerFrame() const +{ + return mConsumerFrame; +} + +EGLenum Stream::getState() const +{ + return mState; +} + +void Stream::setConsumerAcquireTimeout(EGLint timeout) +{ + mConsumerAcquireTimeout = timeout; +} + +EGLint Stream::getConsumerAcquireTimeout() const +{ + return mConsumerAcquireTimeout; +} + +Stream::ProducerType Stream::getProducerType() const +{ + return mProducerType; +} + +Stream::ConsumerType Stream::getConsumerType() const +{ + return mConsumerType; +} + +EGLint Stream::getPlaneCount() const +{ + return mPlaneCount; +} + +rx::StreamProducerImpl *Stream::getImplementation() +{ + return mProducerImplementation; +} + +Error Stream::createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_CREATED_KHR); + ASSERT(mConsumerType == ConsumerType::NoConsumer); + ASSERT(mProducerType == ProducerType::NoProducer); + ASSERT(context != nullptr); + + const auto &glState = context->getGLState(); + EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); + if (bufferType == EGL_RGB_BUFFER) + { + mPlanes[0].texture = glState.getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + ASSERT(mPlanes[0].texture != nullptr); + mPlanes[0].texture->bindStream(this); + mConsumerType = ConsumerType::GLTextureRGB; + mPlaneCount = 1; + } + else + { + mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2); + ASSERT(mPlaneCount <= 3); + for (EGLint i = 0; i < mPlaneCount; i++) + { + // Fetch all the textures + mPlanes[i].textureUnit = attributes.getAsInt(EGL_YUV_PLANE0_TEXTURE_UNIT_NV + i, -1); + if (mPlanes[i].textureUnit != EGL_NONE) + { + mPlanes[i].texture = + glState.getSamplerTexture(mPlanes[i].textureUnit, GL_TEXTURE_EXTERNAL_OES); + ASSERT(mPlanes[i].texture != nullptr); + } + } + + // Bind them to the stream + for (EGLint i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].textureUnit != EGL_NONE) + { + mPlanes[i].texture->bindStream(this); + } + } + mConsumerType = ConsumerType::GLTextureYUV; + } + + mContext = context; + mState = EGL_STREAM_STATE_CONNECTING_KHR; + + return NoError(); +} + +Error Stream::createProducerD3D11TextureNV12(const AttributeMap &attributes) +{ + ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::NoProducer); + ASSERT(mPlaneCount == 2); + + mProducerImplementation = mDisplay->getImplementation()->createStreamProducerD3DTextureNV12( + mConsumerType, attributes); + mProducerType = ProducerType::D3D11TextureNV12; + mState = EGL_STREAM_STATE_EMPTY_KHR; + + return NoError(); +} + +// Called when the consumer of this stream starts using the stream +Error Stream::consumerAcquire(const gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || + mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + mState = EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR; + mConsumerFrame++; + + // Bind the planes to the gl textures + for (int i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].texture != nullptr) + { + ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream( + context, mProducerImplementation->getGLFrameDescription(i))); + } + } + + return NoError(); +} + +Error Stream::consumerRelease(const gl::Context *context) +{ + ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || + mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + // Release the images + for (int i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].texture != nullptr) + { + ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context)); + } + } + + return NoError(); +} + +bool Stream::isConsumerBoundToContext(const gl::Context *context) const +{ + ASSERT(context != nullptr); + return (context == mContext); +} + +Error Stream::validateD3D11NV12Texture(void *texture) const +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + ASSERT(mProducerImplementation != nullptr); + + return mProducerImplementation->validateD3DNV12Texture(texture); +} + +Error Stream::postD3D11NV12Texture(void *texture, const AttributeMap &attributes) +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + mProducerImplementation->postD3DNV12Texture(texture, attributes); + mProducerFrame++; + + mState = EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR; + + return NoError(); +} + +// This is called when a texture object associated with this stream is destroyed. Even if multiple +// textures are bound, one being destroyed invalidates the stream, so all the remaining textures +// will be released and the stream will be invalidated. +void Stream::releaseTextures() +{ + for (auto &plane : mPlanes) + { + if (plane.texture != nullptr) + { + plane.texture->releaseStream(); + plane.texture = nullptr; + } + } + mConsumerType = ConsumerType::NoConsumer; + mProducerType = ProducerType::NoProducer; + mState = EGL_STREAM_STATE_DISCONNECTED_KHR; +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Stream.h b/src/3rdparty/angle/src/libANGLE/Stream.h new file mode 100644 index 0000000000..b674c44008 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Stream.h @@ -0,0 +1,143 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Stream.h: Defines the egl::Stream class, representing the stream +// where frames are streamed in. Implements EGLStreanKHR. + +#ifndef LIBANGLE_STREAM_H_ +#define LIBANGLE_STREAM_H_ + +#include + +#include +#include + +#include "common/angleutils.h" +#include "libANGLE/AttributeMap.h" + +namespace rx +{ +class StreamProducerImpl; +} + +namespace gl +{ +class Context; +class Texture; +} + +namespace egl +{ +class Display; +class Error; +class Thread; + +class Stream final : angle::NonCopyable +{ + public: + Stream(Display *display, const AttributeMap &attribs); + ~Stream(); + + enum class ConsumerType + { + NoConsumer, + GLTextureRGB, + GLTextureYUV, + }; + + enum class ProducerType + { + NoProducer, + D3D11TextureNV12, + }; + + // A GL texture interpretation of a part of a producer frame. For use with GL texture consumers + struct GLTextureDescription + { + unsigned int width; + unsigned int height; + unsigned int internalFormat; + unsigned int mipLevels; + }; + + EGLenum getState() const; + + void setConsumerLatency(EGLint latency); + EGLint getConsumerLatency() const; + + EGLuint64KHR getProducerFrame() const; + EGLuint64KHR getConsumerFrame() const; + + void setConsumerAcquireTimeout(EGLint timeout); + EGLint getConsumerAcquireTimeout() const; + + ConsumerType getConsumerType() const; + ProducerType getProducerType() const; + + EGLint getPlaneCount() const; + + rx::StreamProducerImpl *getImplementation(); + + // Consumer creation methods + Error createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context); + + // Producer creation methods + Error createProducerD3D11TextureNV12(const AttributeMap &attributes); + + // Consumer methods + Error consumerAcquire(const gl::Context *context); + Error consumerRelease(const gl::Context *context); + + // Some consumers are bound to GL contexts. This validates that a given context is bound to the + // stream's consumer + bool isConsumerBoundToContext(const gl::Context *context) const; + + // Producer methods + Error validateD3D11NV12Texture(void *texture) const; + Error postD3D11NV12Texture(void *texture, const AttributeMap &attributes); + + private: + // Associated display + Display *mDisplay; + + // Producer Implementation + rx::StreamProducerImpl *mProducerImplementation; + + // Associated GL context. Note that this is a weak pointer used for validation purposes only, + // and should never be arbitrarily dereferenced without knowing the context still exists as it + // can become dangling at any time. + gl::Context *mContext; + + // EGL defined attributes + EGLint mState; + EGLuint64KHR mProducerFrame; + EGLuint64KHR mConsumerFrame; + EGLint mConsumerLatency; + + // EGL gltexture consumer attributes + EGLint mConsumerAcquireTimeout; + + // EGL gltexture yuv consumer attributes + EGLint mPlaneCount; + struct PlaneTexture + { + EGLint textureUnit; + gl::Texture *texture; + }; + // Texture units and textures for all the planes + std::array mPlanes; + + // Consumer and producer types + ConsumerType mConsumerType; + ProducerType mProducerType; + + // ANGLE-only method, used internally + friend class gl::Texture; + void releaseTextures(); +}; +} // namespace egl + +#endif // LIBANGLE_STREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Surface.cpp b/src/3rdparty/angle/src/libANGLE/Surface.cpp index b5ed0ff5a6..746da03778 100644 --- a/src/3rdparty/angle/src/libANGLE/Surface.cpp +++ b/src/3rdparty/angle/src/libANGLE/Surface.cpp @@ -10,29 +10,44 @@ #include "libANGLE/Surface.h" -#include "libANGLE/Config.h" -#include "libANGLE/Framebuffer.h" -#include "libANGLE/Texture.h" - #include #include +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Thread.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/EGLImplFactory.h" + namespace egl { -Surface::Surface(rx::SurfaceImpl *impl, - EGLint surfaceType, - const egl::Config *config, - const AttributeMap &attributes) +SurfaceState::SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn) + : defaultFramebuffer(nullptr), config(configIn), attributes(attributesIn) +{ +} + +Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) : FramebufferAttachmentObject(), - mImplementation(impl), - mDefaultFramebuffer(nullptr), + mState(config, attributes), + mImplementation(nullptr), mCurrentCount(0), mDestroyed(false), mType(surfaceType), - mConfig(config), mPostSubBufferRequested(false), + mLargestPbuffer(false), + mGLColorspace(EGL_GL_COLORSPACE_LINEAR), + mVGAlphaFormat(EGL_VG_ALPHA_FORMAT_NONPRE), + mVGColorspace(EGL_VG_COLORSPACE_sRGB), + mMipmapTexture(false), + mMipmapLevel(0), + mHorizontalResolution(EGL_UNKNOWN), + mVerticalResolution(EGL_UNKNOWN), + mMultisampleResolve(EGL_MULTISAMPLE_RESOLVE_DEFAULT), mFixedSize(false), mFixedWidth(0), mFixedHeight(0), @@ -41,75 +56,135 @@ Surface::Surface(rx::SurfaceImpl *impl, // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio(static_cast(1.0 * EGL_DISPLAY_SCALING)), mRenderBuffer(EGL_BACK_BUFFER), - mSwapBehavior(impl->getSwapBehavior()), + mSwapBehavior(EGL_NONE), mOrientation(0), - mTexture() + mTexture(), + mBackFormat(config->renderTargetFormat), + mDSFormat(config->depthStencilFormat) { 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); + if (mType == EGL_PBUFFER_BIT) + { + mLargestPbuffer = (attributes.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); + } + + mGLColorspace = + static_cast(attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR)); + mVGAlphaFormat = + static_cast(attributes.get(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_NONPRE)); + mVGColorspace = static_cast(attributes.get(EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB)); + mMipmapTexture = (attributes.get(EGL_MIPMAP_TEXTURE, EGL_FALSE) == EGL_TRUE); + mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); + mRobustResourceInitialization = + (attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); + mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); if (mFixedSize) { - mFixedWidth = attributes.get(EGL_WIDTH, 0); - mFixedHeight = attributes.get(EGL_HEIGHT, 0); + mFixedWidth = static_cast(attributes.get(EGL_WIDTH, 0)); + mFixedHeight = static_cast(attributes.get(EGL_HEIGHT, 0)); } if (mType != EGL_WINDOW_BIT) { - mTextureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + mTextureFormat = static_cast(attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE)); + mTextureTarget = static_cast(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); } - mOrientation = attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0); - - mDefaultFramebuffer = createDefaultFramebuffer(); - ASSERT(mDefaultFramebuffer != nullptr); + mOrientation = static_cast(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); } Surface::~Surface() { +} + +rx::FramebufferAttachmentObjectImpl *Surface::getAttachmentImpl() const +{ + return mImplementation; +} + +Error Surface::destroyImpl(const Display *display) +{ + if (mState.defaultFramebuffer) + { + mState.defaultFramebuffer->destroyDefault(display); + } + if (mImplementation) + { + mImplementation->destroy(display); + } + if (mTexture.get()) { if (mImplementation) { - mImplementation->releaseTexImage(EGL_BACK_BUFFER); + ANGLE_TRY(mImplementation->releaseTexImage(EGL_BACK_BUFFER)); } - mTexture->releaseTexImageFromSurface(); - mTexture.set(nullptr); + auto glErr = mTexture->releaseTexImageFromSurface(display->getProxyContext()); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(nullptr, nullptr); } - SafeDelete(mDefaultFramebuffer); + if (mState.defaultFramebuffer) + { + mState.defaultFramebuffer->onDestroy(display->getProxyContext()); + } + SafeDelete(mState.defaultFramebuffer); SafeDelete(mImplementation); + + delete this; + return NoError(); +} + +Error Surface::initialize(const Display *display) +{ + ANGLE_TRY(mImplementation->initialize(display)); + + // Initialized here since impl is nullptr in the constructor. + // Must happen after implementation initialize for Android. + mSwapBehavior = mImplementation->getSwapBehavior(); + + // Must happen after implementation initialize for OSX. + mState.defaultFramebuffer = createDefaultFramebuffer(display); + ASSERT(mState.defaultFramebuffer != nullptr); + + return NoError(); } -void Surface::setIsCurrent(bool isCurrent) +Error Surface::setIsCurrent(const gl::Context *context, bool isCurrent) { if (isCurrent) { mCurrentCount++; + return NoError(); } - else + + ASSERT(mCurrentCount > 0); + mCurrentCount--; + if (mCurrentCount == 0 && mDestroyed) { - ASSERT(mCurrentCount > 0); - mCurrentCount--; - if (mCurrentCount == 0 && mDestroyed) - { - delete this; - } + ASSERT(context); + return destroyImpl(context->getCurrentDisplay()); } + return NoError(); } -void Surface::onDestroy() +Error Surface::onDestroy(const Display *display) { mDestroyed = true; if (mCurrentCount == 0) { - delete this; + return destroyImpl(display); } + return NoError(); } EGLint Surface::getType() const @@ -117,14 +192,23 @@ EGLint Surface::getType() const return mType; } -Error Surface::swap() +Error Surface::swap(const gl::Context *context) +{ + return mImplementation->swap(context); +} + +Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) { - return mImplementation->swap(); + return mImplementation->swapWithDamage(context, rects, n_rects); } -Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +Error Surface::postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { - return mImplementation->postSubBuffer(x, y, width, height); + return mImplementation->postSubBuffer(context, x, y, width, height); } Error Surface::querySurfacePointerANGLE(EGLint attribute, void **value) @@ -142,9 +226,30 @@ void Surface::setSwapInterval(EGLint interval) mImplementation->setSwapInterval(interval); } +void Surface::setMipmapLevel(EGLint level) +{ + // Level is set but ignored + UNIMPLEMENTED(); + mMipmapLevel = level; +} + +void Surface::setMultisampleResolve(EGLenum resolve) +{ + // Behaviour is set but ignored + UNIMPLEMENTED(); + mMultisampleResolve = resolve; +} + +void Surface::setSwapBehavior(EGLenum behavior) +{ + // Behaviour is set but ignored + UNIMPLEMENTED(); + mSwapBehavior = behavior; +} + const Config *Surface::getConfig() const { - return mConfig; + return mState.config; } EGLint Surface::getPixelAspectRatio() const @@ -172,6 +277,51 @@ EGLenum Surface::getTextureTarget() const return mTextureTarget; } +bool Surface::getLargestPbuffer() const +{ + return mLargestPbuffer; +} + +EGLenum Surface::getGLColorspace() const +{ + return mGLColorspace; +} + +EGLenum Surface::getVGAlphaFormat() const +{ + return mVGAlphaFormat; +} + +EGLenum Surface::getVGColorspace() const +{ + return mVGColorspace; +} + +bool Surface::getMipmapTexture() const +{ + return mMipmapTexture; +} + +EGLint Surface::getMipmapLevel() const +{ + return mMipmapLevel; +} + +EGLint Surface::getHorizontalResolution() const +{ + return mHorizontalResolution; +} + +EGLint Surface::getVerticalResolution() const +{ + return mVerticalResolution; +} + +EGLenum Surface::getMultisampleResolve() const +{ + return mMultisampleResolve; +} + EGLint Surface::isFixedSize() const { return mFixedSize; @@ -187,42 +337,60 @@ EGLint Surface::getHeight() const return mFixedSize ? static_cast(mFixedHeight) : mImplementation->getHeight(); } -Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer) +Error Surface::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer) { ASSERT(!mTexture.get()); + ANGLE_TRY(mImplementation->bindTexImage(texture, buffer)); + + auto glErr = texture->bindTexImageFromSurface(context, this); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(context, texture); - texture->bindTexImageFromSurface(this); - mTexture.set(texture); - return mImplementation->bindTexImage(texture, buffer); + return NoError(); } -Error Surface::releaseTexImage(EGLint buffer) +Error Surface::releaseTexImage(const gl::Context *context, EGLint buffer) { + ASSERT(context); + + ANGLE_TRY(mImplementation->releaseTexImage(buffer)); + ASSERT(mTexture.get()); - mTexture->releaseTexImageFromSurface(); - mTexture.set(nullptr); + auto glErr = mTexture->releaseTexImageFromSurface(context); + if (glErr.isError()) + { + return Error(EGL_BAD_SURFACE); + } + mTexture.set(context, nullptr); - return mImplementation->releaseTexImage(buffer); + return NoError(); } -void Surface::releaseTexImageFromTexture() +Error Surface::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + return mImplementation->getSyncValues(ust, msc, sbc); +} + +void Surface::releaseTexImageFromTexture(const gl::Context *context) { ASSERT(mTexture.get()); - mTexture.set(nullptr); + mTexture.set(context, nullptr); } -gl::Extents Surface::getAttachmentSize(const gl::FramebufferAttachment::Target & /*target*/) const +gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const { return gl::Extents(getWidth(), getHeight(), 1); } -GLenum Surface::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const +const gl::Format &Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const { - const egl::Config *config = getConfig(); - return (target.binding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat); + return (binding == GL_BACK ? mBackFormat : mDSFormat); } -GLsizei Surface::getAttachmentSamples(const gl::FramebufferAttachment::Target &target) const +GLsizei Surface::getAttachmentSamples(const gl::ImageIndex &target) const { return getConfig()->samples; } @@ -233,29 +401,84 @@ GLuint Surface::getId() const return 0; } -gl::Framebuffer *Surface::createDefaultFramebuffer() +gl::Framebuffer *Surface::createDefaultFramebuffer(const Display *display) { - gl::Framebuffer *framebuffer = new gl::Framebuffer(mImplementation); + return new gl::Framebuffer(display, this); +} - GLenum drawBufferState = GL_BACK; - framebuffer->setDrawBuffers(1, &drawBufferState); - framebuffer->setReadBuffer(GL_BACK); +gl::InitState Surface::initState(const gl::ImageIndex & /*imageIndex*/) const +{ + // TODO(jmadill): Lazy surface init. + return gl::InitState::Initialized; +} - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_BACK, gl::ImageIndex::MakeInvalid(), - this); +void Surface::setInitState(const gl::ImageIndex & /*imageIndex*/, gl::InitState /*initState*/) +{ + // No-op. +} - if (mConfig->depthSize > 0) - { - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, gl::ImageIndex::MakeInvalid(), - this); - } +WindowSurface::WindowSurface(rx::EGLImplFactory *implFactory, + const egl::Config *config, + EGLNativeWindowType window, + const AttributeMap &attribs) + : Surface(EGL_WINDOW_BIT, config, attribs) +{ + mImplementation = implFactory->createWindowSurface(mState, window, attribs); +} - if (mConfig->stencilSize > 0) - { - framebuffer->setAttachment(GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, - gl::ImageIndex::MakeInvalid(), this); - } +WindowSurface::~WindowSurface() +{ +} - return framebuffer; +PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + const AttributeMap &attribs) + : Surface(EGL_PBUFFER_BIT, config, attribs) +{ + mImplementation = implFactory->createPbufferSurface(mState, attribs); +} + +PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs) + : Surface(EGL_PBUFFER_BIT, config, attribs) +{ + mImplementation = + implFactory->createPbufferFromClientBuffer(mState, buftype, clientBuffer, attribs); } + +PbufferSurface::~PbufferSurface() +{ } + +PixmapSurface::PixmapSurface(rx::EGLImplFactory *implFactory, + const Config *config, + NativePixmapType nativePixmap, + const AttributeMap &attribs) + : Surface(EGL_PIXMAP_BIT, config, attribs) +{ + mImplementation = implFactory->createPixmapSurface(mState, nativePixmap, attribs); +} + +PixmapSurface::~PixmapSurface() +{ +} + +// SurfaceDeleter implementation. + +SurfaceDeleter::SurfaceDeleter(const Display *display) : mDisplay(display) +{ +} + +SurfaceDeleter::~SurfaceDeleter() +{ +} + +void SurfaceDeleter::operator()(Surface *surface) +{ + ANGLE_SWALLOW_ERR(surface->onDestroy(mDisplay)); +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Surface.h b/src/3rdparty/angle/src/libANGLE/Surface.h index e110f5da7b..b3188ff909 100644 --- a/src/3rdparty/angle/src/libANGLE/Surface.h +++ b/src/3rdparty/angle/src/libANGLE/Surface.h @@ -14,9 +14,11 @@ #include #include "common/angleutils.h" +#include "libANGLE/AttributeMap.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/RefCountObject.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/SurfaceImpl.h" namespace gl @@ -25,33 +27,55 @@ class Framebuffer; class Texture; } +namespace rx +{ +class EGLImplFactory; +} + namespace egl { -class AttributeMap; class Display; struct Config; -class Surface final : public gl::FramebufferAttachmentObject +struct SurfaceState final : private angle::NonCopyable { - public: - Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn); + + gl::Framebuffer *defaultFramebuffer; + const egl::Config *config; + AttributeMap attributes; +}; - rx::SurfaceImpl *getImplementation() { return mImplementation; } - const rx::SurfaceImpl *getImplementation() const { return mImplementation; } +class Surface : public gl::FramebufferAttachmentObject +{ + public: + rx::SurfaceImpl *getImplementation() const { return mImplementation; } EGLint getType() const; - Error swap(); - Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + Error initialize(const Display *display); + Error swap(const gl::Context *context); + Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects); + Error postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height); Error querySurfacePointerANGLE(EGLint attribute, void **value); - Error bindTexImage(gl::Texture *texture, EGLint buffer); - Error releaseTexImage(EGLint buffer); + Error bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer); + Error releaseTexImage(const gl::Context *context, EGLint buffer); + + Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc); EGLint isPostSubBufferSupported() const; void setSwapInterval(EGLint interval); - void setIsCurrent(bool isCurrent); - void onDestroy(); + Error setIsCurrent(const gl::Context *context, bool isCurrent); + Error onDestroy(const Display *display); + + void setMipmapLevel(EGLint level); + void setMultisampleResolve(EGLenum resolve); + void setSwapBehavior(EGLenum behavior); const Config *getConfig() const; @@ -63,19 +87,29 @@ class Surface final : public gl::FramebufferAttachmentObject EGLenum getSwapBehavior() const; EGLenum getTextureFormat() const; EGLenum getTextureTarget() const; + bool getLargestPbuffer() const; + EGLenum getGLColorspace() const; + EGLenum getVGAlphaFormat() const; + EGLenum getVGColorspace() const; + bool getMipmapTexture() const; + EGLint getMipmapLevel() const; + EGLint getHorizontalResolution() const; + EGLint getVerticalResolution() const; + EGLenum getMultisampleResolve() const; gl::Texture *getBoundTexture() const { return mTexture.get(); } - gl::Framebuffer *getDefaultFramebuffer() { return mDefaultFramebuffer; } + gl::Framebuffer *getDefaultFramebuffer() { return mState.defaultFramebuffer; } 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; + gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override; + const gl::Format &getAttachmentFormat(GLenum binding, + const gl::ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override; - void onAttach() override {} - void onDetach() override {} + void onAttach(const gl::Context *context) override {} + void onDetach(const gl::Context *context) override {} GLuint getId() const override; bool flexibleSurfaceCompatibilityRequested() const @@ -86,34 +120,50 @@ class Surface final : public gl::FramebufferAttachmentObject bool directComposition() const { return mDirectComposition; } - private: - virtual ~Surface(); - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mImplementation; } + gl::InitState initState(const gl::ImageIndex &imageIndex) const override; + void setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState) override; + + bool isRobustResourceInitEnabled() const { return mRobustResourceInitialization; } + + protected: + Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + ~Surface() override; + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; - gl::Framebuffer *createDefaultFramebuffer(); + gl::Framebuffer *createDefaultFramebuffer(const Display *display); // ANGLE-only method, used internally friend class gl::Texture; - void releaseTexImageFromTexture(); + void releaseTexImageFromTexture(const gl::Context *context); + SurfaceState mState; rx::SurfaceImpl *mImplementation; - gl::Framebuffer *mDefaultFramebuffer; int mCurrentCount; bool mDestroyed; EGLint mType; - const egl::Config *mConfig; - bool mPostSubBufferRequested; bool mFlexibleSurfaceCompatibilityRequested; + bool mLargestPbuffer; + EGLenum mGLColorspace; + EGLenum mVGAlphaFormat; + EGLenum mVGColorspace; + bool mMipmapTexture; + EGLint mMipmapLevel; + EGLint mHorizontalResolution; + EGLint mVerticalResolution; + EGLenum mMultisampleResolve; + bool mFixedSize; size_t mFixedWidth; size_t mFixedHeight; bool mDirectComposition; + bool mRobustResourceInitialization; + EGLenum mTextureFormat; EGLenum mTextureTarget; @@ -123,9 +173,66 @@ class Surface final : public gl::FramebufferAttachmentObject EGLint mOrientation; - BindingPointer mTexture; + gl::BindingPointer mTexture; + + gl::Format mBackFormat; + gl::Format mDSFormat; + + private: + Error destroyImpl(const Display *display); }; -} +class WindowSurface final : public Surface +{ + public: + WindowSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLNativeWindowType window, + const AttributeMap &attribs); + ~WindowSurface() override; +}; + +class PbufferSurface final : public Surface +{ + public: + PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + const AttributeMap &attribs); + PbufferSurface(rx::EGLImplFactory *implFactory, + const Config *config, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const AttributeMap &attribs); + + protected: + ~PbufferSurface() override; +}; + +class PixmapSurface final : public Surface +{ + public: + PixmapSurface(rx::EGLImplFactory *implFactory, + const Config *config, + NativePixmapType nativePixmap, + const AttributeMap &attribs); + + protected: + ~PixmapSurface() override; +}; + +class SurfaceDeleter final +{ + public: + SurfaceDeleter(const Display *display); + ~SurfaceDeleter(); + void operator()(Surface *surface); + + private: + const Display *mDisplay; +}; + +using SurfacePointer = angle::UniqueObjectPointerBase; + +} // namespace egl #endif // LIBANGLE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp index 5ef6762d3d..da92e65916 100644 --- a/src/3rdparty/angle/src/libANGLE/Texture.cpp +++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp @@ -12,66 +12,571 @@ #include "common/utilities.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/TextureImpl.h" namespace gl { -bool IsMipmapFiltered(const gl::SamplerState &samplerState) +namespace +{ +bool IsPointSampled(const SamplerState &samplerState) +{ + return (samplerState.magFilter == GL_NEAREST && + (samplerState.minFilter == GL_NEAREST || + samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); +} + +size_t GetImageDescIndex(GLenum target, size_t level) +{ + return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) + : level; +} + +ImageIndex GetImageIndexFromDescIndex(GLenum target, size_t descIndex) +{ + if (target == GL_TEXTURE_CUBE_MAP) + { + size_t faceIndex = descIndex % 6; + size_t mipIndex = descIndex / 6; + return ImageIndex::MakeCube(LayerIndexToCubeMapTextureTarget(faceIndex), + static_cast(mipIndex)); + } + + return ImageIndex::MakeGeneric(target, static_cast(descIndex)); +} + +InitState DetermineInitState(const Context *context, const uint8_t *pixels) +{ + // Can happen in tests. + if (!context || !context->isRobustResourceInitEnabled()) + return InitState::Initialized; + + const auto &glState = context->getGLState(); + return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) + ? InitState::MayNeedInit + : InitState::Initialized; +} + +} // namespace + +bool IsMipmapFiltered(const SamplerState &samplerState) { switch (samplerState.minFilter) { - case GL_NEAREST: - case GL_LINEAR: + case GL_NEAREST: + case GL_LINEAR: + return false; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: + UNREACHABLE(); + return false; + } +} + +SwizzleState::SwizzleState() + : swizzleRed(GL_INVALID_INDEX), + swizzleGreen(GL_INVALID_INDEX), + swizzleBlue(GL_INVALID_INDEX), + swizzleAlpha(GL_INVALID_INDEX) +{ +} + +SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool SwizzleState::swizzleRequired() const +{ + return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE || + swizzleAlpha != GL_ALPHA; +} + +bool SwizzleState::operator==(const SwizzleState &other) const +{ + return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha; +} + +bool SwizzleState::operator!=(const SwizzleState &other) const +{ + return !(*this == other); +} + +TextureState::TextureState(GLenum target) + : mTarget(target), + mSwizzleState(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA), + mSamplerState(SamplerState::CreateDefaultForTarget(target)), + mBaseLevel(0), + mMaxLevel(1000), + mDepthStencilTextureMode(GL_DEPTH_COMPONENT), + mImmutableFormat(false), + mImmutableLevels(0), + mUsage(GL_NONE), + mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * + (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), + mInitState(InitState::MayNeedInit) +{ +} + +TextureState::~TextureState() +{ +} + +bool TextureState::swizzleRequired() const +{ + return mSwizzleState.swizzleRequired(); +} + +GLuint TextureState::getEffectiveBaseLevel() const +{ + if (mImmutableFormat) + { + // GLES 3.0.4 section 3.8.10 + return std::min(mBaseLevel, mImmutableLevels - 1); + } + // Some classes use the effective base level to index arrays with level data. By clamping the + // effective base level to max levels these arrays need just one extra item to store properties + // that should be returned for all out-of-range base level values, instead of needing special + // handling for out-of-range base levels. + return std::min(mBaseLevel, static_cast(IMPLEMENTATION_MAX_TEXTURE_LEVELS)); +} + +GLuint TextureState::getEffectiveMaxLevel() const +{ + if (mImmutableFormat) + { + // GLES 3.0.4 section 3.8.10 + GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel()); + clampedMaxLevel = std::min(clampedMaxLevel, mImmutableLevels - 1); + return clampedMaxLevel; + } + return mMaxLevel; +} + +GLuint TextureState::getMipmapMaxLevel() const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + GLuint expectedMipLevels = 0; + if (mTarget == GL_TEXTURE_3D) + { + const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), + baseImageDesc.size.depth); + expectedMipLevels = static_cast(log2(maxDim)); + } + else + { + expectedMipLevels = static_cast( + log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height))); + } + + return std::min(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel()); +} + +bool TextureState::setBaseLevel(GLuint baseLevel) +{ + if (mBaseLevel != baseLevel) + { + mBaseLevel = baseLevel; + return true; + } + return false; +} + +bool TextureState::setMaxLevel(GLuint maxLevel) +{ + if (mMaxLevel != maxLevel) + { + mMaxLevel = maxLevel; + return true; + } + + return false; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +// According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any +// per-level checks begin at the base-level. +// For OpenGL ES2 the base level is always zero. +bool TextureState::isCubeComplete() const +{ + ASSERT(mTarget == GL_TEXTURE_CUBE_MAP); + + const ImageDesc &baseImageDesc = + getImageDesc(FirstCubeMapTextureTarget, getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) + { return false; - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: + } + + for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++) + { + const ImageDesc &faceImageDesc = getImageDesc(face, getEffectiveBaseLevel()); + if (faceImageDesc.size.width != baseImageDesc.size.width || + faceImageDesc.size.height != baseImageDesc.size.height || + !Format::SameSized(faceImageDesc.format, baseImageDesc.format)) + { + return false; + } + } + + return true; +} + +bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState, + const ContextState &data) const +{ + if (mBaseLevel > mMaxLevel) + { + return false; + } + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || + baseImageDesc.size.depth == 0) + { + return false; + } + // The cases where the texture is incomplete because base level is out of range should be + // handled by the above condition. + ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat); + + if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is + // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter + // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture, + // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as + // incomplete texture. So, we ignore filtering for multisample texture completeness here. + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && + !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) && + !IsPointSampled(samplerState)) + { + return false; + } + bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3; + if (!npotSupport) + { + if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.width)) || + (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.height))) + { + return false; + } + } + + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && IsMipmapFiltered(samplerState)) + { + if (!npotSupport) + { + if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height)) + { + return false; + } + } + + if (!computeMipmapCompleteness()) + { + return false; + } + } + else + { + if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) + { + return false; + } + } + + // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a + // texture unit that would have been rejected by a call to TexParameter* for the texture bound + // to that unit, the behavior of the implementation is as if the texture were incomplete. For + // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the + // sampler object bound to a texture unit and the texture bound to that unit is an external + // texture, the texture will be considered incomplete. + // Sampler object state which does not affect sampling for the type of texture bound to a + // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness. + if (mTarget == GL_TEXTURE_EXTERNAL_OES) + { + if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE) + { + return false; + } + + if (samplerState.minFilter != GL_LINEAR && samplerState.minFilter != GL_NEAREST) + { + return false; + } + } + + // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: + // The internalformat specified for the texture arrays is a sized internal depth or + // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- + // MODE is NONE, and either the magnification filter is not NEAREST or the mini- + // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. + if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && baseImageDesc.format.info->depthBits > 0 && + data.getClientMajorVersion() >= 3) + { + // Note: we restrict this validation to sized types. For the OES_depth_textures + // extension, due to some underspecification problems, we must allow linear filtering + // for legacy compatibility with WebGL 1. + // See http://crbug.com/649200 + if (samplerState.compareMode == GL_NONE && baseImageDesc.format.info->sized) + { + if ((samplerState.minFilter != GL_NEAREST && + samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || + samplerState.magFilter != GL_NEAREST) + { + return false; + } + } + } + + return true; +} + +bool TextureState::computeMipmapCompleteness() const +{ + const GLuint maxLevel = getMipmapMaxLevel(); + + for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++) + { + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + if (!computeLevelCompleteness(face, level)) + { + return false; + } + } + } + else + { + if (!computeLevelCompleteness(mTarget, level)) + { + return false; + } + } + } + + return true; +} + +bool TextureState::computeLevelCompleteness(GLenum target, size_t level) const +{ + ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (mImmutableFormat) + { return true; - default: UNREACHABLE(); + } + + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || + baseImageDesc.size.depth == 0) + { + return false; + } + + const ImageDesc &levelImageDesc = getImageDesc(target, level); + if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 || + levelImageDesc.size.depth == 0) + { return false; } + + if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format)) + { + return false; + } + + ASSERT(level >= getEffectiveBaseLevel()); + const size_t relativeLevel = level - getEffectiveBaseLevel(); + if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) + { + return false; + } + + 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 >> relativeLevel)) + { + return false; + } + } + else if (mTarget == GL_TEXTURE_2D_ARRAY) + { + if (levelImageDesc.size.depth != baseImageDesc.size.depth) + { + return false; + } + } + + return true; +} + +GLenum TextureState::getBaseImageTarget() const +{ + return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; +} + +ImageDesc::ImageDesc() + : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized) +{ +} + +ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState) + : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState) +{ } -bool IsPointSampled(const gl::SamplerState &samplerState) +ImageDesc::ImageDesc(const Extents &size, + const Format &format, + const GLsizei samples, + const bool fixedSampleLocations, + const InitState initState) + : size(size), + format(format), + samples(samples), + fixedSampleLocations(fixedSampleLocations), + initState(initState) { - return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); } -static size_t GetImageDescIndex(GLenum target, size_t level) +const ImageDesc &TextureState::getImageDesc(GLenum target, size_t level) const { - return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level; + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + return mImageDescs[descIndex]; } -Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) +void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + mImageDescs[descIndex] = desc; + if (desc.initState == InitState::MayNeedInit) + { + mInitState = InitState::MayNeedInit; + } +} + +const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const +{ + return getImageDesc(imageIndex.type, imageIndex.mipIndex); +} + +void TextureState::setImageDescChain(GLuint baseLevel, + GLuint maxLevel, + Extents baseSize, + const Format &format, + InitState initState) +{ + for (GLuint level = baseLevel; level <= maxLevel; level++) + { + int relativeLevel = (level - baseLevel); + Extents levelSize(std::max(baseSize.width >> relativeLevel, 1), + std::max(baseSize.height >> relativeLevel, 1), + (mTarget == GL_TEXTURE_2D_ARRAY) + ? baseSize.depth + : std::max(baseSize.depth >> relativeLevel, 1)); + ImageDesc levelInfo(levelSize, format, initState); + + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + setImageDesc(face, level, levelInfo); + } + } + else + { + setImageDesc(mTarget, level, levelInfo); + } + } +} + +void TextureState::setImageDescChainMultisample(Extents baseSize, + const Format &format, + GLsizei samples, + bool fixedSampleLocations, + InitState initState) +{ + ASSERT(mTarget == GL_TEXTURE_2D_MULTISAMPLE); + ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState); + setImageDesc(mTarget, 0, levelInfo); +} + +void TextureState::clearImageDesc(GLenum target, size_t level) +{ + setImageDesc(target, level, ImageDesc()); +} + +void TextureState::clearImageDescs() +{ + for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + { + mImageDescs[descIndex] = ImageDesc(); + } +} + +Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target) : egl::ImageSibling(id), - mTexture(impl), + mState(target), + mTexture(factory->createTexture(mState)), mLabel(), - mTextureState(), - mTarget(target), - mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), - mCompletenessCache(), - mBoundSurface(NULL) + mBoundSurface(nullptr), + mBoundStream(nullptr) { } -Texture::~Texture() +Error Texture::onDestroy(const Context *context) { if (mBoundSurface) { - mBoundSurface->releaseTexImage(EGL_BACK_BUFFER); - mBoundSurface = NULL; + ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER)); + mBoundSurface = nullptr; + } + if (mBoundStream) + { + mBoundStream->releaseTextures(); + mBoundStream = nullptr; + } + + ANGLE_TRY(orphanImages(context)); + + if (mTexture) + { + ANGLE_TRY(mTexture->onDestroy(context)); } + return NoError(); +} + +Texture::~Texture() +{ SafeDelete(mTexture); } void Texture::setLabel(const std::string &label) { mLabel = label; + mDirtyBits.set(DIRTY_BIT_LABEL); } const std::string &Texture::getLabel() const @@ -81,295 +586,323 @@ const std::string &Texture::getLabel() const GLenum Texture::getTarget() const { - return mTarget; + return mState.mTarget; } void Texture::setSwizzleRed(GLenum swizzleRed) { - mTextureState.swizzleRed = swizzleRed; + mState.mSwizzleState.swizzleRed = swizzleRed; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_RED); } GLenum Texture::getSwizzleRed() const { - return mTextureState.swizzleRed; + return mState.mSwizzleState.swizzleRed; } void Texture::setSwizzleGreen(GLenum swizzleGreen) { - mTextureState.swizzleGreen = swizzleGreen; + mState.mSwizzleState.swizzleGreen = swizzleGreen; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_GREEN); } GLenum Texture::getSwizzleGreen() const { - return mTextureState.swizzleGreen; + return mState.mSwizzleState.swizzleGreen; } void Texture::setSwizzleBlue(GLenum swizzleBlue) { - mTextureState.swizzleBlue = swizzleBlue; + mState.mSwizzleState.swizzleBlue = swizzleBlue; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_BLUE); } GLenum Texture::getSwizzleBlue() const { - return mTextureState.swizzleBlue; + return mState.mSwizzleState.swizzleBlue; } void Texture::setSwizzleAlpha(GLenum swizzleAlpha) { - mTextureState.swizzleAlpha = swizzleAlpha; + mState.mSwizzleState.swizzleAlpha = swizzleAlpha; + mDirtyBits.set(DIRTY_BIT_SWIZZLE_ALPHA); } GLenum Texture::getSwizzleAlpha() const { - return mTextureState.swizzleAlpha; + return mState.mSwizzleState.swizzleAlpha; } void Texture::setMinFilter(GLenum minFilter) { - mTextureState.samplerState.minFilter = minFilter; + mState.mSamplerState.minFilter = minFilter; + mDirtyBits.set(DIRTY_BIT_MIN_FILTER); } GLenum Texture::getMinFilter() const { - return mTextureState.samplerState.minFilter; + return mState.mSamplerState.minFilter; } void Texture::setMagFilter(GLenum magFilter) { - mTextureState.samplerState.magFilter = magFilter; + mState.mSamplerState.magFilter = magFilter; + mDirtyBits.set(DIRTY_BIT_MAG_FILTER); } GLenum Texture::getMagFilter() const { - return mTextureState.samplerState.magFilter; + return mState.mSamplerState.magFilter; } void Texture::setWrapS(GLenum wrapS) { - mTextureState.samplerState.wrapS = wrapS; + mState.mSamplerState.wrapS = wrapS; + mDirtyBits.set(DIRTY_BIT_WRAP_S); } GLenum Texture::getWrapS() const { - return mTextureState.samplerState.wrapS; + return mState.mSamplerState.wrapS; } void Texture::setWrapT(GLenum wrapT) { - mTextureState.samplerState.wrapT = wrapT; + mState.mSamplerState.wrapT = wrapT; + mDirtyBits.set(DIRTY_BIT_WRAP_T); } GLenum Texture::getWrapT() const { - return mTextureState.samplerState.wrapT; + return mState.mSamplerState.wrapT; } void Texture::setWrapR(GLenum wrapR) { - mTextureState.samplerState.wrapR = wrapR; + mState.mSamplerState.wrapR = wrapR; + mDirtyBits.set(DIRTY_BIT_WRAP_R); } GLenum Texture::getWrapR() const { - return mTextureState.samplerState.wrapR; + return mState.mSamplerState.wrapR; } void Texture::setMaxAnisotropy(float maxAnisotropy) { - mTextureState.samplerState.maxAnisotropy = maxAnisotropy; + mState.mSamplerState.maxAnisotropy = maxAnisotropy; + mDirtyBits.set(DIRTY_BIT_MAX_ANISOTROPY); } float Texture::getMaxAnisotropy() const { - return mTextureState.samplerState.maxAnisotropy; + return mState.mSamplerState.maxAnisotropy; } void Texture::setMinLod(GLfloat minLod) { - mTextureState.samplerState.minLod = minLod; + mState.mSamplerState.minLod = minLod; + mDirtyBits.set(DIRTY_BIT_MIN_LOD); } GLfloat Texture::getMinLod() const { - return mTextureState.samplerState.minLod; + return mState.mSamplerState.minLod; } void Texture::setMaxLod(GLfloat maxLod) { - mTextureState.samplerState.maxLod = maxLod; + mState.mSamplerState.maxLod = maxLod; + mDirtyBits.set(DIRTY_BIT_MAX_LOD); } GLfloat Texture::getMaxLod() const { - return mTextureState.samplerState.maxLod; + return mState.mSamplerState.maxLod; } void Texture::setCompareMode(GLenum compareMode) { - mTextureState.samplerState.compareMode = compareMode; + mState.mSamplerState.compareMode = compareMode; + mDirtyBits.set(DIRTY_BIT_COMPARE_MODE); } GLenum Texture::getCompareMode() const { - return mTextureState.samplerState.compareMode; + return mState.mSamplerState.compareMode; } void Texture::setCompareFunc(GLenum compareFunc) { - mTextureState.samplerState.compareFunc = compareFunc; + mState.mSamplerState.compareFunc = compareFunc; + mDirtyBits.set(DIRTY_BIT_COMPARE_FUNC); } GLenum Texture::getCompareFunc() const { - return mTextureState.samplerState.compareFunc; + return mState.mSamplerState.compareFunc; +} + +void Texture::setSRGBDecode(GLenum sRGBDecode) +{ + mState.mSamplerState.sRGBDecode = sRGBDecode; + mDirtyBits.set(DIRTY_BIT_SRGB_DECODE); +} + +GLenum Texture::getSRGBDecode() const +{ + return mState.mSamplerState.sRGBDecode; } const SamplerState &Texture::getSamplerState() const { - return mTextureState.samplerState; + return mState.mSamplerState; } -void Texture::setBaseLevel(GLuint baseLevel) +Error Texture::setBaseLevel(const Context *context, GLuint baseLevel) { - mTextureState.baseLevel = baseLevel; + if (mState.setBaseLevel(baseLevel)) + { + ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel())); + mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); + invalidateCompletenessCache(); + } + + return NoError(); } GLuint Texture::getBaseLevel() const { - return mTextureState.baseLevel; + return mState.mBaseLevel; } void Texture::setMaxLevel(GLuint maxLevel) { - mTextureState.maxLevel = maxLevel; + if (mState.setMaxLevel(maxLevel)) + { + mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); + invalidateCompletenessCache(); + } } GLuint Texture::getMaxLevel() const { - return mTextureState.maxLevel; + return mState.mMaxLevel; +} + +void Texture::setDepthStencilTextureMode(GLenum mode) +{ + if (mode != mState.mDepthStencilTextureMode) + { + // Changing the mode from the default state (GL_DEPTH_COMPONENT) is not implemented yet + UNIMPLEMENTED(); + } + + // TODO(geofflang): add dirty bits + mState.mDepthStencilTextureMode = mode; +} + +GLenum Texture::getDepthStencilTextureMode() const +{ + return mState.mDepthStencilTextureMode; } bool Texture::getImmutableFormat() const { - return mTextureState.immutableFormat; + return mState.mImmutableFormat; } GLuint Texture::getImmutableLevels() const { - return mTextureState.immutableLevels; + return mState.mImmutableLevels; } void Texture::setUsage(GLenum usage) { - mTextureState.usage = usage; - getImplementation()->setUsage(usage); + mState.mUsage = usage; + mDirtyBits.set(DIRTY_BIT_USAGE); } GLenum Texture::getUsage() const { - return mTextureState.usage; + return mState.mUsage; } const TextureState &Texture::getTextureState() const { - return mTextureState; + return mState; } size_t Texture::getWidth(GLenum target, size_t level) const { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - return getImageDesc(target, level).size.width; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).size.width; } size_t Texture::getHeight(GLenum target, size_t level) const { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - return getImageDesc(target, level).size.height; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).size.height; } size_t Texture::getDepth(GLenum target, size_t level) const { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - return getImageDesc(target, level).size.depth; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).size.depth; } -GLenum Texture::getInternalFormat(GLenum target, size_t level) const +const Format &Texture::getFormat(GLenum target, size_t level) const { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - return getImageDesc(target, level).internalFormat; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).format; } -bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const +GLsizei Texture::getSamples(GLenum target, size_t level) const { - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); - const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); - if (!mCompletenessCache.cacheValid || - mCompletenessCache.samplerState != samplerState || - mCompletenessCache.filterable != textureCaps.filterable || - mCompletenessCache.clientVersion != data.clientVersion || - mCompletenessCache.supportsNPOT != data.extensions->textureNPOT) - { - mCompletenessCache.cacheValid = true; - mCompletenessCache.samplerState = samplerState; - mCompletenessCache.filterable = textureCaps.filterable; - mCompletenessCache.clientVersion = data.clientVersion; - mCompletenessCache.supportsNPOT = data.extensions->textureNPOT; - mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data); - } - return mCompletenessCache.samplerComplete; + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).samples; } -bool Texture::isMipmapComplete() const +bool Texture::getFixedSampleLocations(GLenum target, size_t level) const { - return computeMipmapCompleteness(); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return mState.getImageDesc(target, level).fixedSampleLocations; } -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture::isCubeComplete() const +GLuint Texture::getMipmapMaxLevel() const { - ASSERT(mTarget == GL_TEXTURE_CUBE_MAP); - - const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0); - if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) - { - return false; - } + return mState.getMipmapMaxLevel(); +} - for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++) - { - const ImageDesc &faceImageDesc = getImageDesc(face, 0); - if (faceImageDesc.size.width != baseImageDesc.size.width || - faceImageDesc.size.height != baseImageDesc.size.height || - faceImageDesc.internalFormat != baseImageDesc.internalFormat) - { - return false; - } - } +bool Texture::isMipmapComplete() const +{ + return mState.computeMipmapCompleteness(); +} - return true; +egl::Surface *Texture::getBoundSurface() const +{ + return mBoundSurface; } -size_t Texture::getMipCompleteLevels() const +egl::Stream *Texture::getBoundStream() const { - 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; - } + return mBoundStream; } -egl::Surface *Texture::getBoundSurface() const +void Texture::signalDirty(InitState initState) const { - return mBoundSurface; + mDirtyChannel.signal(initState); + invalidateCompletenessCache(); } -Error Texture::setImage(Context *context, +Error Texture::setImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -378,33 +911,25 @@ Error Texture::setImage(Context *context, GLenum type, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); - - // Hack: allow nullptr for testing - if (context != nullptr) - { - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); - } + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - 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; - } + ANGLE_TRY(mTexture->setImage(context, target, level, internalFormat, size, format, type, + unpackState, pixels)); - setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); + InitState initState = DetermineInitState(context, pixels); + mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState)); + signalDirty(initState); - return Error(GL_NO_ERROR); + return NoError(); } -Error Texture::setSubImage(Context *context, +Error Texture::setSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -412,16 +937,16 @@ Error Texture::setSubImage(Context *context, GLenum type, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, area)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - return mTexture->setSubImage(target, level, area, format, type, unpack, pixels); + return mTexture->setSubImage(context, target, level, area, format, type, unpackState, pixels); } -Error Texture::setCompressedImage(Context *context, +Error Texture::setCompressedImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -429,28 +954,25 @@ Error Texture::setCompressedImage(Context *context, size_t imageSize, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); - - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->setCompressedImage(context, target, level, internalFormat, size, + unpackState, imageSize, pixels)); - setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + InitState initState = DetermineInitState(context, pixels); + mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState)); + signalDirty(initState); - return Error(GL_NO_ERROR); + return NoError(); } -Error Texture::setCompressedSubImage(Context *context, +Error Texture::setCompressedSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -458,428 +980,505 @@ Error Texture::setCompressedSubImage(Context *context, size_t imageSize, const uint8_t *pixels) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // Sync the unpack state - context->syncRendererState(context->getState().unpackStateBitMask()); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, area)); - const PixelUnpackState &unpack = context->getState().getUnpackState(); - return mTexture->setCompressedSubImage(target, level, area, format, unpack, imageSize, pixels); + return mTexture->setCompressedSubImage(context, target, level, area, format, unpackState, + imageSize, pixels); } -Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, - const Framebuffer *source) +Error Texture::copyImage(const Context *context, + GLenum target, + size_t level, + const Rectangle &sourceArea, + GLenum internalFormat, + Framebuffer *source) { - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); - if (error.isError()) - { - return error; - } + // Ensure source FBO is initialized. + ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); - setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), - GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + // Use the source FBO size as the init image area. + Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); - return Error(GL_NO_ERROR); -} + ANGLE_TRY(mTexture->copyImage(context, target, level, sourceArea, internalFormat, source)); -Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, - const Framebuffer *source) -{ - ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + const InternalFormat &internalFormatInfo = + GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); + + mState.setImageDesc(target, level, + ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), + Format(internalFormatInfo), InitState::Initialized)); + + // We need to initialize this texture only if the source attachment is not initialized. + signalDirty(InitState::Initialized); - return mTexture->copySubImage(target, level, destOffset, sourceArea, source); + return NoError(); } -Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size) +Error Texture::copySubImage(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + const Rectangle &sourceArea, + Framebuffer *source) { - ASSERT(target == mTarget); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - // 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; - } + // Ensure source FBO is initialized. + ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT)); - mTextureState.immutableFormat = true; - mTextureState.immutableLevels = static_cast(levels); - clearImageDescs(); - setImageDescChain(levels, size, internalFormat); + Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); - return Error(GL_NO_ERROR); + return mTexture->copySubImage(context, target, level, destOffset, sourceArea, source); } -Error Texture::generateMipmaps() +Error Texture::copyTexture(const Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source) { + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture - // is not mip complete. - if (!isMipmapComplete()) - { - orphanImages(); - } + // Initialize source texture. + // Note: we don't have a way to notify which portions of the image changed currently. + ANGLE_TRY(source->ensureInitialized(context)); - Error error = mTexture->generateMipmaps(mTextureState); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->copyTexture(context, target, level, internalFormat, type, sourceLevel, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, + source)); + + const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0); + const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type); + mState.setImageDesc( + target, level, + ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized)); - 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); + signalDirty(InitState::Initialized); - return Error(GL_NO_ERROR); + return NoError(); } -void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat) +Error Texture::copySubTexture(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + size_t sourceLevel, + const Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source) { - 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)); - ImageDesc levelInfo(levelSize, sizedInternalFormat); + ASSERT(target == mState.mTarget || + (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); - if (mTarget == GL_TEXTURE_CUBE_MAP) - { - for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) - { - setImageDesc(face, level, levelInfo); - } - } - else - { - setImageDesc(mTarget, level, levelInfo); - } - } -} + // Ensure source is initialized. + ANGLE_TRY(source->ensureInitialized(context)); -Texture::ImageDesc::ImageDesc() - : ImageDesc(Extents(0, 0, 0), GL_NONE) -{ -} + Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox)); -Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat) - : size(size), - internalFormat(internalFormat) -{ + return mTexture->copySubTexture(context, target, level, destOffset, sourceLevel, sourceArea, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, + source); } -const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const +Error Texture::copyCompressedTexture(const Context *context, const Texture *source) { - size_t descIndex = GetImageDescIndex(target, level); - ASSERT(descIndex < mImageDescs.size()); - return mImageDescs[descIndex]; + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->copyCompressedTexture(context, source)); + + ASSERT(source->getTarget() != GL_TEXTURE_CUBE_MAP && getTarget() != GL_TEXTURE_CUBE_MAP); + const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0); + mState.setImageDesc(getTarget(), 0, sourceDesc); + + return NoError(); } -void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +Error Texture::setStorage(const Context *context, + GLenum target, + GLsizei levels, + GLenum internalFormat, + const Extents &size) { - size_t descIndex = GetImageDescIndex(target, level); - ASSERT(descIndex < mImageDescs.size()); - mImageDescs[descIndex] = desc; - mCompletenessCache.cacheValid = false; + ASSERT(target == mState.mTarget); + + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->setStorage(context, target, levels, internalFormat, size)); + + mState.mImmutableFormat = true; + mState.mImmutableLevels = static_cast(levels); + mState.clearImageDescs(); + mState.setImageDescChain(0, static_cast(levels - 1), size, Format(internalFormat), + InitState::MayNeedInit); + + // Changing the texture to immutable can trigger a change in the base and max levels: + // GLES 3.0.4 section 3.8.10 pg 158: + // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then + // clamped to the range[levelbase;levels]. + mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); + mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); + + signalDirty(InitState::MayNeedInit); + + return NoError(); } -void Texture::clearImageDesc(GLenum target, size_t level) +Error Texture::setStorageMultisample(const Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const Extents &size, + bool fixedSampleLocations) { - setImageDesc(target, level, ImageDesc()); + ASSERT(target == mState.mTarget); + + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); + + ANGLE_TRY(mTexture->setStorageMultisample(context, target, samples, internalFormat, size, + fixedSampleLocations)); + + mState.mImmutableFormat = true; + mState.mImmutableLevels = static_cast(1); + mState.clearImageDescs(); + mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations, + InitState::MayNeedInit); + + signalDirty(InitState::MayNeedInit); + + return NoError(); } -void Texture::clearImageDescs() +Error Texture::generateMipmap(const Context *context) { - for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + // Release from previous calls to eglBindTexImage, to avoid calling the Impl after + ANGLE_TRY(releaseTexImageInternal(context)); + + // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture + // is not mip complete. + if (!isMipmapComplete()) { - mImageDescs[descIndex] = ImageDesc(); + ANGLE_TRY(orphanImages(context)); + } + + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + + if (maxLevel > baseLevel) + { + syncState(); + const ImageDesc &baseImageInfo = + mState.getImageDesc(mState.getBaseImageTarget(), baseLevel); + + // Clear the base image immediately if necessary. + if (context->isRobustResourceInitEnabled() && + baseImageInfo.initState == InitState::MayNeedInit) + { + ANGLE_TRY(initializeContents( + context, GetImageIndexFromDescIndex(mState.getBaseImageTarget(), baseLevel))); + } + + ANGLE_TRY(mTexture->generateMipmap(context)); + + mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format, + InitState::Initialized); } - mCompletenessCache.cacheValid = false; + + signalDirty(InitState::Initialized); + + return NoError(); } -void Texture::bindTexImageFromSurface(egl::Surface *surface) +Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *surface) { ASSERT(surface); if (mBoundSurface) { - releaseTexImageFromSurface(); + ANGLE_TRY(releaseTexImageFromSurface(context)); } - mTexture->bindTexImage(surface); + ANGLE_TRY(mTexture->bindTexImage(context, surface)); mBoundSurface = surface; // Set the image info to the size and format of the surface - ASSERT(mTarget == GL_TEXTURE_2D); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); Extents size(surface->getWidth(), surface->getHeight(), 1); - ImageDesc desc(size, surface->getConfig()->renderTargetFormat); - setImageDesc(mTarget, 0, desc); + ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat), InitState::Initialized); + mState.setImageDesc(mState.mTarget, 0, desc); + signalDirty(InitState::Initialized); + return NoError(); } -void Texture::releaseTexImageFromSurface() +Error Texture::releaseTexImageFromSurface(const Context *context) { ASSERT(mBoundSurface); mBoundSurface = nullptr; - mTexture->releaseTexImage(); + ANGLE_TRY(mTexture->releaseTexImage(context)); // Erase the image info for level 0 - ASSERT(mTarget == GL_TEXTURE_2D); - clearImageDesc(mTarget, 0); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); + mState.clearImageDesc(mState.mTarget, 0); + signalDirty(InitState::Initialized); + return NoError(); +} + +void Texture::bindStream(egl::Stream *stream) +{ + ASSERT(stream); + + // It should not be possible to bind a texture already bound to another stream + ASSERT(mBoundStream == nullptr); + + mBoundStream = stream; + + ASSERT(mState.mTarget == GL_TEXTURE_EXTERNAL_OES); +} + +void Texture::releaseStream() +{ + ASSERT(mBoundStream); + mBoundStream = nullptr; +} + +Error Texture::acquireImageFromStream(const Context *context, + const egl::Stream::GLTextureDescription &desc) +{ + ASSERT(mBoundStream != nullptr); + ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, mBoundStream, desc)); + + Extents size(desc.width, desc.height, 1); + mState.setImageDesc(mState.mTarget, 0, + ImageDesc(size, Format(desc.internalFormat), InitState::Initialized)); + signalDirty(InitState::Initialized); + return NoError(); +} + +Error Texture::releaseImageFromStream(const Context *context) +{ + ASSERT(mBoundStream != nullptr); + ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, nullptr, + egl::Stream::GLTextureDescription())); + + // Set to incomplete + mState.clearImageDesc(mState.mTarget, 0); + signalDirty(InitState::Initialized); + return NoError(); } -void Texture::releaseTexImageInternal() +Error Texture::releaseTexImageInternal(const Context *context) { if (mBoundSurface) { // Notify the surface - mBoundSurface->releaseTexImageFromTexture(); + mBoundSurface->releaseTexImageFromTexture(context); // Then, call the same method as from the surface - releaseTexImageFromSurface(); + ANGLE_TRY(releaseTexImageFromSurface(context)); } + return NoError(); } -Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget) +Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget) { - ASSERT(target == mTarget); - ASSERT(target == GL_TEXTURE_2D); + ASSERT(target == mState.mTarget); + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after - releaseTexImageInternal(); - orphanImages(); + ANGLE_TRY(releaseTexImageInternal(context)); + ANGLE_TRY(orphanImages(context)); - Error error = mTexture->setEGLImageTarget(target, imageTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexture->setEGLImageTarget(context, target, imageTarget)); - setTargetImage(imageTarget); + setTargetImage(context, 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))); + auto initState = imageTarget->sourceInitState(); - return Error(GL_NO_ERROR); + mState.clearImageDescs(); + mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState)); + signalDirty(initState); + + return NoError(); } -GLenum Texture::getBaseImageTarget() const +Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const { - return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; + return mState.getImageDesc(imageIndex).size; } -bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const +const Format &Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const { - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); - if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) - { - return false; - } - - if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) - { - return false; - } - - const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); - if (!textureCaps.filterable && !IsPointSampled(samplerState)) - { - return false; - } - - bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3; - if (!npotSupport) - { - if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) || - (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height))) - { - return false; - } - } - - if (IsMipmapFiltered(samplerState)) - { - if (!npotSupport) - { - if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height)) - { - return false; - } - } - - if (!computeMipmapCompleteness()) - { - return false; - } - } - else - { - if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) - { - return false; - } - } + return mState.getImageDesc(imageIndex).format; +} - // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: - // The internalformat specified for the texture arrays is a sized internal depth or - // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- - // MODE is NONE, and either the magnification filter is not NEAREST or the mini- - // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat); - if (formatInfo.depthBits > 0 && data.clientVersion > 2) - { - if (samplerState.compareMode == GL_NONE) - { - if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || - samplerState.magFilter != GL_NEAREST) - { - return false; - } - } - } +GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const +{ + return getSamples(imageIndex.type, 0); +} - return true; +void Texture::onAttach(const Context *context) +{ + addRef(); } -bool Texture::computeMipmapCompleteness() const +void Texture::onDetach(const Context *context) { - size_t expectedMipLevels = getMipCompleteLevels(); + release(context); +} - size_t maxLevel = std::min(expectedMipLevels, mTextureState.maxLevel + 1); +GLuint Texture::getId() const +{ + return id(); +} - 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)) - { - return false; - } - } - } - else - { - if (!computeLevelCompleteness(mTarget, level)) - { - return false; - } - } - } +void Texture::syncState() +{ + mTexture->syncState(mDirtyBits); + mDirtyBits.reset(); +} - return true; +rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const +{ + return mTexture; } -bool Texture::computeLevelCompleteness(GLenum target, size_t level) const +bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler) { - ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + const auto &samplerState = + optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState; + const auto &contextState = context->getContextState(); - if (mTextureState.immutableFormat) + if (contextState.getContextID() != mCompletenessCache.context || + mCompletenessCache.samplerState != samplerState) { - return true; + mCompletenessCache.context = context->getContextState().getContextID(); + mCompletenessCache.samplerState = samplerState; + mCompletenessCache.samplerComplete = + mState.computeSamplerCompleteness(samplerState, contextState); } - const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), mTextureState.baseLevel); - if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) - { - return false; - } + return mCompletenessCache.samplerComplete; +} - const ImageDesc &levelImageDesc = getImageDesc(target, level); - if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 || - levelImageDesc.size.depth == 0) - { - return false; - } +Texture::SamplerCompletenessCache::SamplerCompletenessCache() + : context(0), samplerState(), samplerComplete(false) +{ +} - if (levelImageDesc.internalFormat != baseImageDesc.internalFormat) - { - return false; - } +void Texture::invalidateCompletenessCache() const +{ + mCompletenessCache.context = 0; +} - ASSERT(level >= mTextureState.baseLevel); - const size_t relativeLevel = level - mTextureState.baseLevel; - if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel)) +Error Texture::ensureInitialized(const Context *context) +{ + if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) { - return false; + return NoError(); } - if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel)) - { - return false; - } + bool anyDirty = false; - if (mTarget == GL_TEXTURE_3D) + for (size_t descIndex = 0; descIndex < mState.mImageDescs.size(); ++descIndex) { - if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel)) + auto &imageDesc = mState.mImageDescs[descIndex]; + if (imageDesc.initState == InitState::MayNeedInit) { - return false; + ASSERT(mState.mInitState == InitState::MayNeedInit); + const auto &imageIndex = GetImageIndexFromDescIndex(mState.mTarget, descIndex); + ANGLE_TRY(initializeContents(context, imageIndex)); + imageDesc.initState = InitState::Initialized; + anyDirty = true; } } - else if (mTarget == GL_TEXTURE_2D_ARRAY) + if (anyDirty) { - if (levelImageDesc.size.depth != baseImageDesc.size.depth) - { - return false; - } + signalDirty(InitState::Initialized); } + mState.mInitState = InitState::Initialized; - return true; + return NoError(); } -Texture::SamplerCompletenessCache::SamplerCompletenessCache() - : cacheValid(false), - samplerState(), - filterable(false), - clientVersion(0), - supportsNPOT(false), - samplerComplete(false) +InitState Texture::initState(const ImageIndex &imageIndex) const { + return mState.getImageDesc(imageIndex).initState; } -Extents Texture::getAttachmentSize(const gl::FramebufferAttachment::Target &target) const +InitState Texture::initState() const { - return getImageDesc(target.textureIndex().type, target.textureIndex().mipIndex).size; + return mState.mInitState; } -GLenum Texture::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const +void Texture::setInitState(const ImageIndex &imageIndex, InitState initState) { - return getInternalFormat(target.textureIndex().type, target.textureIndex().mipIndex); + ImageDesc newDesc = mState.getImageDesc(imageIndex); + newDesc.initState = initState; + mState.setImageDesc(imageIndex.type, imageIndex.mipIndex, newDesc); } -GLsizei Texture::getAttachmentSamples(const gl::FramebufferAttachment::Target &/*target*/) const +Error Texture::ensureSubImageInitialized(const Context *context, + GLenum target, + size_t level, + const gl::Box &area) { - // Multisample textures not currently supported - return 0; -} + if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized) + { + return NoError(); + } -void Texture::onAttach() -{ - addRef(); -} + // Pre-initialize the texture contents if necessary. + // TODO(jmadill): Check if area overlaps the entire texture. + const auto &imageIndex = GetImageIndexFromDescIndex(target, level); + const auto &desc = mState.getImageDesc(imageIndex); + if (desc.initState == InitState::MayNeedInit) + { + ASSERT(mState.mInitState == InitState::MayNeedInit); + bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 && + area.width == desc.size.width && area.height == desc.size.height && + area.depth == desc.size.depth; + if (!coversWholeImage) + { + ANGLE_TRY(initializeContents(context, imageIndex)); + } + setInitState(imageIndex, InitState::Initialized); + } -void Texture::onDetach() -{ - release(); + return NoError(); } -GLuint Texture::getId() const -{ - return id(); -} -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Texture.h b/src/3rdparty/angle/src/libANGLE/Texture.h index 7ca8a456fc..7525da2b2f 100644 --- a/src/3rdparty/angle/src/libANGLE/Texture.h +++ b/src/3rdparty/angle/src/libANGLE/Texture.h @@ -13,37 +13,169 @@ #include #include "angle_gl.h" +#include "common/Optional.h" #include "common/debug.h" #include "libANGLE/Caps.h" -#include "libANGLE/Debug.h" #include "libANGLE/Constants.h" +#include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Image.h" +#include "libANGLE/Stream.h" #include "libANGLE/angletypes.h" -#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/formatutils.h" namespace egl { class Surface; +class Stream; +} + +namespace rx +{ +class GLImplFactory; +class TextureImpl; +class TextureGL; } namespace gl { -class Context; +class ContextState; class Framebuffer; -struct Data; +class Sampler; +class Texture; bool IsMipmapFiltered(const SamplerState &samplerState); +struct ImageDesc final +{ + ImageDesc(); + ImageDesc(const Extents &size, const Format &format, const InitState initState); + ImageDesc(const Extents &size, + const Format &format, + const GLsizei samples, + const bool fixedSampleLocations, + const InitState initState); + + ImageDesc(const ImageDesc &other) = default; + ImageDesc &operator=(const ImageDesc &other) = default; + + Extents size; + Format format; + GLsizei samples; + bool fixedSampleLocations; + + // Needed for robust resource initialization. + InitState initState; +}; + +struct SwizzleState final +{ + SwizzleState(); + SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha); + SwizzleState(const SwizzleState &other) = default; + SwizzleState &operator=(const SwizzleState &other) = default; + + bool swizzleRequired() const; + + bool operator==(const SwizzleState &other) const; + bool operator!=(const SwizzleState &other) const; + + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; +}; + +// State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec. +struct TextureState final : private angle::NonCopyable +{ + TextureState(GLenum target); + ~TextureState(); + + bool swizzleRequired() const; + GLuint getEffectiveBaseLevel() const; + GLuint getEffectiveMaxLevel() const; + + // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10. + GLuint getMipmapMaxLevel() const; + + // Returns true if base level changed. + bool setBaseLevel(GLuint baseLevel); + bool setMaxLevel(GLuint maxLevel); + + bool isCubeComplete() const; + + const ImageDesc &getImageDesc(GLenum target, size_t level) const; + const ImageDesc &getImageDesc(const ImageIndex &imageIndex) const; + + GLenum getTarget() const { return mTarget; } + const SwizzleState &getSwizzleState() const { return mSwizzleState; } + const SamplerState &getSamplerState() const { return mSamplerState; } + GLenum getUsage() const { return mUsage; } + + private: + // Texture needs access to the ImageDesc functions. + friend class Texture; + // TODO(jmadill): Remove TextureGL from friends. + friend class rx::TextureGL; + friend bool operator==(const TextureState &a, const TextureState &b); + + bool computeSamplerCompleteness(const SamplerState &samplerState, + const ContextState &data) const; + bool computeMipmapCompleteness() const; + bool computeLevelCompleteness(GLenum target, size_t level) const; + + GLenum getBaseImageTarget() const; + + void setImageDesc(GLenum target, size_t level, const ImageDesc &desc); + void setImageDescChain(GLuint baselevel, + GLuint maxLevel, + Extents baseSize, + const Format &format, + InitState initState); + void setImageDescChainMultisample(Extents baseSize, + const Format &format, + GLsizei samples, + bool fixedSampleLocations, + InitState initState); + + void clearImageDesc(GLenum target, size_t level); + void clearImageDescs(); + + const GLenum mTarget; + + SwizzleState mSwizzleState; + + SamplerState mSamplerState; + + GLuint mBaseLevel; + GLuint mMaxLevel; + + GLenum mDepthStencilTextureMode; + + bool mImmutableFormat; + GLuint mImmutableLevels; + + // From GL_ANGLE_texture_usage + GLenum mUsage; + + std::vector mImageDescs; + InitState mInitState; +}; + +bool operator==(const TextureState &a, const TextureState &b); +bool operator!=(const TextureState &a, const TextureState &b); + class Texture final : public egl::ImageSibling, - public FramebufferAttachmentObject, public LabeledObject { public: - Texture(rx::TextureImpl *impl, GLuint id, GLenum target); + Texture(rx::GLImplFactory *factory, GLuint id, GLenum target); ~Texture() override; + Error onDestroy(const Context *context) override; + void setLabel(const std::string &label) override; const std::string &getLabel() const override; @@ -91,14 +223,20 @@ class Texture final : public egl::ImageSibling, void setCompareFunc(GLenum compareFunc); GLenum getCompareFunc() const; + void setSRGBDecode(GLenum sRGBDecode); + GLenum getSRGBDecode() const; + const SamplerState &getSamplerState() const; - void setBaseLevel(GLuint baseLevel); + gl::Error setBaseLevel(const Context *context, GLuint baseLevel); GLuint getBaseLevel() const; void setMaxLevel(GLuint maxLevel); GLuint getMaxLevel() const; + void setDepthStencilTextureMode(GLenum mode); + GLenum getDepthStencilTextureMode() const; + bool getImmutableFormat() const; GLuint getImmutableLevels() const; @@ -111,14 +249,17 @@ class Texture final : public egl::ImageSibling, 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; + GLsizei getSamples(GLenum target, size_t level) const; + bool getFixedSampleLocations(GLenum target, size_t level) const; + const Format &getFormat(GLenum target, size_t level) const; + + // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10. + GLuint getMipmapMaxLevel() const; - bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const; bool isMipmapComplete() const; - bool isCubeComplete() const; - size_t getMipCompleteLevels() const; - Error setImage(Context *context, + Error setImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, @@ -126,7 +267,8 @@ class Texture final : public egl::ImageSibling, GLenum format, GLenum type, const uint8_t *pixels); - Error setSubImage(Context *context, + Error setSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -134,14 +276,16 @@ class Texture final : public egl::ImageSibling, GLenum type, const uint8_t *pixels); - Error setCompressedImage(Context *context, + Error setCompressedImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, GLenum internalFormat, const Extents &size, size_t imageSize, const uint8_t *pixels); - Error setCompressedSubImage(Context *context, + Error setCompressedSubImage(const Context *context, + const PixelUnpackState &unpackState, GLenum target, size_t level, const Box &area, @@ -149,98 +293,179 @@ class Texture final : public egl::ImageSibling, size_t imageSize, const uint8_t *pixels); - Error copyImage(GLenum target, + Error copyImage(const Context *context, + GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, - const Framebuffer *source); - Error copySubImage(GLenum target, + Framebuffer *source); + Error copySubImage(const Context *context, + GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, - const Framebuffer *source); + Framebuffer *source); - Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size); + Error copyTexture(const Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source); + Error copySubTexture(const Context *context, + GLenum target, + size_t level, + const Offset &destOffset, + size_t sourceLevel, + const Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + Texture *source); + Error copyCompressedTexture(const Context *context, const Texture *source); + + Error setStorage(const Context *context, + GLenum target, + GLsizei levels, + GLenum internalFormat, + const Extents &size); + + Error setStorageMultisample(const Context *context, + GLenum target, + GLsizei samples, + GLint internalformat, + const Extents &size, + bool fixedSampleLocations); - Error setEGLImageTarget(GLenum target, egl::Image *imageTarget); + Error setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget); - Error generateMipmaps(); + Error generateMipmap(const Context *context); egl::Surface *getBoundSurface() const; + egl::Stream *getBoundStream() const; - rx::TextureImpl *getImplementation() { return mTexture; } - const rx::TextureImpl *getImplementation() const { return mTexture; } + void signalDirty(InitState initState) const; + + bool isSamplerComplete(const Context *context, const Sampler *optionalSampler); + + rx::TextureImpl *getImplementation() const { return mTexture; } // 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; + Extents getAttachmentSize(const ImageIndex &imageIndex) const override; + const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; + GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; - void onAttach() override; - void onDetach() override; + void onAttach(const Context *context) override; + void onDetach(const Context *context) override; GLuint getId() const override; + // Needed for robust resource init. + Error ensureInitialized(const Context *context); + InitState initState(const ImageIndex &imageIndex) const override; + InitState initState() const; + void setInitState(const ImageIndex &imageIndex, InitState initState) override; + + enum DirtyBitType + { + // Sampler state + DIRTY_BIT_MIN_FILTER, + DIRTY_BIT_MAG_FILTER, + DIRTY_BIT_WRAP_S, + DIRTY_BIT_WRAP_T, + DIRTY_BIT_WRAP_R, + DIRTY_BIT_MAX_ANISOTROPY, + DIRTY_BIT_MIN_LOD, + DIRTY_BIT_MAX_LOD, + DIRTY_BIT_COMPARE_MODE, + DIRTY_BIT_COMPARE_FUNC, + DIRTY_BIT_SRGB_DECODE, + + // Texture state + DIRTY_BIT_SWIZZLE_RED, + DIRTY_BIT_SWIZZLE_GREEN, + DIRTY_BIT_SWIZZLE_BLUE, + DIRTY_BIT_SWIZZLE_ALPHA, + DIRTY_BIT_BASE_LEVEL, + DIRTY_BIT_MAX_LEVEL, + + // Misc + DIRTY_BIT_LABEL, + DIRTY_BIT_USAGE, + + DIRTY_BIT_COUNT, + }; + using DirtyBits = angle::BitSet; + + void syncState(); + bool hasAnyDirtyBit() const { return mDirtyBits.any(); } + private: - rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mTexture; } + rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; // ANGLE-only method, used internally friend class egl::Surface; - void bindTexImageFromSurface(egl::Surface *surface); - void releaseTexImageFromSurface(); - + Error bindTexImageFromSurface(const Context *context, egl::Surface *surface); + Error releaseTexImageFromSurface(const Context *context); + + // ANGLE-only methods, used internally + friend class egl::Stream; + void bindStream(egl::Stream *stream); + void releaseStream(); + Error acquireImageFromStream(const Context *context, + const egl::Stream::GLTextureDescription &desc); + Error releaseImageFromStream(const Context *context); + + void invalidateCompletenessCache() const; + Error releaseTexImageInternal(const Context *context); + + Error ensureSubImageInitialized(const Context *context, + GLenum target, + size_t level, + const gl::Box &area); + + TextureState mState; + DirtyBits mDirtyBits; rx::TextureImpl *mTexture; std::string mLabel; - TextureState mTextureState; - - GLenum mTarget; - - struct ImageDesc - { - Extents size; - GLenum internalFormat; - - ImageDesc(); - ImageDesc(const Extents &size, GLenum internalFormat); - }; - - GLenum getBaseImageTarget() const; - - bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) 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; + egl::Surface *mBoundSurface; + egl::Stream *mBoundStream; struct SamplerCompletenessCache { SamplerCompletenessCache(); - bool cacheValid; + // Context used to generate this cache entry + ContextID context; // All values that affect sampler completeness that are not stored within // the texture itself SamplerState samplerState; - bool filterable; - GLint clientVersion; - bool supportsNPOT; // Result of the sampler completeness with the above parameters bool samplerComplete; }; - mutable SamplerCompletenessCache mCompletenessCache; - egl::Surface *mBoundSurface; + mutable SamplerCompletenessCache mCompletenessCache; }; +inline bool operator==(const TextureState &a, const TextureState &b) +{ + return a.mSwizzleState == b.mSwizzleState && a.mSamplerState == b.mSamplerState && + a.mBaseLevel == b.mBaseLevel && a.mMaxLevel == b.mMaxLevel && + a.mImmutableFormat == b.mImmutableFormat && a.mImmutableLevels == b.mImmutableLevels && + a.mUsage == b.mUsage; +} + +inline bool operator!=(const TextureState &a, const TextureState &b) +{ + return !(a == b); } +} // namespace gl -#endif // LIBANGLE_TEXTURE_H_ +#endif // LIBANGLE_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Thread.cpp b/src/3rdparty/angle/src/libANGLE/Thread.cpp new file mode 100644 index 0000000000..d346db1fa2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Thread.cpp @@ -0,0 +1,91 @@ +// +// Copyright(c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Thread.cpp : Defines the Thread class which represents a global EGL thread. + +#include "libANGLE/Thread.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" + +namespace egl +{ +Thread::Thread() + : mError(EGL_SUCCESS), + mAPI(EGL_OPENGL_ES_API), + mContext(static_cast(EGL_NO_CONTEXT)) +{ +} + +void Thread::setError(const Error &error) +{ + mError = error.getCode(); +} + +EGLint Thread::getError() const +{ + return mError; +} + +void Thread::setAPI(EGLenum api) +{ + mAPI = api; +} + +EGLenum Thread::getAPI() const +{ + return mAPI; +} + +void Thread::setCurrent(gl::Context *context) +{ + mContext = context; +} + +Surface *Thread::getCurrentDrawSurface() const +{ + if (mContext) + { + return mContext->getCurrentDrawSurface(); + } + return nullptr; +} + +Surface *Thread::getCurrentReadSurface() const +{ + if (mContext) + { + return mContext->getCurrentReadSurface(); + } + return nullptr; +} + +gl::Context *Thread::getContext() const +{ + return mContext; +} + +gl::Context *Thread::getValidContext() const +{ + if (mContext && mContext->isContextLost()) + { + mContext->handleError(gl::OutOfMemory() << "Context has been lost."); + return nullptr; + } + + return mContext; +} + +Display *Thread::getCurrentDisplay() const +{ + if (mContext) + { + return mContext->getCurrentDisplay(); + } + return nullptr; +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/Thread.h b/src/3rdparty/angle/src/libANGLE/Thread.h new file mode 100644 index 0000000000..6406dad9e0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Thread.h @@ -0,0 +1,51 @@ +// +// Copyright(c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Thread.h : Defines the Thread class which represents a global EGL thread. + +#ifndef LIBANGLE_THREAD_H_ +#define LIBANGLE_THREAD_H_ + +#include + +namespace gl +{ +class Context; +} // namespace gl + +namespace egl +{ +class Error; +class Display; +class Surface; + +class Thread +{ + public: + Thread(); + + void setError(const Error &error); + EGLint getError() const; + + void setAPI(EGLenum api); + EGLenum getAPI() const; + + void setCurrent(gl::Context *context); + Surface *getCurrentDrawSurface() const; + Surface *getCurrentReadSurface() const; + gl::Context *getContext() const; + gl::Context *getValidContext() const; + Display *getCurrentDisplay() const; + + private: + EGLint mError; + EGLenum mAPI; + gl::Context *mContext; +}; + +} // namespace egl + +#endif // LIBANGLE_THREAD_H_ diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp index b7961971d0..99235debd4 100644 --- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp @@ -8,133 +8,204 @@ #include "libANGLE/Buffer.h" #include "libANGLE/Caps.h" +#include "libANGLE/ContextState.h" +#include "libANGLE/Program.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/TransformFeedbackImpl.h" namespace gl { -TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl *impl, GLuint id, const Caps &caps) - : RefCountObject(id), - mImplementation(impl), - mLabel(), +TransformFeedbackState::TransformFeedbackState(size_t maxIndexedBuffers) + : mLabel(), mActive(false), mPrimitiveMode(GL_NONE), mPaused(false), + mProgram(nullptr), mGenericBuffer(), - mIndexedBuffers(caps.maxTransformFeedbackSeparateAttributes) + mIndexedBuffers(maxIndexedBuffers) { - ASSERT(impl != NULL); } -TransformFeedback::~TransformFeedback() +TransformFeedbackState::~TransformFeedbackState() +{ +} + +const BindingPointer &TransformFeedbackState::getGenericBuffer() const { - mGenericBuffer.set(nullptr); - for (size_t i = 0; i < mIndexedBuffers.size(); i++) + return mGenericBuffer; +} + +const OffsetBindingPointer &TransformFeedbackState::getIndexedBuffer(size_t idx) const +{ + return mIndexedBuffers[idx]; +} + +const std::vector> &TransformFeedbackState::getIndexedBuffers() const +{ + return mIndexedBuffers; +} + +TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps) + : RefCountObject(id), + mState(caps.maxTransformFeedbackSeparateAttributes), + mImplementation(implFactory->createTransformFeedback(mState)) +{ + ASSERT(mImplementation != nullptr); +} + +Error TransformFeedback::onDestroy(const Context *context) +{ + if (mState.mProgram) { - mIndexedBuffers[i].set(nullptr); + mState.mProgram->release(context); + mState.mProgram = nullptr; } + ASSERT(!mState.mProgram); + mState.mGenericBuffer.set(context, nullptr); + for (size_t i = 0; i < mState.mIndexedBuffers.size(); i++) + { + mState.mIndexedBuffers[i].set(context, nullptr); + } + + return NoError(); +} + +TransformFeedback::~TransformFeedback() +{ SafeDelete(mImplementation); } void TransformFeedback::setLabel(const std::string &label) { - mLabel = label; + mState.mLabel = label; } const std::string &TransformFeedback::getLabel() const { - return mLabel; + return mState.mLabel; } -void TransformFeedback::begin(GLenum primitiveMode) +void TransformFeedback::begin(const Context *context, GLenum primitiveMode, Program *program) { - mActive = true; - mPrimitiveMode = primitiveMode; - mPaused = false; + mState.mActive = true; + mState.mPrimitiveMode = primitiveMode; + mState.mPaused = false; mImplementation->begin(primitiveMode); + bindProgram(context, program); } -void TransformFeedback::end() +void TransformFeedback::end(const Context *context) { - mActive = false; - mPrimitiveMode = GL_NONE; - mPaused = false; + mState.mActive = false; + mState.mPrimitiveMode = GL_NONE; + mState.mPaused = false; mImplementation->end(); + if (mState.mProgram) + { + mState.mProgram->release(context); + mState.mProgram = nullptr; + } } void TransformFeedback::pause() { - mPaused = true; + mState.mPaused = true; mImplementation->pause(); } void TransformFeedback::resume() { - mPaused = false; + mState.mPaused = false; mImplementation->resume(); } bool TransformFeedback::isActive() const { - return mActive; + return mState.mActive; } bool TransformFeedback::isPaused() const { - return mPaused; + return mState.mPaused; } GLenum TransformFeedback::getPrimitiveMode() const { - return mPrimitiveMode; + return mState.mPrimitiveMode; +} + +void TransformFeedback::bindProgram(const Context *context, Program *program) +{ + if (mState.mProgram != program) + { + if (mState.mProgram != nullptr) + { + mState.mProgram->release(context); + } + mState.mProgram = program; + if (mState.mProgram != nullptr) + { + mState.mProgram->addRef(); + } + } } -void TransformFeedback::bindGenericBuffer(Buffer *buffer) +bool TransformFeedback::hasBoundProgram(GLuint program) const { - mGenericBuffer.set(buffer); - mImplementation->bindGenericBuffer(mGenericBuffer); + return mState.mProgram != nullptr && mState.mProgram->id() == program; } -void TransformFeedback::detachBuffer(GLuint bufferName) +void TransformFeedback::bindGenericBuffer(const Context *context, Buffer *buffer) { - for (size_t index = 0; index < mIndexedBuffers.size(); index++) + mState.mGenericBuffer.set(context, buffer); + mImplementation->bindGenericBuffer(mState.mGenericBuffer); +} + +void TransformFeedback::detachBuffer(const Context *context, GLuint bufferName) +{ + for (size_t index = 0; index < mState.mIndexedBuffers.size(); index++) { - if (mIndexedBuffers[index].id() == bufferName) + if (mState.mIndexedBuffers[index].id() == bufferName) { - mIndexedBuffers[index].set(nullptr); - mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]); + mState.mIndexedBuffers[index].set(context, nullptr); + mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]); } } - if (mGenericBuffer.id() == bufferName) + if (mState.mGenericBuffer.id() == bufferName) { - mGenericBuffer.set(nullptr); - mImplementation->bindGenericBuffer(mGenericBuffer); + mState.mGenericBuffer.set(context, nullptr); + mImplementation->bindGenericBuffer(mState.mGenericBuffer); } } const BindingPointer &TransformFeedback::getGenericBuffer() const { - return mGenericBuffer; + return mState.mGenericBuffer; } -void TransformFeedback::bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size) +void TransformFeedback::bindIndexedBuffer(const Context *context, + 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]); + ASSERT(index < mState.mIndexedBuffers.size()); + mState.mIndexedBuffers[index].set(context, buffer, offset, size); + mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]); } const OffsetBindingPointer &TransformFeedback::getIndexedBuffer(size_t index) const { - ASSERT(index < mIndexedBuffers.size()); - return mIndexedBuffers[index]; + ASSERT(index < mState.mIndexedBuffers.size()); + return mState.mIndexedBuffers[index]; } size_t TransformFeedback::getIndexedBufferCount() const { - return mIndexedBuffers.size(); + return mState.mIndexedBuffers.size(); } rx::TransformFeedbackImpl *TransformFeedback::getImplementation() diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h index 098e4ea4d6..2b35d43f9a 100644 --- a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h @@ -16,6 +16,7 @@ namespace rx { +class GLImplFactory; class TransformFeedbackImpl; } @@ -23,18 +24,46 @@ namespace gl { class Buffer; struct Caps; +class Context; +class Program; + +class TransformFeedbackState final : angle::NonCopyable +{ + public: + TransformFeedbackState(size_t maxIndexedBuffers); + ~TransformFeedbackState(); + + const BindingPointer &getGenericBuffer() const; + const OffsetBindingPointer &getIndexedBuffer(size_t idx) const; + const std::vector> &getIndexedBuffers() const; + + private: + friend class TransformFeedback; + + std::string mLabel; + + bool mActive; + GLenum mPrimitiveMode; + bool mPaused; + + Program *mProgram; + + BindingPointer mGenericBuffer; + std::vector> mIndexedBuffers; +}; class TransformFeedback final : public RefCountObject, public LabeledObject { public: - TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id, const Caps &caps); - virtual ~TransformFeedback(); + TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps); + ~TransformFeedback() override; + Error onDestroy(const Context *context) override; void setLabel(const std::string &label) override; const std::string &getLabel() const override; - void begin(GLenum primitiveMode); - void end(); + void begin(const Context *context, GLenum primitiveMode, Program *program); + void end(const Context *context); void pause(); void resume(); @@ -42,29 +71,29 @@ class TransformFeedback final : public RefCountObject, public LabeledObject bool isPaused() const; GLenum getPrimitiveMode() const; - void bindGenericBuffer(Buffer *buffer); + bool hasBoundProgram(GLuint program) const; + + void bindGenericBuffer(const Context *context, Buffer *buffer); const BindingPointer &getGenericBuffer() const; - void bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size); + void bindIndexedBuffer(const Context *context, + 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); + void detachBuffer(const Context *context, GLuint bufferName); rx::TransformFeedbackImpl *getImplementation(); const rx::TransformFeedbackImpl *getImplementation() const; private: - rx::TransformFeedbackImpl* mImplementation; - - std::string mLabel; + void bindProgram(const Context *context, Program *program); - bool mActive; - GLenum mPrimitiveMode; - bool mPaused; - - BindingPointer mGenericBuffer; - std::vector> mIndexedBuffers; + TransformFeedbackState mState; + rx::TransformFeedbackImpl* mImplementation; }; } diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.cpp b/src/3rdparty/angle/src/libANGLE/Uniform.cpp index bfae3c014f..dee8eee915 100644 --- a/src/3rdparty/angle/src/libANGLE/Uniform.cpp +++ b/src/3rdparty/angle/src/libANGLE/Uniform.cpp @@ -13,46 +13,99 @@ namespace gl { +StaticallyUsed::StaticallyUsed() + : vertexStaticUse(false), fragmentStaticUse(false), computeStaticUse(false) +{ +} + +StaticallyUsed::~StaticallyUsed() +{ +} + +StaticallyUsed::StaticallyUsed(const StaticallyUsed &rhs) = default; +StaticallyUsed &StaticallyUsed::operator=(const StaticallyUsed &rhs) = default; + +void StaticallyUsed::setStaticUse(GLenum shaderType, bool used) +{ + switch (shaderType) + { + case GL_VERTEX_SHADER: + vertexStaticUse = used; + break; + + case GL_FRAGMENT_SHADER: + fragmentStaticUse = used; + break; + + case GL_COMPUTE_SHADER: + computeStaticUse = used; + break; + + default: + UNREACHABLE(); + } +} + +void StaticallyUsed::unionReferencesWith(const StaticallyUsed &other) +{ + vertexStaticUse |= other.vertexStaticUse; + fragmentStaticUse |= other.fragmentStaticUse; + computeStaticUse |= other.computeStaticUse; +} + LinkedUniform::LinkedUniform() - : blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) + : typeInfo(nullptr), bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) { } LinkedUniform::LinkedUniform(GLenum typeIn, GLenum precisionIn, const std::string &nameIn, - unsigned int arraySizeIn, - const int blockIndexIn, + const std::vector &arraySizesIn, + const int bindingIn, + const int offsetIn, + const int locationIn, + const int bufferIndexIn, const sh::BlockMemberInfo &blockInfoIn) - : blockIndex(blockIndexIn), blockInfo(blockInfoIn) + : typeInfo(&GetUniformTypeInfo(typeIn)), bufferIndex(bufferIndexIn), blockInfo(blockInfoIn) { type = typeIn; precision = precisionIn; name = nameIn; - arraySize = arraySizeIn; + arraySizes = arraySizesIn; + binding = bindingIn; + offset = offsetIn; + location = locationIn; + ASSERT(!isArrayOfArrays()); + ASSERT(!isArray() || !isStruct()); } LinkedUniform::LinkedUniform(const sh::Uniform &uniform) - : sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) + : sh::Uniform(uniform), + typeInfo(&GetUniformTypeInfo(type)), + bufferIndex(-1), + blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) { + ASSERT(!isArrayOfArrays()); + ASSERT(!isArray() || !isStruct()); } LinkedUniform::LinkedUniform(const LinkedUniform &uniform) - : sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo) + : sh::Uniform(uniform), + StaticallyUsed(uniform), + typeInfo(uniform.typeInfo), + bufferIndex(uniform.bufferIndex), + blockInfo(uniform.blockInfo) { - // This function is not intended to be called during runtime. - ASSERT(uniform.mLazyData.empty()); } LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform) { - // This function is not intended to be called during runtime. - ASSERT(uniform.mLazyData.empty()); - sh::Uniform::operator=(uniform); - blockIndex = uniform.blockIndex; + StaticallyUsed::operator=(uniform); + typeInfo = uniform.typeInfo; + bufferIndex = uniform.bufferIndex; blockInfo = uniform.blockInfo; - return *this; } @@ -62,80 +115,92 @@ LinkedUniform::~LinkedUniform() bool LinkedUniform::isInDefaultBlock() const { - return blockIndex == -1; + return bufferIndex == -1; } -size_t LinkedUniform::dataSize() const +bool LinkedUniform::isSampler() const { - ASSERT(type != GL_STRUCT_ANGLEX); - if (mLazyData.empty()) - { - mLazyData.resize(VariableExternalSize(type) * elementCount()); - ASSERT(!mLazyData.empty()); - } + return typeInfo->isSampler; +} - return mLazyData.size(); +bool LinkedUniform::isImage() const +{ + return typeInfo->isImageType; } -uint8_t *LinkedUniform::data() +bool LinkedUniform::isAtomicCounter() const { - if (mLazyData.empty()) - { - // dataSize() will init the data store. - size_t size = dataSize(); - memset(mLazyData.data(), 0, size); - } + return IsAtomicCounterType(type); +} - return mLazyData.data(); +bool LinkedUniform::isField() const +{ + return name.find('.') != std::string::npos; } -const uint8_t *LinkedUniform::data() const +size_t LinkedUniform::getElementSize() const { - return const_cast(this)->data(); + return typeInfo->externalSize; } -bool LinkedUniform::isSampler() const +size_t LinkedUniform::getElementComponents() const { - return IsSamplerType(type); + return typeInfo->componentCount; } -bool LinkedUniform::isField() const +BufferVariable::BufferVariable() + : bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()), topLevelArraySize(-1) { - return name.find('.') != std::string::npos; } -size_t LinkedUniform::getElementSize() const +BufferVariable::BufferVariable(GLenum typeIn, + GLenum precisionIn, + const std::string &nameIn, + const std::vector &arraySizesIn, + const int bufferIndexIn, + const sh::BlockMemberInfo &blockInfoIn) + : bufferIndex(bufferIndexIn), blockInfo(blockInfoIn), topLevelArraySize(-1) +{ + type = typeIn; + precision = precisionIn; + name = nameIn; + arraySizes = arraySizesIn; +} + +BufferVariable::~BufferVariable() { - return VariableExternalSize(type); } -uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) +ShaderVariableBuffer::ShaderVariableBuffer() : binding(0), dataSize(0) { - ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize)); - return data() + getElementSize() * elementIndex; } -const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const +ShaderVariableBuffer::ShaderVariableBuffer(const ShaderVariableBuffer &other) = default; + +ShaderVariableBuffer::~ShaderVariableBuffer() +{ +} + +int ShaderVariableBuffer::numActiveVariables() const { - return const_cast(this)->getDataPtrToElement(elementIndex); + return static_cast(memberIndexes.size()); } -UniformBlock::UniformBlock() - : isArray(false), arrayElement(0), dataSize(0), vertexStaticUse(false), fragmentStaticUse(false) +InterfaceBlock::InterfaceBlock() : isArray(false), arrayElement(0) { } -UniformBlock::UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn) - : name(nameIn), - isArray(isArrayIn), - arrayElement(arrayElementIn), - dataSize(0), - vertexStaticUse(false), - fragmentStaticUse(false) +InterfaceBlock::InterfaceBlock(const std::string &nameIn, + const std::string &mappedNameIn, + bool isArrayIn, + unsigned int arrayElementIn, + int bindingIn) + : name(nameIn), mappedName(mappedNameIn), isArray(isArrayIn), arrayElement(arrayElementIn) { + binding = bindingIn; } -std::string UniformBlock::nameWithArrayIndex() const +std::string InterfaceBlock::nameWithArrayIndex() const { std::stringstream fullNameStr; fullNameStr << name; @@ -146,4 +211,16 @@ std::string UniformBlock::nameWithArrayIndex() const return fullNameStr.str(); } + +std::string InterfaceBlock::mappedNameWithArrayIndex() const +{ + std::stringstream fullNameStr; + fullNameStr << mappedName; + 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 e62a583f3d..14c39387a6 100644 --- a/src/3rdparty/angle/src/libANGLE/Uniform.h +++ b/src/3rdparty/angle/src/libANGLE/Uniform.h @@ -18,53 +18,107 @@ namespace gl { +struct UniformTypeInfo; + +struct StaticallyUsed +{ + StaticallyUsed(); + StaticallyUsed(const StaticallyUsed &rhs); + virtual ~StaticallyUsed(); + + StaticallyUsed &operator=(const StaticallyUsed &rhs); + + void setStaticUse(GLenum shaderType, bool used); + void unionReferencesWith(const StaticallyUsed &other); + + bool vertexStaticUse; + bool fragmentStaticUse; + bool computeStaticUse; +}; // Helper struct representing a single shader uniform -struct LinkedUniform : public sh::Uniform +struct LinkedUniform : public sh::Uniform, public StaticallyUsed { LinkedUniform(); - LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); + LinkedUniform(GLenum type, + GLenum precision, + const std::string &name, + const std::vector &arraySizes, + const int binding, + const int offset, + const int location, + const int bufferIndex, + const sh::BlockMemberInfo &blockInfo); LinkedUniform(const sh::Uniform &uniform); LinkedUniform(const LinkedUniform &uniform); LinkedUniform &operator=(const LinkedUniform &uniform); - ~LinkedUniform(); + ~LinkedUniform() override; - size_t dataSize() const; - uint8_t *data(); - const uint8_t *data() const; bool isSampler() const; + bool isImage() const; + bool isAtomicCounter() 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; + size_t getElementComponents() const; + + const UniformTypeInfo *typeInfo; - int blockIndex; + // Identifies the containing buffer backed resource -- interface block or atomic counter buffer. + int bufferIndex; sh::BlockMemberInfo blockInfo; +}; - private: - mutable rx::MemoryBuffer mLazyData; +struct BufferVariable : public sh::ShaderVariable, public StaticallyUsed +{ + BufferVariable(); + BufferVariable(GLenum type, + GLenum precision, + const std::string &name, + const std::vector &arraySizes, + const int bufferIndex, + const sh::BlockMemberInfo &blockInfo); + ~BufferVariable() override; + + int bufferIndex; + sh::BlockMemberInfo blockInfo; + + int topLevelArraySize; +}; + +// Parent struct for atomic counter, uniform block, and shader storage block buffer, which all +// contain a group of shader variables, and have a GL buffer backed. +struct ShaderVariableBuffer : public StaticallyUsed +{ + ShaderVariableBuffer(); + ShaderVariableBuffer(const ShaderVariableBuffer &other); + ~ShaderVariableBuffer() override; + int numActiveVariables() const; + + int binding; + unsigned int dataSize; + std::vector memberIndexes; }; -// Helper struct representing a single shader uniform block -struct UniformBlock +using AtomicCounterBuffer = ShaderVariableBuffer; + +// Helper struct representing a single shader interface block +struct InterfaceBlock : public ShaderVariableBuffer { - UniformBlock(); - UniformBlock(const std::string &nameIn, bool isArrayIn, unsigned int arrayElementIn); - UniformBlock(const UniformBlock &other) = default; - UniformBlock &operator=(const UniformBlock &other) = default; + InterfaceBlock(); + InterfaceBlock(const std::string &nameIn, + const std::string &mappedNameIn, + bool isArrayIn, + unsigned int arrayElementIn, + int bindingIn); std::string nameWithArrayIndex() const; + std::string mappedNameWithArrayIndex() const; std::string name; + std::string mappedName; bool isArray; unsigned int arrayElement; - unsigned int dataSize; - - bool vertexStaticUse; - bool fragmentStaticUse; - - std::vector memberUniformIndexes; }; } diff --git a/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp b/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp new file mode 100644 index 0000000000..6fc707b549 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VaryingPacking.cpp @@ -0,0 +1,408 @@ +// +// 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, according +// to the spec, or using custom packing algorithms. We also keep a register +// allocation list for the D3D renderer. +// + +#include "libANGLE/VaryingPacking.h" + +#include "common/utilities.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" + +namespace gl +{ + +namespace +{ + +// true if varying x has a higher priority in packing than y +bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) +{ + // If the PackedVarying 'x' or 'y' to be compared is an array element, this clones an equivalent + // non-array shader variable 'vx' or 'vy' for actual comparison instead. + sh::ShaderVariable vx, vy; + const sh::ShaderVariable *px, *py; + if (x.isArrayElement()) + { + vx = *x.varying; + vx.arraySizes.clear(); + px = &vx; + } + else + { + px = x.varying; + } + + if (y.isArrayElement()) + { + vy = *y.varying; + vy.arraySizes.clear(); + py = &vy; + } + else + { + py = y.varying; + } + + return gl::CompareShaderVar(*px, *py); +} + +} // anonymous namespace + +// Implementation of VaryingPacking +VaryingPacking::VaryingPacking(GLuint maxVaryingVectors, PackMode packMode) + : mRegisterMap(maxVaryingVectors), mPackMode(packMode) +{ +} + +VaryingPacking::~VaryingPacking() = default; + +// 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) +{ + 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." + // 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); + unsigned int varyingRows = gl::VariableRowCount(transposedType); + unsigned int varyingColumns = gl::VariableColumnCount(transposedType); + + // "Variables of type mat2 occupies 2 complete rows." + // For non-WebGL contexts, we allow mat2 to occupy only two columns per row. + if (mPackMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2) + { + varyingColumns = 4; + } + + // "Arrays of size N are assumed to take N times the size of the base type" + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + const unsigned int elementCount = varying.getBasicTypeElementCount(); + varyingRows *= (packedVarying.isArrayElement() ? 1 : elementCount); + + unsigned int maxVaryingVectors = static_cast(mRegisterMap.size()); + + // Fail if we are packing a single over-large varying. + if (varyingRows > maxVaryingVectors) + { + return false; + } + + // "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 = + (packedVarying.isArrayElement() ? packedVarying.arrayIndex : arrayIndex); + registerInfo.varyingRowIndex = 0; + // Do not record register info for builtins. + // TODO(jmadill): Clean this up. + if (!packedVarying.varying->isBuiltIn()) + { + 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; + + // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of + // structures, so we may use getBasicTypeElementCount(). + const unsigned int arrayElementCount = varying.getBasicTypeElementCount(); + for (unsigned int arrayElement = 0; arrayElement < arrayElementCount; ++arrayElement) + { + if (packedVarying.isArrayElement() && arrayElement != packedVarying.arrayIndex) + { + continue; + } + for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow) + { + registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow; + registerInfo.varyingRowIndex = varyingRow; + registerInfo.varyingArrayIndex = arrayElement; + // Do not record register info for builtins. + // TODO(jmadill): Clean this up. + if (!packedVarying.varying->isBuiltIn()) + { + mRegisterList.push_back(registerInfo); + } + + for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex) + { + mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true; + } + } + } +} + +bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, + const Program::MergedVaryings &mergedVaryings, + const std::vector &tfVaryings) +{ + std::set uniqueFullNames; + mPackedVaryings.clear(); + + for (const auto &ref : mergedVaryings) + { + const sh::Varying *input = ref.second.vertex; + const sh::Varying *output = ref.second.fragment; + + // Only pack statically used varyings that have a matched input or output, plus special + // builtins. + if (((input && output) || (output && output->isBuiltIn())) && output->staticUse) + { + // Will get the vertex shader interpolation by default. + auto interpolation = ref.second.get()->interpolation; + + // Note that we lose the vertex shader static use information here. The data for the + // variable is taken from the fragment shader. + if (output->isStruct()) + { + ASSERT(!output->isArray()); + for (const auto &field : output->fields) + { + ASSERT(!field.isStruct() && !field.isArray()); + mPackedVaryings.push_back(PackedVarying(field, interpolation, output->name)); + uniqueFullNames.insert(mPackedVaryings.back().nameWithArrayIndex()); + } + } + else + { + mPackedVaryings.push_back(PackedVarying(*output, interpolation)); + uniqueFullNames.insert(mPackedVaryings.back().nameWithArrayIndex()); + } + continue; + } + + // Keep Transform FB varyings in the merged list always. + if (!input) + { + continue; + } + + for (const std::string &tfVarying : tfVaryings) + { + std::vector subscripts; + std::string baseName = ParseResourceName(tfVarying, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) + { + subscript = subscripts.back(); + } + // Already packed for fragment shader. + if (uniqueFullNames.count(tfVarying) > 0 || uniqueFullNames.count(baseName) > 0) + { + continue; + } + // Array as a whole and array element conflict has already been checked in + // linkValidateTransformFeedback. + if (baseName == input->name) + { + // Transform feedback for varying structs is underspecified. + // See Khronos bug 9856. + // TODO(jmadill): Figure out how to be spec-compliant here. + if (!input->isStruct() && tfVarying.compare(0, 3, "gl_") != 0) + { + mPackedVaryings.push_back(PackedVarying(*input, input->interpolation)); + mPackedVaryings.back().vertexOnly = true; + mPackedVaryings.back().arrayIndex = static_cast(subscript); + uniqueFullNames.insert(tfVarying); + } + // Continue to match next array element for 'input' if the current match is array + // element. + if (subscript == GL_INVALID_INDEX) + { + break; + } + } + } + } + + std::sort(mPackedVaryings.begin(), mPackedVaryings.end(), ComparePackedVarying); + + return packUserVaryings(infoLog, mPackedVaryings, tfVaryings); +} + +// See comment on packVarying. +bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, + const std::vector &packedVaryings, + const std::vector &transformFeedbackVaryings) +{ + + // "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) + { + if (!packVarying(packedVarying)) + { + infoLog << "Could not pack varying " << packedVarying.nameWithArrayIndex(); + 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; + } + } + + return count; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/VaryingPacking.h b/src/3rdparty/angle/src/libANGLE/VaryingPacking.h new file mode 100644 index 0000000000..14b25f929e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VaryingPacking.h @@ -0,0 +1,184 @@ +// +// 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, according +// to the spec, or using custom packing algorithms. We also keep a register +// allocation list for the D3D renderer. +// + +#ifndef LIBANGLE_VARYINGPACKING_H_ +#define LIBANGLE_VARYINGPACKING_H_ + +#include + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Program.h" + +namespace gl +{ +class InfoLog; + +struct PackedVarying +{ + PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn) + : PackedVarying(varyingIn, interpolationIn, "") + { + } + PackedVarying(const sh::ShaderVariable &varyingIn, + sh::InterpolationType interpolationIn, + const std::string &parentStructNameIn) + : varying(&varyingIn), + vertexOnly(false), + interpolation(interpolationIn), + parentStructName(parentStructNameIn), + arrayIndex(GL_INVALID_INDEX) + { + } + + bool isStructField() const { return !parentStructName.empty(); } + + bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; } + + std::string nameWithArrayIndex() const + { + std::stringstream fullNameStr; + fullNameStr << varying->name; + if (arrayIndex != GL_INVALID_INDEX) + { + fullNameStr << "[" << arrayIndex << "]"; + } + return fullNameStr.str(); + } + + 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; + + GLuint arrayIndex; +}; + +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; +}; + +// Supported packing modes: +enum class PackMode +{ + // We treat mat2 arrays as taking two full rows. + WEBGL_STRICT, + + // We allow mat2 to take a 2x2 chunk. + ANGLE_RELAXED, +}; + +class VaryingPacking final : angle::NonCopyable +{ + public: + VaryingPacking(GLuint maxVaryingVectors, PackMode packMode); + ~VaryingPacking(); + + bool packUserVaryings(gl::InfoLog &infoLog, + const std::vector &packedVaryings, + const std::vector &tfVaryings); + + bool collectAndPackUserVaryings(gl::InfoLog &infoLog, + const Program::MergedVaryings &mergedVaryings, + const std::vector &tfVaryings); + + 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; + size_t getRegisterMapSize() const { return mRegisterMap.size(); } + + 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 mPackedVaryings; + + PackMode mPackMode; +}; + +} // namespace gl + +#endif // LIBANGLE_VARYINGPACKING_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Version.h b/src/3rdparty/angle/src/libANGLE/Version.h index 72dfbb6b8d..7bd41846c8 100644 --- a/src/3rdparty/angle/src/libANGLE/Version.h +++ b/src/3rdparty/angle/src/libANGLE/Version.h @@ -9,23 +9,24 @@ #ifndef LIBANGLE_VERSION_H_ #define LIBANGLE_VERSION_H_ -#include - namespace gl { struct Version { - Version(); - Version(GLuint major, GLuint minor); + constexpr Version(); + constexpr Version(unsigned int major, unsigned int minor); - GLuint major; - GLuint minor; + unsigned int major; + unsigned int minor; }; +bool operator==(const Version &a, const Version &b); +bool operator!=(const Version &a, const Version &b); bool operator>=(const Version &a, const Version &b); +bool operator<=(const Version &a, const Version &b); bool operator<(const Version &a, const Version &b); - +bool operator>(const Version &a, const Version &b); } #include "Version.inl" diff --git a/src/3rdparty/angle/src/libANGLE/Version.inl b/src/3rdparty/angle/src/libANGLE/Version.inl index f64f7cae77..c98054829e 100644 --- a/src/3rdparty/angle/src/libANGLE/Version.inl +++ b/src/3rdparty/angle/src/libANGLE/Version.inl @@ -6,28 +6,54 @@ // Version.inl: Encapsulation of a GL version. +#include + namespace gl { -inline Version::Version() +constexpr Version::Version() : Version(0, 0) { } -inline Version::Version(GLuint major_, GLuint minor_) +// Avoid conflicts with linux system defines +#undef major +#undef minor + +constexpr Version::Version(unsigned int major_, unsigned int minor_) + : major(major_), + minor(minor_) { - major = major_; - minor = minor_; +} + +inline bool operator==(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) == std::tie(b.major, b.minor); +} + +inline bool operator!=(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) != std::tie(b.major, b.minor); } inline bool operator>=(const Version &a, const Version &b) { - return a.major > b.major || (a.major == b.major && a.minor >= b.minor); + return std::tie(a.major, a.minor) >= std::tie(b.major, b.minor); +} + +inline bool operator<=(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) <= std::tie(b.major, b.minor); } inline bool operator<(const Version &a, const Version &b) { - return !(a >= b); + return std::tie(a.major, a.minor) < std::tie(b.major, b.minor); } +inline bool operator>(const Version &a, const Version &b) +{ + return std::tie(a.major, a.minor) > std::tie(b.major, b.minor); } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp index 8d51e9b469..a8c2fce155 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp @@ -8,36 +8,53 @@ #include "libANGLE/VertexArray.h" #include "libANGLE/Buffer.h" -#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/VertexArrayImpl.h" namespace gl { -VertexArray::Data::Data(size_t maxAttribs) - : mLabel(), mVertexAttributes(maxAttribs), mMaxEnabledAttribute(0) +VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings) + : mLabel(), mVertexBindings(maxAttribBindings), mMaxEnabledAttribute(0) { -} + ASSERT(maxAttribs <= maxAttribBindings); -VertexArray::Data::~Data() -{ - for (size_t i = 0; i < getMaxAttribs(); i++) + for (size_t i = 0; i < maxAttribs; i++) { - mVertexAttributes[i].buffer.set(nullptr); + mVertexAttributes.emplace_back(static_cast(i)); } - mElementArrayBuffer.set(nullptr); } -VertexArray::VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs) +VertexArrayState::~VertexArrayState() +{ +} + +VertexArray::VertexArray(rx::GLImplFactory *factory, + GLuint id, + size_t maxAttribs, + size_t maxAttribBindings) : mId(id), - mVertexArray(factory->createVertexArray(mData)), - mData(maxAttribs) + mState(maxAttribs, maxAttribBindings), + mVertexArray(factory->createVertexArray(mState)) { } -VertexArray::~VertexArray() +void VertexArray::onDestroy(const Context *context) { + for (auto &binding : mState.mVertexBindings) + { + binding.setBuffer(context, nullptr); + } + mState.mElementArrayBuffer.set(context, nullptr); + mVertexArray->destroy(context); SafeDelete(mVertexArray); + delete this; +} + +VertexArray::~VertexArray() +{ + ASSERT(!mVertexArray); } GLuint VertexArray::id() const @@ -47,94 +64,204 @@ GLuint VertexArray::id() const void VertexArray::setLabel(const std::string &label) { - mData.mLabel = label; + mState.mLabel = label; } const std::string &VertexArray::getLabel() const { - return mData.mLabel; + return mState.mLabel; } -void VertexArray::detachBuffer(GLuint bufferName) +void VertexArray::detachBuffer(const Context *context, GLuint bufferName) { - for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) + for (auto &binding : mState.mVertexBindings) { - if (mData.mVertexAttributes[attribute].buffer.id() == bufferName) + if (binding.getBuffer().id() == bufferName) { - mData.mVertexAttributes[attribute].buffer.set(nullptr); + binding.setBuffer(context, nullptr); } } - if (mData.mElementArrayBuffer.id() == bufferName) + if (mState.mElementArrayBuffer.id() == bufferName) + { + mState.mElementArrayBuffer.set(context, nullptr); + } +} + +const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const +{ + ASSERT(attribIndex < getMaxAttribs()); + return mState.mVertexAttributes[attribIndex]; +} + +const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const +{ + ASSERT(bindingIndex < getMaxBindings()); + return mState.mVertexBindings[bindingIndex]; +} + +size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit) +{ + static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, + "The stride of vertex attributes should equal to that of vertex bindings."); + ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER); + return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS; +} + +void VertexArray::bindVertexBufferImpl(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + ASSERT(bindingIndex < getMaxBindings()); + + VertexBinding *binding = &mState.mVertexBindings[bindingIndex]; + + binding->setBuffer(context, boundBuffer); + binding->setOffset(offset); + binding->setStride(stride); +} + +void VertexArray::bindVertexBuffer(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride); + + mDirtyBits.set(DIRTY_BIT_BINDING_0_BUFFER + bindingIndex); +} + +void VertexArray::setVertexAttribBinding(const Context *context, + size_t attribIndex, + GLuint bindingIndex) +{ + ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings()); + + if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex) { - mData.mElementArrayBuffer.set(nullptr); + // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable. + ASSERT(context->getClientVersion() >= ES_3_1); + mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex; + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex); } } -const VertexAttribute &VertexArray::getVertexAttribute(size_t attributeIndex) const +void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) +{ + ASSERT(bindingIndex < getMaxBindings()); + + mState.mVertexBindings[bindingIndex].setDivisor(divisor); + + mDirtyBits.set(DIRTY_BIT_BINDING_0_DIVISOR + bindingIndex); +} + +void VertexArray::setVertexAttribFormatImpl(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) { - ASSERT(attributeIndex < getMaxAttribs()); - return mData.mVertexAttributes[attributeIndex]; + ASSERT(attribIndex < getMaxAttribs()); + + VertexAttribute *attrib = &mState.mVertexAttributes[attribIndex]; + + attrib->size = size; + attrib->type = type; + attrib->normalized = normalized; + attrib->pureInteger = pureInteger; + attrib->relativeOffset = relativeOffset; } -void VertexArray::setVertexAttribDivisor(size_t index, GLuint divisor) +void VertexArray::setVertexAttribFormat(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) { - ASSERT(index < getMaxAttribs()); - mData.mVertexAttributes[index].divisor = divisor; - mDirtyBits.set(DIRTY_BIT_ATTRIB_0_DIVISOR + index); + setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset); + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_FORMAT + attribIndex); +} + +void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor) +{ + ASSERT(attribIndex < getMaxAttribs()); + + setVertexAttribBinding(context, attribIndex, static_cast(attribIndex)); + setVertexBindingDivisor(attribIndex, divisor); } -void VertexArray::enableAttribute(size_t attributeIndex, bool enabledState) +void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) { - ASSERT(attributeIndex < getMaxAttribs()); - mData.mVertexAttributes[attributeIndex].enabled = enabledState; - mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attributeIndex); + ASSERT(attribIndex < getMaxAttribs()); + + mState.mVertexAttributes[attribIndex].enabled = enabledState; + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex); // Update state cache if (enabledState) { - mData.mMaxEnabledAttribute = std::max(attributeIndex + 1, mData.mMaxEnabledAttribute); + mState.mMaxEnabledAttribute = std::max(attribIndex + 1, mState.mMaxEnabledAttribute); } - else if (mData.mMaxEnabledAttribute == attributeIndex + 1) + else if (mState.mMaxEnabledAttribute == attribIndex + 1) { - while (mData.mMaxEnabledAttribute > 0 && - !mData.mVertexAttributes[mData.mMaxEnabledAttribute - 1].enabled) + while (mState.mMaxEnabledAttribute > 0 && + !mState.mVertexAttributes[mState.mMaxEnabledAttribute - 1].enabled) { - --mData.mMaxEnabledAttribute; + --mState.mMaxEnabledAttribute; } } } -void VertexArray::setAttributeState(size_t attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer) +void VertexArray::setVertexAttribPointer(const Context *context, + size_t attribIndex, + gl::Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer) { - ASSERT(attributeIndex < getMaxAttribs()); + ASSERT(attribIndex < getMaxAttribs()); + + GLintptr offset = boundBuffer ? reinterpret_cast(pointer) : 0; + + setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, 0); + setVertexAttribBinding(context, attribIndex, static_cast(attribIndex)); - VertexAttribute *attrib = &mData.mVertexAttributes[attributeIndex]; + VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; - 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); + GLsizei effectiveStride = + stride != 0 ? stride : static_cast(ComputeVertexAttributeTypeSize(attrib)); + attrib.pointer = pointer; + attrib.vertexAttribArrayStride = stride; + + bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride); + + mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attribIndex); } -void VertexArray::setElementArrayBuffer(Buffer *buffer) +void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer) { - mData.mElementArrayBuffer.set(buffer); + mState.mElementArrayBuffer.set(context, buffer); mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER); } -void VertexArray::syncImplState() +void VertexArray::syncState(const Context *context) { if (mDirtyBits.any()) { - mVertexArray->syncState(mDirtyBits); + mVertexArray->syncState(context, mDirtyBits); mDirtyBits.reset(); } } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.h b/src/3rdparty/angle/src/libANGLE/VertexArray.h index 6bc267d399..f82ec789f0 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexArray.h +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.h @@ -23,68 +23,131 @@ namespace rx { -class ImplFactory; +class GLImplFactory; class VertexArrayImpl; -} +} // namespace rx namespace gl { class Buffer; -class VertexArray final : public LabeledObject +class VertexArrayState final : angle::NonCopyable { public: - VertexArray(rx::ImplFactory *factory, GLuint id, size_t maxAttribs); - ~VertexArray(); + VertexArrayState(size_t maxAttribs, size_t maxBindings); + ~VertexArrayState(); - GLuint id() const; + const std::string &getLabel() const { return mLabel; } - void setLabel(const std::string &label) override; - const std::string &getLabel() const override; + const BindingPointer &getElementArrayBuffer() const { return mElementArrayBuffer; } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + size_t getMaxBindings() const { return mVertexBindings.size(); } + size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; } + const std::vector &getVertexAttributes() const { return mVertexAttributes; } + const VertexAttribute &getVertexAttribute(size_t attribIndex) const + { + return mVertexAttributes[attribIndex]; + } + const std::vector &getVertexBindings() const { return mVertexBindings; } + const VertexBinding &getVertexBinding(size_t bindingIndex) const + { + return mVertexBindings[bindingIndex]; + } + const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const + { + return mVertexBindings[mVertexAttributes[attribIndex].bindingIndex]; + } + size_t getBindingIndexFromAttribIndex(size_t attribIndex) const + { + return mVertexAttributes[attribIndex].bindingIndex; + } - const VertexAttribute &getVertexAttribute(size_t attributeIndex) const; + private: + friend class VertexArray; + std::string mLabel; + std::vector mVertexAttributes; + BindingPointer mElementArrayBuffer; + std::vector mVertexBindings; + size_t mMaxEnabledAttribute; +}; - void detachBuffer(GLuint bufferName); - 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); +class VertexArray final : public LabeledObject +{ + public: + VertexArray(rx::GLImplFactory *factory, GLuint id, size_t maxAttribs, size_t maxAttribBindings); - void setElementArrayBuffer(Buffer *buffer); + void onDestroy(const Context *context); - const BindingPointer &getElementArrayBuffer() const { return mData.getElementArrayBuffer(); } - size_t getMaxAttribs() const { return mData.getVertexAttributes().size(); } - const std::vector &getVertexAttributes() const { return mData.getVertexAttributes(); } + GLuint id() const; - rx::VertexArrayImpl *getImplementation() { return mVertexArray; } - const rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + void setLabel(const std::string &label) override; + const std::string &getLabel() const override; - size_t getMaxEnabledAttribute() const { return mData.getMaxEnabledAttribute(); } + const VertexBinding &getVertexBinding(size_t bindingIndex) const; + const VertexAttribute &getVertexAttribute(size_t attribIndex) const; + const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const + { + return mState.getBindingFromAttribIndex(attribIndex); + } + + void detachBuffer(const Context *context, GLuint bufferName); + void setVertexAttribDivisor(const Context *context, size_t index, GLuint divisor); + void enableAttribute(size_t attribIndex, bool enabledState); + void setVertexAttribPointer(const Context *context, + size_t attribIndex, + Buffer *boundBuffer, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLsizei stride, + const void *pointer); + void setVertexAttribFormat(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void bindVertexBuffer(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + void setVertexAttribBinding(const Context *context, size_t attribIndex, GLuint bindingIndex); + void setVertexBindingDivisor(size_t bindingIndex, GLuint divisor); + void setVertexAttribFormatImpl(size_t attribIndex, + GLint size, + GLenum type, + bool normalized, + bool pureInteger, + GLuint relativeOffset); + void bindVertexBufferImpl(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride); + + void setElementArrayBuffer(const Context *context, Buffer *buffer); + + const BindingPointer &getElementArrayBuffer() const + { + return mState.getElementArrayBuffer(); + } + size_t getMaxAttribs() const { return mState.getMaxAttribs(); } + size_t getMaxBindings() const { return mState.getMaxBindings(); } - class Data final : public angle::NonCopyable + const std::vector &getVertexAttributes() const { - 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; - }; + return mState.getVertexAttributes(); + } + const std::vector &getVertexBindings() const + { + return mState.getVertexBindings(); + } + + rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + + size_t getMaxEnabledAttribute() const { return mState.getMaxEnabledAttribute(); } enum DirtyBitType { @@ -98,28 +161,45 @@ class VertexArray final : public LabeledObject 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, + // Reserve bits for changes to VertexAttribFormat + DIRTY_BIT_ATTRIB_0_FORMAT = DIRTY_BIT_ATTRIB_MAX_POINTER, + DIRTY_BIT_ATTRIB_MAX_FORMAT = DIRTY_BIT_ATTRIB_0_FORMAT + gl::MAX_VERTEX_ATTRIBS, + + // Reserve bits for changes to VertexAttribBinding + DIRTY_BIT_ATTRIB_0_BINDING = DIRTY_BIT_ATTRIB_MAX_FORMAT, + DIRTY_BIT_ATTRIB_MAX_BINDING = DIRTY_BIT_ATTRIB_0_BINDING + gl::MAX_VERTEX_ATTRIBS, + + // Reserve bits for changes to BindVertexBuffer + DIRTY_BIT_BINDING_0_BUFFER = DIRTY_BIT_ATTRIB_MAX_BINDING, + DIRTY_BIT_BINDING_MAX_BUFFER = DIRTY_BIT_BINDING_0_BUFFER + gl::MAX_VERTEX_ATTRIB_BINDINGS, - DIRTY_BIT_UNKNOWN = DIRTY_BIT_ATTRIB_MAX_DIVISOR, + // Reserve bits for binding divisors + DIRTY_BIT_BINDING_0_DIVISOR = DIRTY_BIT_BINDING_MAX_BUFFER, + DIRTY_BIT_BINDING_MAX_DIVISOR = + DIRTY_BIT_BINDING_0_DIVISOR + gl::MAX_VERTEX_ATTRIB_BINDINGS, + + DIRTY_BIT_UNKNOWN = DIRTY_BIT_BINDING_MAX_DIVISOR, DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, }; - typedef std::bitset DirtyBits; + using DirtyBits = angle::BitSet; + + static size_t GetVertexIndexFromDirtyBit(size_t dirtyBit); - void syncImplState(); + void syncState(const Context *context); bool hasAnyDirtyBit() const { return mDirtyBits.any(); } private: - GLuint mId; + ~VertexArray() override; - rx::VertexArrayImpl *mVertexArray; + GLuint mId; - Data mData; + VertexArrayState mState; DirtyBits mDirtyBits; + + rx::VertexArrayImpl *mVertexArray; }; -} +} // namespace gl #endif // LIBANGLE_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp index 13d78fd13c..20f7452fa5 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp @@ -3,7 +3,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// Implementation of the state classes for mananging GLES 3.1 Vertex Array Objects. // #include "libANGLE/VertexAttribute.h" @@ -11,16 +11,74 @@ namespace gl { -VertexAttribute::VertexAttribute() +// [OpenGL ES 3.1] (November 3, 2016) Section 20 Page 361 +// Table 20.2: Vertex Array Object State +VertexBinding::VertexBinding() : mStride(16u), mDivisor(0), mOffset(0) +{ +} + +VertexBinding::VertexBinding(VertexBinding &&binding) +{ + *this = std::move(binding); +} + +VertexBinding::~VertexBinding() +{ +} + +VertexBinding &VertexBinding::operator=(VertexBinding &&binding) +{ + if (this != &binding) + { + mStride = binding.mStride; + mDivisor = binding.mDivisor; + mOffset = binding.mOffset; + std::swap(binding.mBuffer, mBuffer); + } + return *this; +} + +VertexAttribute::VertexAttribute(GLuint bindingIndex) : enabled(false), type(GL_FLOAT), - size(4), + size(4u), normalized(false), pureInteger(false), - stride(0), - pointer(NULL), - divisor(0) + pointer(nullptr), + relativeOffset(0), + vertexAttribArrayStride(0), + bindingIndex(bindingIndex) +{ +} + +VertexAttribute::VertexAttribute(VertexAttribute &&attrib) + : enabled(attrib.enabled), + type(attrib.type), + size(attrib.size), + normalized(attrib.normalized), + pureInteger(attrib.pureInteger), + pointer(attrib.pointer), + relativeOffset(attrib.relativeOffset), + vertexAttribArrayStride(attrib.vertexAttribArrayStride), + bindingIndex(attrib.bindingIndex) +{ +} + +VertexAttribute &VertexAttribute::operator=(VertexAttribute &&attrib) { + if (this != &attrib) + { + enabled = attrib.enabled; + type = attrib.type; + size = attrib.size; + normalized = attrib.normalized; + pureInteger = attrib.pureInteger; + pointer = attrib.pointer; + relativeOffset = attrib.relativeOffset; + vertexAttribArrayStride = attrib.vertexAttribArrayStride; + bindingIndex = attrib.bindingIndex; + } + return *this; } size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) @@ -43,32 +101,62 @@ size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) } } -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) +size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding) { - if (!attrib.enabled) - { - return 16; - } - return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); + // In ES 3.1, VertexAttribPointer will store the type size in the binding stride. + // Hence, rendering always uses the binding's stride. + return attrib.enabled ? binding.getStride() : 16u; +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding) +{ + return attrib.relativeOffset + binding.getOffset(); } -size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib, - size_t drawCount, - size_t instanceCount) +size_t ComputeVertexBindingElementCount(GLuint divisor, 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) + if (instanceCount > 0 && 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 (instanceCount + divisor - 1u) / divisor; } return drawCount; } + +GLenum GetVertexAttributeBaseType(const VertexAttribute &attrib) +{ + if (attrib.pureInteger) + { + switch (attrib.type) + { + case GL_BYTE: + case GL_SHORT: + case GL_INT: + return GL_INT; + + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + return GL_UNSIGNED_INT; + + default: + UNREACHABLE(); + return GL_NONE; + } + } + else + { + return GL_FLOAT; + } } + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h index d1ee1b47a2..c531bece7c 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h @@ -3,7 +3,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Helper structure describing a single vertex attribute +// Helper structures about Generic Vertex Attribute. // #ifndef LIBANGLE_VERTEXATTRIBUTE_H_ @@ -13,45 +13,77 @@ namespace gl { +class VertexArray; -struct VertexAttribute +// +// Implementation of Generic Vertex Attribute Bindings for ES3.1. The members are intentionally made +// private in order to hide implementation details. +// +class VertexBinding final : angle::NonCopyable { - bool enabled; // From glEnable/DisableVertexAttribArray + public: + VertexBinding(); + VertexBinding(VertexBinding &&binding); + ~VertexBinding(); + VertexBinding &operator=(VertexBinding &&binding); + + GLuint getStride() const { return mStride; } + void setStride(GLuint strideIn) { mStride = strideIn; } + + GLuint getDivisor() const { return mDivisor; } + void setDivisor(GLuint divisorIn) { mDivisor = divisorIn; } + + GLintptr getOffset() const { return mOffset; } + void setOffset(GLintptr offsetIn) { mOffset = offsetIn; } + + const BindingPointer &getBuffer() const { return mBuffer; } + void setBuffer(const gl::Context *context, Buffer *bufferIn) { mBuffer.set(context, bufferIn); } + + private: + GLuint mStride; + GLuint mDivisor; + GLintptr mOffset; + + BindingPointer mBuffer; +}; +// +// Implementation of Generic Vertex Attributes for ES3.1 +// +struct VertexAttribute final : private angle::NonCopyable +{ + explicit VertexAttribute(GLuint bindingIndex); + explicit VertexAttribute(VertexAttribute &&attrib); + VertexAttribute &operator=(VertexAttribute &&attrib); + + bool enabled; // For glEnable/DisableVertexAttribArray GLenum type; GLuint size; bool normalized; bool pureInteger; - GLuint stride; // 0 means natural stride - union - { - const GLvoid *pointer; - GLintptr offset; - }; - BindingPointer buffer; // Captured when glVertexAttribPointer is called. - - GLuint divisor; + const void *pointer; + GLuint relativeOffset; - VertexAttribute(); + GLuint vertexAttribArrayStride; // ONLY for queries of VERTEX_ATTRIB_ARRAY_STRIDE + GLuint bindingIndex; }; -bool operator==(const VertexAttribute &a, const VertexAttribute &b); -bool operator!=(const VertexAttribute &a, const VertexAttribute &b); +size_t ComputeVertexAttributeTypeSize(const VertexAttribute &attrib); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding); -template -T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname); +size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount); -size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); -size_t ComputeVertexAttributeElementCount(const VertexAttribute &attrib, - size_t drawCount, - size_t instanceCount); +GLenum GetVertexAttributeBaseType(const VertexAttribute &attrib); struct VertexAttribCurrentValueData { - union - { + union { GLfloat FloatValues[4]; GLint IntValues[4]; GLuint UnsignedIntValues[4]; @@ -68,8 +100,8 @@ struct VertexAttribCurrentValueData bool operator==(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b); bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttribCurrentValueData &b); -} +} // namespace gl #include "VertexAttribute.inl" -#endif // LIBANGLE_VERTEXATTRIBUTE_H_ +#endif // LIBANGLE_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl index 0cd31f6762..1c1843e46f 100644 --- a/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.inl @@ -9,51 +9,6 @@ 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) { @@ -100,4 +55,4 @@ inline bool operator!=(const VertexAttribCurrentValueData &a, const VertexAttrib return !(a == b); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Workarounds.h b/src/3rdparty/angle/src/libANGLE/Workarounds.h new file mode 100644 index 0000000000..898031d78d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Workarounds.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Workarounds.h: Workarounds for driver bugs and other behaviors seen +// on all platforms. + +#ifndef LIBANGLE_WORKAROUNDS_H_ +#define LIBANGLE_WORKAROUNDS_H_ + +namespace gl +{ + +struct Workarounds +{ + // Force the context to be lost (via KHR_robustness) if a GL_OUT_OF_MEMORY error occurs. The + // driver may be in an inconsistent state if this happens, and some users of ANGLE rely on this + // notification to prevent further execution. + bool loseContextOnOutOfMemory = false; + + // Program binaries don't contain transform feedback varyings on Qualcomm GPUs. + // Work around this by disabling the program cache for programs with transform feedback. + bool disableProgramCachingForTransformFeedback = false; +}; +} // namespace gl + +#endif // LIBANGLE_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp b/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp new file mode 100644 index 0000000000..b5d789ef93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/WorkerThread.cpp @@ -0,0 +1,157 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WorkerThread: +// Task running thread for ANGLE, similar to a TaskRunner in Chromium. +// Might be implemented differently depending on platform. +// + +#include "libANGLE/WorkerThread.h" + +namespace angle +{ + +namespace priv +{ +// SingleThreadedWorkerPool implementation. +SingleThreadedWorkerPool::SingleThreadedWorkerPool(size_t maxThreads) + : WorkerThreadPoolBase(maxThreads) +{ +} + +SingleThreadedWorkerPool::~SingleThreadedWorkerPool() +{ +} + +SingleThreadedWaitableEvent SingleThreadedWorkerPool::postWorkerTaskImpl(Closure *task) +{ + (*task)(); + return SingleThreadedWaitableEvent(EventResetPolicy::Automatic, EventInitialState::Signaled); +} + +// SingleThreadedWaitableEvent implementation. +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent() + : SingleThreadedWaitableEvent(EventResetPolicy::Automatic, EventInitialState::NonSignaled) +{ +} + +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent(EventResetPolicy resetPolicy, + EventInitialState initialState) + : WaitableEventBase(resetPolicy, initialState) +{ +} + +SingleThreadedWaitableEvent::~SingleThreadedWaitableEvent() +{ +} + +SingleThreadedWaitableEvent::SingleThreadedWaitableEvent(SingleThreadedWaitableEvent &&other) + : WaitableEventBase(std::move(other)) +{ +} + +SingleThreadedWaitableEvent &SingleThreadedWaitableEvent::operator=( + SingleThreadedWaitableEvent &&other) +{ + return copyBase(std::move(other)); +} + +void SingleThreadedWaitableEvent::resetImpl() +{ + mSignaled = false; +} + +void SingleThreadedWaitableEvent::waitImpl() +{ +} + +void SingleThreadedWaitableEvent::signalImpl() +{ + mSignaled = true; +} + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +// AsyncWorkerPool implementation. +AsyncWorkerPool::AsyncWorkerPool(size_t maxThreads) : WorkerThreadPoolBase(maxThreads) +{ +} + +AsyncWorkerPool::~AsyncWorkerPool() +{ +} + +AsyncWaitableEvent AsyncWorkerPool::postWorkerTaskImpl(Closure *task) +{ + auto future = std::async(std::launch::async, [task] { (*task)(); }); + + AsyncWaitableEvent waitable(EventResetPolicy::Automatic, EventInitialState::NonSignaled); + + waitable.setFuture(std::move(future)); + + return waitable; +} + +// AsyncWaitableEvent implementation. +AsyncWaitableEvent::AsyncWaitableEvent() + : AsyncWaitableEvent(EventResetPolicy::Automatic, EventInitialState::NonSignaled) +{ +} + +AsyncWaitableEvent::AsyncWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState) + : WaitableEventBase(resetPolicy, initialState) +{ +} + +AsyncWaitableEvent::~AsyncWaitableEvent() +{ +} + +AsyncWaitableEvent::AsyncWaitableEvent(AsyncWaitableEvent &&other) + : WaitableEventBase(std::move(other)), mFuture(std::move(other.mFuture)) +{ +} + +AsyncWaitableEvent &AsyncWaitableEvent::operator=(AsyncWaitableEvent &&other) +{ + std::swap(mFuture, other.mFuture); + return copyBase(std::move(other)); +} + +void AsyncWaitableEvent::setFuture(std::future &&future) +{ + mFuture = std::move(future); +} + +void AsyncWaitableEvent::resetImpl() +{ + mSignaled = false; + mFuture = std::future(); +} + +void AsyncWaitableEvent::waitImpl() +{ + if (mSignaled || !mFuture.valid()) + { + return; + } + + mFuture.wait(); + signal(); +} + +void AsyncWaitableEvent::signalImpl() +{ + mSignaled = true; + + if (mResetPolicy == EventResetPolicy::Automatic) + { + reset(); + } +} +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace priv + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/WorkerThread.h b/src/3rdparty/angle/src/libANGLE/WorkerThread.h new file mode 100644 index 0000000000..f6b81dce21 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/WorkerThread.h @@ -0,0 +1,284 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WorkerThread: +// Asychronous tasks/threads for ANGLE, similar to a TaskRunner in Chromium. +// Can be implemented as different targets, depending on platform. +// + +#ifndef LIBANGLE_WORKER_THREAD_H_ +#define LIBANGLE_WORKER_THREAD_H_ + +#include +#include + +#include "common/debug.h" +#include "libANGLE/features.h" + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +#include +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +namespace angle +{ +// Indicates whether a WaitableEvent should automatically reset the event state after a single +// waiting thread has been released or remain signaled until reset() is manually invoked. +enum class EventResetPolicy +{ + Manual, + Automatic +}; + +// Specify the initial state on creation. +enum class EventInitialState +{ + NonSignaled, + Signaled +}; + +// A callback function with no return value and no arguments. +class Closure +{ + public: + virtual ~Closure() = default; + virtual void operator()() = 0; +}; + +namespace priv +{ +// An event that we can wait on, useful for joining worker threads. +template +class WaitableEventBase : angle::NonCopyable +{ + public: + WaitableEventBase(EventResetPolicy resetPolicy, EventInitialState initialState); + + WaitableEventBase(WaitableEventBase &&other); + + // Puts the event in the un-signaled state. + void reset(); + + // Waits indefinitely for the event to be signaled. + void wait(); + + // Puts the event in the signaled state, causing any thread blocked on Wait to be woken up. + // The event state is reset to non-signaled after a waiting thread has been released. + void signal(); + + protected: + Impl ©Base(Impl &&other); + + template + static size_t WaitManyBase(std::array *waitables); + + EventResetPolicy mResetPolicy; + bool mSignaled; +}; + +template +WaitableEventBase::WaitableEventBase(EventResetPolicy resetPolicy, + EventInitialState initialState) + : mResetPolicy(resetPolicy), mSignaled(initialState == EventInitialState::Signaled) +{ +} + +template +WaitableEventBase::WaitableEventBase(WaitableEventBase &&other) + : mResetPolicy(other.mResetPolicy), mSignaled(other.mSignaled) +{ +} + +template +void WaitableEventBase::reset() +{ + static_cast(this)->resetImpl(); +} + +template +void WaitableEventBase::wait() +{ + static_cast(this)->waitImpl(); +} + +template +void WaitableEventBase::signal() +{ + static_cast(this)->signalImpl(); +} + +template +template +// static +size_t WaitableEventBase::WaitManyBase(std::array *waitables) +{ + ASSERT(Count > 0); + + for (size_t index = 0; index < Count; ++index) + { + (*waitables)[index].wait(); + } + + return 0; +} + +template +Impl &WaitableEventBase::copyBase(Impl &&other) +{ + std::swap(mSignaled, other.mSignaled); + std::swap(mResetPolicy, other.mResetPolicy); + return *static_cast(this); +} + +class SingleThreadedWaitableEvent : public WaitableEventBase +{ + public: + SingleThreadedWaitableEvent(); + SingleThreadedWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~SingleThreadedWaitableEvent(); + + SingleThreadedWaitableEvent(SingleThreadedWaitableEvent &&other); + SingleThreadedWaitableEvent &operator=(SingleThreadedWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template + static size_t WaitMany(std::array *waitables); +}; + +template +// static +size_t SingleThreadedWaitableEvent::WaitMany( + std::array *waitables) +{ + return WaitableEventBase::WaitManyBase(waitables); +} + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWaitableEvent : public WaitableEventBase +{ + public: + AsyncWaitableEvent(); + AsyncWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~AsyncWaitableEvent(); + + AsyncWaitableEvent(AsyncWaitableEvent &&other); + AsyncWaitableEvent &operator=(AsyncWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template + static size_t WaitMany(std::array *waitables); + + private: + friend class AsyncWorkerPool; + void setFuture(std::future &&future); + + std::future mFuture; +}; + +template +// static +size_t AsyncWaitableEvent::WaitMany(std::array *waitables) +{ + return WaitableEventBase::WaitManyBase(waitables); +} +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// The traits class allows the the thread pool to return the "Typed" waitable event from postTask. +// Otherwise postTask would always think it returns the current active type, so the unit tests +// could not run on multiple worker types in the same compilation. +template +struct WorkerThreadPoolTraits; + +class SingleThreadedWorkerPool; +template <> +struct WorkerThreadPoolTraits +{ + using WaitableEventType = SingleThreadedWaitableEvent; +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool; +template <> +struct WorkerThreadPoolTraits +{ + using WaitableEventType = AsyncWaitableEvent; +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// Request WorkerThreads from the WorkerThreadPool. Each pool can keep worker threads around so +// we avoid the costly spin up and spin down time. +template +class WorkerThreadPoolBase : angle::NonCopyable +{ + public: + WorkerThreadPoolBase(size_t maxThreads); + ~WorkerThreadPoolBase(); + + using WaitableEventType = typename WorkerThreadPoolTraits::WaitableEventType; + + // Returns an event to wait on for the task to finish. + // If the pool fails to create the task, returns null. + WaitableEventType postWorkerTask(Closure *task); +}; + +template +WorkerThreadPoolBase::WorkerThreadPoolBase(size_t maxThreads) +{ +} + +template +WorkerThreadPoolBase::~WorkerThreadPoolBase() +{ +} + +template +typename WorkerThreadPoolBase::WaitableEventType WorkerThreadPoolBase::postWorkerTask( + Closure *task) +{ + return static_cast(this)->postWorkerTaskImpl(task); +} + +class SingleThreadedWorkerPool : public WorkerThreadPoolBase +{ + public: + SingleThreadedWorkerPool(size_t maxThreads); + ~SingleThreadedWorkerPool(); + + SingleThreadedWaitableEvent postWorkerTaskImpl(Closure *task); +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool : public WorkerThreadPoolBase +{ + public: + AsyncWorkerPool(size_t maxThreads); + ~AsyncWorkerPool(); + + AsyncWaitableEvent postWorkerTaskImpl(Closure *task); +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace priv + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +using WaitableEvent = priv::AsyncWaitableEvent; +using WorkerThreadPool = priv::AsyncWorkerPool; +#else +using WaitableEvent = priv::SingleThreadedWaitableEvent; +using WorkerThreadPool = priv::SingleThreadedWorkerPool; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace angle + +#endif // LIBANGLE_WORKER_THREAD_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.cpp b/src/3rdparty/angle/src/libANGLE/angletypes.cpp index fa5b157906..702d391e46 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.cpp +++ b/src/3rdparty/angle/src/libANGLE/angletypes.cpp @@ -39,39 +39,143 @@ PrimitiveType GetPrimitiveType(GLenum drawMode) } } +RasterizerState::RasterizerState() +{ + memset(this, 0, sizeof(RasterizerState)); + + rasterizerDiscard = false; + cullFace = false; + cullMode = CullFaceMode::Back; + frontFace = GL_CCW; + polygonOffsetFill = false; + polygonOffsetFactor = 0.0f; + polygonOffsetUnits = 0.0f; + pointDrawMode = false; + multiSample = false; +} + +bool operator==(const RasterizerState &a, const RasterizerState &b) +{ + return memcmp(&a, &b, sizeof(RasterizerState)) == 0; +} + +bool operator!=(const RasterizerState &a, const RasterizerState &b) +{ + return !(a == b); +} + +BlendState::BlendState() +{ + memset(this, 0, sizeof(BlendState)); + + blend = false; + sourceBlendRGB = GL_ONE; + sourceBlendAlpha = GL_ONE; + destBlendRGB = GL_ZERO; + destBlendAlpha = GL_ZERO; + blendEquationRGB = GL_FUNC_ADD; + blendEquationAlpha = GL_FUNC_ADD; + sampleAlphaToCoverage = false; + dither = true; +} + +BlendState::BlendState(const BlendState &other) +{ + memcpy(this, &other, sizeof(BlendState)); +} + +bool operator==(const BlendState &a, const BlendState &b) +{ + return memcmp(&a, &b, sizeof(BlendState)) == 0; +} + +bool operator!=(const BlendState &a, const BlendState &b) +{ + return !(a == b); +} + +DepthStencilState::DepthStencilState() +{ + memset(this, 0, sizeof(DepthStencilState)); + + depthTest = false; + depthFunc = GL_LESS; + depthMask = true; + stencilTest = false; + stencilFunc = GL_ALWAYS; + stencilMask = static_cast(-1); + stencilWritemask = static_cast(-1); + stencilBackFunc = GL_ALWAYS; + stencilBackMask = static_cast(-1); + stencilBackWritemask = static_cast(-1); + stencilFail = GL_KEEP; + stencilPassDepthFail = GL_KEEP; + stencilPassDepthPass = GL_KEEP; + stencilBackFail = GL_KEEP; + stencilBackPassDepthFail = GL_KEEP; + stencilBackPassDepthPass = GL_KEEP; +} + +DepthStencilState::DepthStencilState(const DepthStencilState &other) +{ + memcpy(this, &other, sizeof(DepthStencilState)); +} + +bool operator==(const DepthStencilState &a, const DepthStencilState &b) +{ + return memcmp(&a, &b, sizeof(DepthStencilState)) == 0; +} + +bool operator!=(const DepthStencilState &a, const DepthStencilState &b) +{ + return !(a == b); +} + SamplerState::SamplerState() - : minFilter(GL_NEAREST_MIPMAP_LINEAR), - magFilter(GL_LINEAR), - wrapS(GL_REPEAT), - wrapT(GL_REPEAT), - wrapR(GL_REPEAT), - maxAnisotropy(1.0f), - minLod(-1000.0f), - maxLod(1000.0f), - compareMode(GL_NONE), - compareFunc(GL_LEQUAL) { + memset(this, 0, sizeof(SamplerState)); + + minFilter = GL_NEAREST_MIPMAP_LINEAR; + magFilter = GL_LINEAR; + wrapS = GL_REPEAT; + wrapT = GL_REPEAT; + wrapR = GL_REPEAT; + maxAnisotropy = 1.0f; + minLod = -1000.0f; + maxLod = 1000.0f; + compareMode = GL_NONE; + compareFunc = GL_LEQUAL; + sRGBDecode = GL_DECODE_EXT; } -TextureState::TextureState() - : swizzleRed(GL_RED), - swizzleGreen(GL_GREEN), - swizzleBlue(GL_BLUE), - swizzleAlpha(GL_ALPHA), - samplerState(), - baseLevel(0), - maxLevel(1000), - immutableFormat(false), - immutableLevels(0) +SamplerState::SamplerState(const SamplerState &other) = default; + +// static +SamplerState SamplerState::CreateDefaultForTarget(GLenum target) { + SamplerState state; + + // According to OES_EGL_image_external and ARB_texture_rectangle: For external textures, the + // default min filter is GL_LINEAR and the default s and t wrap modes are GL_CLAMP_TO_EDGE. + if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE) + { + state.minFilter = GL_LINEAR; + state.wrapS = GL_CLAMP_TO_EDGE; + state.wrapT = GL_CLAMP_TO_EDGE; + } + + return state; } -bool TextureState::swizzleRequired() const +ImageUnit::ImageUnit() + : texture(), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI) { - return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || - swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; } +ImageUnit::ImageUnit(const ImageUnit &other) = default; + +ImageUnit::~ImageUnit() = default; + static void MinMax(int a, int b, int *minimum, int *maximum) { if (a < b) @@ -133,6 +237,16 @@ bool Box::operator!=(const Box &other) const return !(*this == other); } +bool operator==(const Offset &a, const Offset &b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +bool operator!=(const Offset &a, const Offset &b) +{ + return !(a == b); +} + bool operator==(const Extents &lhs, const Extents &rhs) { return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depth == rhs.depth; @@ -142,4 +256,4 @@ bool operator!=(const Extents &lhs, const Extents &rhs) { return !(lhs == rhs); } -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h index c29ad06bd2..4f364b090a 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.h +++ b/src/3rdparty/angle/src/libANGLE/angletypes.h @@ -9,20 +9,22 @@ #ifndef LIBANGLE_ANGLETYPES_H_ #define LIBANGLE_ANGLETYPES_H_ +#include "common/bitset_utils.h" #include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/PackedGLEnums.h" #include "libANGLE/RefCountObject.h" #include #include +#include +#include namespace gl { class Buffer; -class State; -class Program; -struct VertexAttribute; -struct VertexAttribCurrentValueData; +class Texture; enum PrimitiveType { @@ -41,31 +43,19 @@ PrimitiveType GetPrimitiveType(GLenum drawMode); enum SamplerType { SAMPLER_PIXEL, - SAMPLER_VERTEX + SAMPLER_VERTEX, + SAMPLER_COMPUTE }; -template -struct Color +enum ShaderType { - T red; - T green; - T blue; - T alpha; - - Color() : red(0), green(0), blue(0), alpha(0) { } - Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) { } + SHADER_VERTEX, + SHADER_FRAGMENT, + SHADER_GEOMETRY, + SHADER_COMPUTE, + SHADER_TYPE_MAX }; -template -bool operator==(const Color &a, const Color &b); - -template -bool operator!=(const Color &a, const Color &b); - -typedef Color ColorF; -typedef Color ColorI; -typedef Color ColorUI; - struct Rectangle { Rectangle() : x(0), y(0), width(0), height(0) {} @@ -100,6 +90,9 @@ struct Offset Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) { } }; +bool operator==(const Offset &a, const Offset &b); +bool operator!=(const Offset &a, const Offset &b); + struct Extents { int width; @@ -109,6 +102,9 @@ struct Extents Extents() : width(0), height(0), depth(0) { } Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } + Extents(const Extents &other) = default; + Extents &operator=(const Extents &other) = default; + bool empty() const { return (width * height * depth) == 0; } }; @@ -131,11 +127,13 @@ struct Box bool operator!=(const Box &other) const; }; - -struct RasterizerState +struct RasterizerState final { + // This will zero-initialize the struct, including padding. + RasterizerState(); + bool cullFace; - GLenum cullMode; + CullFaceMode cullMode; GLenum frontFace; bool polygonOffsetFill; @@ -148,8 +146,15 @@ struct RasterizerState bool rasterizerDiscard; }; -struct BlendState +bool operator==(const RasterizerState &a, const RasterizerState &b); +bool operator!=(const RasterizerState &a, const RasterizerState &b); + +struct BlendState final { + // This will zero-initialize the struct, including padding. + BlendState(); + BlendState(const BlendState &other); + bool blend; GLenum sourceBlendRGB; GLenum destBlendRGB; @@ -168,8 +173,15 @@ struct BlendState bool dither; }; -struct DepthStencilState +bool operator==(const BlendState &a, const BlendState &b); +bool operator!=(const BlendState &a, const BlendState &b); + +struct DepthStencilState final { + // This will zero-initialize the struct, including padding. + DepthStencilState(); + DepthStencilState(const DepthStencilState &other); + bool depthTest; GLenum depthFunc; bool depthMask; @@ -189,10 +201,17 @@ struct DepthStencilState GLuint stencilBackWritemask; }; +bool operator==(const DepthStencilState &a, const DepthStencilState &b); +bool operator!=(const DepthStencilState &a, const DepthStencilState &b); + // State from Table 6.10 (state per sampler object) -struct SamplerState +struct SamplerState final { + // This will zero-initialize the struct, including padding. SamplerState(); + SamplerState(const SamplerState &other); + + static SamplerState CreateDefaultForTarget(GLenum target); GLenum minFilter; GLenum magFilter; @@ -209,110 +228,92 @@ struct SamplerState GLenum compareMode; GLenum compareFunc; + + GLenum sRGBDecode; }; 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 +struct DrawArraysIndirectCommand { - TextureState(); - - GLenum swizzleRed; - GLenum swizzleGreen; - GLenum swizzleBlue; - GLenum swizzleAlpha; - - SamplerState samplerState; - - GLuint baseLevel; - GLuint maxLevel; - - bool immutableFormat; - GLuint immutableLevels; + GLuint count; + GLuint instanceCount; + GLuint first; + GLuint baseInstance; +}; +static_assert(sizeof(DrawArraysIndirectCommand) == 16, + "Unexpected size of DrawArraysIndirectCommand"); - // From GL_ANGLE_texture_usage - GLenum usage; +struct DrawElementsIndirectCommand +{ + GLuint count; + GLuint primCount; + GLuint firstIndex; + GLint baseVertex; + GLuint baseInstance; +}; +static_assert(sizeof(DrawElementsIndirectCommand) == 20, + "Unexpected size of DrawElementsIndirectCommand"); - bool swizzleRequired() const; +struct ImageUnit +{ + ImageUnit(); + ImageUnit(const ImageUnit &other); + ~ImageUnit(); + + BindingPointer texture; + GLint level; + GLboolean layered; + GLint layer; + GLenum access; + GLenum format; }; -bool operator==(const TextureState &a, const TextureState &b); -bool operator!=(const TextureState &a, const TextureState &b); +struct PixelStoreStateBase +{ + GLint alignment = 4; + GLint rowLength = 0; + GLint skipRows = 0; + GLint skipPixels = 0; + GLint imageHeight = 0; + GLint skipImages = 0; +}; -struct PixelUnpackState +struct PixelUnpackState : PixelStoreStateBase { - BindingPointer pixelBuffer; - GLint alignment; - GLint rowLength; - GLint skipRows; - GLint skipPixels; - GLint imageHeight; - GLint skipImages; - - PixelUnpackState() - : alignment(4), - rowLength(0), - skipRows(0), - skipPixels(0), - imageHeight(0), - skipImages(0) - {} - - PixelUnpackState(GLint alignmentIn, GLint rowLengthIn) - : alignment(alignmentIn), - rowLength(rowLengthIn), - skipRows(0), - skipPixels(0), - imageHeight(0), - skipImages(0) - {} }; -struct PixelPackState +struct PixelPackState : PixelStoreStateBase { - BindingPointer pixelBuffer; - GLint alignment; - bool reverseRowOrder; - GLint rowLength; - GLint skipRows; - GLint skipPixels; - - PixelPackState() - : alignment(4), - reverseRowOrder(false), - rowLength(0), - skipRows(0), - skipPixels(0) - {} - - explicit PixelPackState(GLint alignmentIn, bool reverseRowOrderIn) - : alignment(alignmentIn), - reverseRowOrder(reverseRowOrderIn), - rowLength(0), - skipRows(0), - skipPixels(0) - {} + bool reverseRowOrder = false; }; // Used in Program and VertexArray. -typedef std::bitset AttributesMask; +using AttributesMask = angle::BitSet; -// Use in Program -typedef std::bitset UniformBlockBindingMask; -} +// Used in Program +using UniformBlockBindingMask = angle::BitSet; + +// Used in Framebuffer +using DrawBufferMask = angle::BitSet; + +using ContextID = uintptr_t; + +constexpr size_t CUBE_FACE_COUNT = 6; + +using TextureMap = std::map>; + +template +using AttachmentArray = std::array; + +template +using DrawBuffersArray = std::array; + +} // namespace gl namespace rx { -enum VendorID : uint32_t -{ - 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) @@ -354,12 +355,12 @@ inline DestT *GetImplAs(SrcT *src) } template -inline const DestT *GetImplAs(const SrcT *src) +inline DestT *SafeGetImplAs(SrcT *src) { - return GetAs(src->getImplementation()); + return src != nullptr ? GetAs(src->getImplementation()) : nullptr; } -} +} // namespace rx #include "angletypes.inl" @@ -407,6 +408,80 @@ inline GLenum FramebufferBindingToEnum(FramebufferBinding binding) return GL_NONE; } } -} + +template +class DestroyThenDelete +{ + public: + DestroyThenDelete(const ContextT *context) : mContext(context) {} + + void operator()(ObjT *obj) + { + ANGLE_SWALLOW_ERR(obj->onDestroy(mContext)); + delete obj; + } + + private: + const ContextT *mContext; +}; + +// Helper class for wrapping an onDestroy function. +template +class UniqueObjectPointerBase : angle::NonCopyable +{ + public: + template + UniqueObjectPointerBase(const ContextT *context) : mObject(nullptr), mDeleter(context) + { + } + + template + UniqueObjectPointerBase(ObjT *obj, const ContextT *context) : mObject(obj), mDeleter(context) + { + } + + ~UniqueObjectPointerBase() + { + if (mObject) + { + mDeleter(mObject); + } + } + + ObjT *operator->() const { return mObject; } + + ObjT *release() + { + auto obj = mObject; + mObject = nullptr; + return obj; + } + + ObjT *get() const { return mObject; } + + void reset(ObjT *obj) + { + if (mObject) + { + mDeleter(mObject); + } + mObject = obj; + } + + private: + ObjT *mObject; + DeleterT mDeleter; +}; + +template +using UniqueObjectPointer = UniqueObjectPointerBase>; + +} // namespace angle + +namespace gl +{ +class ContextState; + +} // namespace gl #endif // LIBANGLE_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.inl b/src/3rdparty/angle/src/libANGLE/angletypes.inl index d51bcaaa78..3fbe0747d2 100644 --- a/src/3rdparty/angle/src/libANGLE/angletypes.inl +++ b/src/3rdparty/angle/src/libANGLE/angletypes.inl @@ -9,21 +9,6 @@ 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 && @@ -39,16 +24,7 @@ inline bool operator!=(const Rectangle &a, const Rectangle &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; + return memcmp(&a, &b, sizeof(SamplerState)) == 0; } inline bool operator!=(const SamplerState &a, const SamplerState &b) @@ -56,23 +32,4 @@ 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); -} - -} +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h b/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h new file mode 100644 index 0000000000..14b5e3c1b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/entry_points_enum_autogen.h @@ -0,0 +1,336 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_enum_autogen.h: +// Defines the GLES entry points enumeration. + +#ifndef LIBGLESV2_ENTRYPOINTSENUM_AUTOGEN_H_ +#define LIBGLESV2_ENTRYPOINTSENUM_AUTOGEN_H_ + +namespace gl +{ +enum class EntryPoint +{ + Invalid, + ActiveTexture, + AttachShader, + BindAttribLocation, + BindBuffer, + BindFramebuffer, + BindRenderbuffer, + BindTexture, + BlendColor, + BlendEquation, + BlendEquationSeparate, + BlendFunc, + BlendFuncSeparate, + BufferData, + BufferSubData, + CheckFramebufferStatus, + Clear, + ClearColor, + ClearDepthf, + ClearStencil, + ColorMask, + CompileShader, + CompressedTexImage2D, + CompressedTexSubImage2D, + CopyTexImage2D, + CopyTexSubImage2D, + CreateProgram, + CreateShader, + CullFace, + DeleteBuffers, + DeleteFramebuffers, + DeleteProgram, + DeleteRenderbuffers, + DeleteShader, + DeleteTextures, + DepthFunc, + DepthMask, + DepthRangef, + DetachShader, + Disable, + DisableVertexAttribArray, + DrawArrays, + DrawElements, + Enable, + EnableVertexAttribArray, + Finish, + Flush, + FramebufferRenderbuffer, + FramebufferTexture2D, + FrontFace, + GenBuffers, + GenerateMipmap, + GenFramebuffers, + GenRenderbuffers, + GenTextures, + GetActiveAttrib, + GetActiveUniform, + GetAttachedShaders, + GetAttribLocation, + GetBooleanv, + GetBufferParameteriv, + GetError, + GetFloatv, + GetFramebufferAttachmentParameteriv, + GetIntegerv, + GetProgramiv, + GetProgramInfoLog, + GetRenderbufferParameteriv, + GetShaderiv, + GetShaderInfoLog, + GetShaderPrecisionFormat, + GetShaderSource, + GetString, + GetTexParameterfv, + GetTexParameteriv, + GetUniformfv, + GetUniformiv, + GetUniformLocation, + GetVertexAttribfv, + GetVertexAttribiv, + GetVertexAttribPointerv, + Hint, + IsBuffer, + IsEnabled, + IsFramebuffer, + IsProgram, + IsRenderbuffer, + IsShader, + IsTexture, + LineWidth, + LinkProgram, + PixelStorei, + PolygonOffset, + ReadPixels, + ReleaseShaderCompiler, + RenderbufferStorage, + SampleCoverage, + Scissor, + ShaderBinary, + ShaderSource, + StencilFunc, + StencilFuncSeparate, + StencilMask, + StencilMaskSeparate, + StencilOp, + StencilOpSeparate, + TexImage2D, + TexParameterf, + TexParameterfv, + TexParameteri, + TexParameteriv, + TexSubImage2D, + Uniform1f, + Uniform1fv, + Uniform1i, + Uniform1iv, + Uniform2f, + Uniform2fv, + Uniform2i, + Uniform2iv, + Uniform3f, + Uniform3fv, + Uniform3i, + Uniform3iv, + Uniform4f, + Uniform4fv, + Uniform4i, + Uniform4iv, + UniformMatrix2fv, + UniformMatrix3fv, + UniformMatrix4fv, + UseProgram, + ValidateProgram, + VertexAttrib1f, + VertexAttrib1fv, + VertexAttrib2f, + VertexAttrib2fv, + VertexAttrib3f, + VertexAttrib3fv, + VertexAttrib4f, + VertexAttrib4fv, + VertexAttribPointer, + Viewport, + ReadBuffer, + DrawRangeElements, + TexImage3D, + TexSubImage3D, + CopyTexSubImage3D, + CompressedTexImage3D, + CompressedTexSubImage3D, + GenQueries, + DeleteQueries, + IsQuery, + BeginQuery, + EndQuery, + GetQueryiv, + GetQueryObjectuiv, + UnmapBuffer, + GetBufferPointerv, + DrawBuffers, + UniformMatrix2x3fv, + UniformMatrix3x2fv, + UniformMatrix2x4fv, + UniformMatrix4x2fv, + UniformMatrix3x4fv, + UniformMatrix4x3fv, + BlitFramebuffer, + RenderbufferStorageMultisample, + FramebufferTextureLayer, + MapBufferRange, + FlushMappedBufferRange, + BindVertexArray, + DeleteVertexArrays, + GenVertexArrays, + IsVertexArray, + GetIntegeri_v, + BeginTransformFeedback, + EndTransformFeedback, + BindBufferRange, + BindBufferBase, + TransformFeedbackVaryings, + GetTransformFeedbackVarying, + VertexAttribIPointer, + GetVertexAttribIiv, + GetVertexAttribIuiv, + VertexAttribI4i, + VertexAttribI4ui, + VertexAttribI4iv, + VertexAttribI4uiv, + GetUniformuiv, + GetFragDataLocation, + Uniform1ui, + Uniform2ui, + Uniform3ui, + Uniform4ui, + Uniform1uiv, + Uniform2uiv, + Uniform3uiv, + Uniform4uiv, + ClearBufferiv, + ClearBufferuiv, + ClearBufferfv, + ClearBufferfi, + GetStringi, + CopyBufferSubData, + GetUniformIndices, + GetActiveUniformsiv, + GetUniformBlockIndex, + GetActiveUniformBlockiv, + GetActiveUniformBlockName, + UniformBlockBinding, + DrawArraysInstanced, + DrawElementsInstanced, + FenceSync, + IsSync, + DeleteSync, + ClientWaitSync, + WaitSync, + GetInteger64v, + GetSynciv, + GetInteger64i_v, + GetBufferParameteri64v, + GenSamplers, + DeleteSamplers, + IsSampler, + BindSampler, + SamplerParameteri, + SamplerParameteriv, + SamplerParameterf, + SamplerParameterfv, + GetSamplerParameteriv, + GetSamplerParameterfv, + VertexAttribDivisor, + BindTransformFeedback, + DeleteTransformFeedbacks, + GenTransformFeedbacks, + IsTransformFeedback, + PauseTransformFeedback, + ResumeTransformFeedback, + GetProgramBinary, + ProgramBinary, + ProgramParameteri, + InvalidateFramebuffer, + InvalidateSubFramebuffer, + TexStorage2D, + TexStorage3D, + GetInternalformativ, + DispatchCompute, + DispatchComputeIndirect, + DrawArraysIndirect, + DrawElementsIndirect, + FramebufferParameteri, + GetFramebufferParameteriv, + GetProgramInterfaceiv, + GetProgramResourceIndex, + GetProgramResourceName, + GetProgramResourceiv, + GetProgramResourceLocation, + UseProgramStages, + ActiveShaderProgram, + CreateShaderProgramv, + BindProgramPipeline, + DeleteProgramPipelines, + GenProgramPipelines, + IsProgramPipeline, + GetProgramPipelineiv, + ProgramUniform1i, + ProgramUniform2i, + ProgramUniform3i, + ProgramUniform4i, + ProgramUniform1ui, + ProgramUniform2ui, + ProgramUniform3ui, + ProgramUniform4ui, + ProgramUniform1f, + ProgramUniform2f, + ProgramUniform3f, + ProgramUniform4f, + ProgramUniform1iv, + ProgramUniform2iv, + ProgramUniform3iv, + ProgramUniform4iv, + ProgramUniform1uiv, + ProgramUniform2uiv, + ProgramUniform3uiv, + ProgramUniform4uiv, + ProgramUniform1fv, + ProgramUniform2fv, + ProgramUniform3fv, + ProgramUniform4fv, + ProgramUniformMatrix2fv, + ProgramUniformMatrix3fv, + ProgramUniformMatrix4fv, + ProgramUniformMatrix2x3fv, + ProgramUniformMatrix3x2fv, + ProgramUniformMatrix2x4fv, + ProgramUniformMatrix4x2fv, + ProgramUniformMatrix3x4fv, + ProgramUniformMatrix4x3fv, + ValidateProgramPipeline, + GetProgramPipelineInfoLog, + BindImageTexture, + GetBooleani_v, + MemoryBarrier, + MemoryBarrierByRegion, + TexStorage2DMultisample, + GetMultisamplefv, + SampleMaski, + GetTexLevelParameteriv, + GetTexLevelParameterfv, + BindVertexBuffer, + VertexAttribFormat, + VertexAttribIFormat, + VertexAttribBinding, + VertexBindingDivisor, + DrawElementsInstancedANGLE +}; +} // namespace gl +#endif // LIBGLESV2_ENTRY_POINTS_ENUM_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json new file mode 100644 index 0000000000..39b71fd93a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_formats.json @@ -0,0 +1,44 @@ +{ + "From ES 3.0.1 spec, table 3.15": + [ + [ "GL_ALPHA", "GL_RGBA" ], + [ "GL_LUMINANCE", "GL_RED" ], + [ "GL_LUMINANCE", "GL_RG" ], + [ "GL_LUMINANCE", "GL_RGB" ], + [ "GL_LUMINANCE", "GL_RGBA" ], + [ "GL_LUMINANCE_ALPHA", "GL_RGBA" ], + [ "GL_RED", "GL_RED" ], + [ "GL_RED", "GL_RG" ], + [ "GL_RED", "GL_RGB" ], + [ "GL_RED", "GL_RGBA" ], + [ "GL_RG", "GL_RG" ], + [ "GL_RG", "GL_RGB" ], + [ "GL_RG", "GL_RGBA" ], + [ "GL_RGB", "GL_RGB" ], + [ "GL_RGB", "GL_RGBA" ], + [ "GL_RGBA", "GL_RGBA" ] + ], + + "Necessary for ANGLE back-buffers": + [ + [ "GL_ALPHA", "GL_BGRA_EXT" ], + [ "GL_LUMINANCE", "GL_BGRA_EXT" ], + [ "GL_LUMINANCE_ALPHA", "GL_BGRA_EXT" ], + [ "GL_RED", "GL_BGRA_EXT" ], + [ "GL_RG", "GL_BGRA_EXT" ], + [ "GL_RGB", "GL_BGRA_EXT" ], + [ "GL_RGBA", "GL_BGRA_EXT" ], + [ "GL_BGRA_EXT", "GL_BGRA_EXT" ], + + [ "GL_RED_INTEGER", "GL_RED_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RG_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RED_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RG_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RG_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RGB_INTEGER", "GL_RGB_INTEGER" ], + [ "GL_RGB_INTEGER", "GL_RGBA_INTEGER" ], + [ "GL_RGBA_INTEGER", "GL_RGBA_INTEGER" ] + ] +} diff --git a/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp new file mode 100644 index 0000000000..149f79f458 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_copy_conversion_table_autogen.cpp @@ -0,0 +1,171 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_copy_conversion_table.py using data from es3_copy_conversion_formats.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// format_map: +// Determining the sized internal format from a (format,type) pair. +// Also check es3 format combinations for validity. + +#include "angle_gl.h" +#include "common/debug.h" + +namespace gl +{ + +bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat) +{ + switch (textureFormat) + { + case GL_ALPHA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + return true; + default: + break; + } + break; + + case GL_LUMINANCE: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RED: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (framebufferFormat) + { + case GL_RED_INTEGER: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + return true; + default: + break; + } + break; + + case GL_RG: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RG: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGB: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGB: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGBA: + switch (framebufferFormat) + { + case GL_BGRA_EXT: + case GL_RGBA: + return true; + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + return true; + default: + break; + } + break; + + case GL_RGB_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + return true; + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (framebufferFormat) + { + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + return true; + default: + break; + } + break; + + default: + break; + } + + return false; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json b/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json new file mode 100644 index 0000000000..fb12242e75 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/es3_format_type_combinations.json @@ -0,0 +1,171 @@ +{ + "Format combinations from ES 3.0.1 spec, table 3.2": + [ + [ "GL_RGBA8", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA4", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8_ALPHA8", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA8_SNORM", "GL_RGBA", "GL_BYTE" ], + [ "GL_RGBA4", "GL_RGBA", "GL_UNSIGNED_SHORT_4_4_4_4" ], + [ "GL_RGB10_A2", "GL_RGBA", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB5_A1", "GL_RGBA", "GL_UNSIGNED_SHORT_5_5_5_1" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_HALF_FLOAT" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_HALF_FLOAT_OES" ], + [ "GL_RGBA32F", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGBA16F", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGBA8UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA8I", "GL_RGBA_INTEGER", "GL_BYTE" ], + [ "GL_RGBA16UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RGBA16I", "GL_RGBA_INTEGER", "GL_SHORT" ], + [ "GL_RGBA32UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RGBA32I", "GL_RGBA_INTEGER", "GL_INT" ], + [ "GL_RGB10_A2UI", "GL_RGBA_INTEGER", "GL_UNSIGNED_INT_2_10_10_10_REV" ], + [ "GL_RGB8", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB565", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB8_SNORM", "GL_RGB", "GL_BYTE" ], + [ "GL_RGB565", "GL_RGB", "GL_UNSIGNED_SHORT_5_6_5" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_UNSIGNED_INT_10F_11F_11F_REV" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_UNSIGNED_INT_5_9_9_9_REV" ], + [ "GL_RGB16F", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_RGB16F", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_HALF_FLOAT" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB32F", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB16F", "GL_RGB", "GL_FLOAT" ], + [ "GL_R11F_G11F_B10F", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB9_E5", "GL_RGB", "GL_FLOAT" ], + [ "GL_RGB8UI", "GL_RGB_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB8I", "GL_RGB_INTEGER", "GL_BYTE" ], + [ "GL_RGB16UI", "GL_RGB_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RGB16I", "GL_RGB_INTEGER", "GL_SHORT" ], + [ "GL_RGB32UI", "GL_RGB_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RGB32I", "GL_RGB_INTEGER", "GL_INT" ], + [ "GL_RG8", "GL_RG", "GL_UNSIGNED_BYTE" ], + [ "GL_RG8_SNORM", "GL_RG", "GL_BYTE" ], + [ "GL_RG16F", "GL_RG", "GL_HALF_FLOAT" ], + [ "GL_RG16F", "GL_RG", "GL_HALF_FLOAT_OES" ], + [ "GL_RG32F", "GL_RG", "GL_FLOAT" ], + [ "GL_RG16F", "GL_RG", "GL_FLOAT" ], + [ "GL_RG8UI", "GL_RG_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_RG8I", "GL_RG_INTEGER", "GL_BYTE" ], + [ "GL_RG16UI", "GL_RG_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_RG16I", "GL_RG_INTEGER", "GL_SHORT" ], + [ "GL_RG32UI", "GL_RG_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_RG32I", "GL_RG_INTEGER", "GL_INT" ], + [ "GL_R8", "GL_RED", "GL_UNSIGNED_BYTE" ], + [ "GL_R8_SNORM", "GL_RED", "GL_BYTE" ], + [ "GL_R16F", "GL_RED", "GL_HALF_FLOAT" ], + [ "GL_R16F", "GL_RED", "GL_HALF_FLOAT_OES" ], + [ "GL_R32F", "GL_RED", "GL_FLOAT" ], + [ "GL_R16F", "GL_RED", "GL_FLOAT" ], + [ "GL_R8UI", "GL_RED_INTEGER", "GL_UNSIGNED_BYTE" ], + [ "GL_R8I", "GL_RED_INTEGER", "GL_BYTE" ], + [ "GL_R16UI", "GL_RED_INTEGER", "GL_UNSIGNED_SHORT" ], + [ "GL_R16I", "GL_RED_INTEGER", "GL_SHORT" ], + [ "GL_R32UI", "GL_RED_INTEGER", "GL_UNSIGNED_INT" ], + [ "GL_R32I", "GL_RED_INTEGER", "GL_INT" ] + ], + "Unsized formats": + [ + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_BYTE" ], + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_SHORT_4_4_4_4" ], + [ "GL_RGBA", "GL_RGBA", "GL_UNSIGNED_SHORT_5_5_5_1" ], + [ "GL_RGB", "GL_RGB", "GL_UNSIGNED_BYTE" ], + [ "GL_RGB", "GL_RGB", "GL_UNSIGNED_SHORT_5_6_5" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_UNSIGNED_BYTE" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB_ALPHA_EXT", "GL_SRGB_ALPHA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB_EXT", "GL_SRGB_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_RG", "GL_RG", "GL_UNSIGNED_BYTE" ], + [ "GL_RG", "GL_RG", "GL_FLOAT" ], + [ "GL_RG", "GL_RG", "GL_HALF_FLOAT" ], + [ "GL_RG", "GL_RG", "GL_HALF_FLOAT_OES" ], + [ "GL_RED", "GL_RED", "GL_UNSIGNED_BYTE" ], + [ "GL_RED", "GL_RED", "GL_FLOAT" ], + [ "GL_RED", "GL_RED", "GL_HALF_FLOAT" ], + [ "GL_RED", "GL_RED", "GL_HALF_FLOAT_OES" ], + [ "GL_DEPTH_STENCIL", "GL_DEPTH_STENCIL", "GL_UNSIGNED_INT_24_8" ] + ], + "Depth stencil formats": + [ + [ "GL_DEPTH_COMPONENT16", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_SHORT" ], + [ "GL_DEPTH_COMPONENT24", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ], + [ "GL_DEPTH_COMPONENT16", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ], + [ "GL_DEPTH_COMPONENT32F", "GL_DEPTH_COMPONENT", "GL_FLOAT" ], + [ "GL_DEPTH24_STENCIL8", "GL_DEPTH_STENCIL", "GL_UNSIGNED_INT_24_8" ], + [ "GL_DEPTH32F_STENCIL8", "GL_DEPTH_STENCIL", "GL_FLOAT_32_UNSIGNED_INT_24_8_REV" ] + ], + "From GL_EXT_sRGB": + [ + [ "GL_SRGB8_ALPHA8_EXT", "GL_SRGB_ALPHA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_SRGB8", "GL_SRGB_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_OES_texture_float": + [ + [ "GL_RGBA", "GL_RGBA", "GL_FLOAT" ], + [ "GL_RGB", "GL_RGB", "GL_FLOAT" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_FLOAT" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_FLOAT" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_FLOAT" ] + ], + "From GL_OES_texture_half_float": + [ + [ "GL_RGBA", "GL_RGBA", "GL_HALF_FLOAT_OES" ], + [ "GL_RGB", "GL_RGB", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE_ALPHA", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE", "GL_LUMINANCE", "GL_HALF_FLOAT_OES" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_ALPHA", "GL_ALPHA", "GL_HALF_FLOAT_OES" ] + ], + "From GL_EXT_texture_format_BGRA8888": + [ + [ "GL_BGRA_EXT", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_EXT_texture_storage": + [ + [ "GL_ALPHA8_EXT", "GL_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE8_EXT", "GL_LUMINANCE", "GL_UNSIGNED_BYTE" ], + [ "GL_LUMINANCE8_ALPHA8_EXT", "GL_LUMINANCE_ALPHA", "GL_UNSIGNED_BYTE" ], + [ "GL_ALPHA32F_EXT", "GL_ALPHA", "GL_FLOAT" ], + [ "GL_LUMINANCE32F_EXT", "GL_LUMINANCE", "GL_FLOAT" ], + [ "GL_LUMINANCE_ALPHA32F_EXT", "GL_LUMINANCE_ALPHA", "GL_FLOAT" ], + [ "GL_ALPHA16F_EXT", "GL_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_ALPHA16F_EXT", "GL_ALPHA", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE16F_EXT", "GL_LUMINANCE", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE16F_EXT", "GL_LUMINANCE", "GL_HALF_FLOAT_OES" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "GL_LUMINANCE_ALPHA", "GL_HALF_FLOAT_OES" ] + ], + "From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888": + [ + [ "GL_BGRA8_EXT", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_BGRA4_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT" ], + [ "GL_BGRA4_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ], + [ "GL_BGR5_A1_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT" ], + [ "GL_BGR5_A1_ANGLEX", "GL_BGRA_EXT", "GL_UNSIGNED_BYTE" ] + ], + "From GL_ANGLE_depth_texture and OES_depth_texture": + [ + [ "GL_DEPTH_COMPONENT32_OES", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT_24_8" ], + [ "GL_DEPTH_COMPONENT", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_SHORT" ], + [ "GL_DEPTH_COMPONENT", "GL_DEPTH_COMPONENT", "GL_UNSIGNED_INT" ] + ], + "From GL_EXT_texture_norm16": + [ + [ "GL_R16_EXT", "GL_RED", "GL_UNSIGNED_SHORT" ], + [ "GL_RG16_EXT", "GL_RG", "GL_UNSIGNED_SHORT" ], + [ "GL_RGB16_EXT", "GL_RGB", "GL_UNSIGNED_SHORT" ], + [ "GL_RGBA16_EXT", "GL_RGBA", "GL_UNSIGNED_SHORT" ], + [ "GL_R16_SNORM_EXT", "GL_RED", "GL_SHORT" ], + [ "GL_RG16_SNORM_EXT", "GL_RG", "GL_SHORT" ], + [ "GL_RGB16_SNORM_EXT", "GL_RGB", "GL_SHORT" ], + [ "GL_RGBA16_SNORM_EXT", "GL_RGBA", "GL_SHORT" ] + ] +} diff --git a/src/3rdparty/angle/src/libANGLE/features.h b/src/3rdparty/angle/src/libANGLE/features.h index ecf486dcf7..48a194ff0b 100644 --- a/src/3rdparty/angle/src/libANGLE/features.h +++ b/src/3rdparty/angle/src/libANGLE/features.h @@ -7,6 +7,8 @@ #ifndef LIBANGLE_FEATURES_H_ #define LIBANGLE_FEATURES_H_ +#include "common/platform.h" + #define ANGLE_DISABLED 0 #define ANGLE_ENABLED 1 @@ -50,4 +52,14 @@ #define ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION ANGLE_ENABLED #endif +// Controls if our threading code uses std::async or falls back to single-threaded operations. +// TODO(jmadill): Enable on Linux once STL chrono headers are updated. +#if !defined(ANGLE_STD_ASYNC_WORKERS) +#if defined(ANGLE_PLATFORM_WINDOWS) +#define ANGLE_STD_ASYNC_WORKERS ANGLE_ENABLED +#else +#define ANGLE_STD_ASYNC_WORKERS ANGLE_DISABLED +#endif // defined(ANGLE_PLATFORM_WINDOWS) +#endif // !defined(ANGLE_STD_ASYNC_WORKERS) + #endif // LIBANGLE_FEATURES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp b/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp new file mode 100644 index 0000000000..a7f3ebafc8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/format_map_autogen.cpp @@ -0,0 +1,1570 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_format_map.py using data from format_map_data.json. +// ES3 format info from es3_format_type_combinations.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// format_map: +// Determining the sized internal format from a (format,type) pair. +// Also check es3 format combinations for validity. + +#include "angle_gl.h" +#include "common/debug.h" + +namespace gl +{ + +GLenum GetSizedFormatInternal(GLenum format, GLenum type) +{ + switch (format) + { + case GL_ALPHA: + switch (type) + { + case GL_FLOAT: + return GL_ALPHA32F_EXT; + case GL_HALF_FLOAT: + return GL_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_ALPHA16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_ALPHA8_EXT; + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_BGRA8_EXT; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + return GL_BGR5_A1_ANGLEX; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return GL_BGRA4_ANGLEX; + case GL_UNSIGNED_SHORT_5_6_5: + return GL_BGR565_ANGLEX; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + default: + break; + } + break; + + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + default: + break; + } + break; + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + default: + break; + } + break; + + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + default: + break; + } + break; + + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_FLOAT: + return GL_DEPTH_COMPONENT32F; + case GL_UNSIGNED_INT: + return GL_DEPTH_COMPONENT32_OES; + case GL_UNSIGNED_SHORT: + return GL_DEPTH_COMPONENT16; + default: + break; + } + break; + + case GL_DEPTH_STENCIL: + switch (type) + { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return GL_DEPTH32F_STENCIL8; + case GL_UNSIGNED_INT_24_8: + return GL_DEPTH24_STENCIL8; + default: + break; + } + break; + + case GL_LUMINANCE: + switch (type) + { + case GL_FLOAT: + return GL_LUMINANCE32F_EXT; + case GL_HALF_FLOAT: + return GL_LUMINANCE16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_LUMINANCE16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_LUMINANCE8_EXT; + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_FLOAT: + return GL_LUMINANCE_ALPHA32F_EXT; + case GL_HALF_FLOAT: + return GL_LUMINANCE_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: + return GL_LUMINANCE_ALPHA16F_EXT; + case GL_UNSIGNED_BYTE: + return GL_LUMINANCE8_ALPHA8_EXT; + default: + break; + } + break; + + case GL_RED: + switch (type) + { + case GL_BYTE: + return GL_R8_SNORM; + case GL_FLOAT: + return GL_R32F; + case GL_HALF_FLOAT: + return GL_R16F; + case GL_HALF_FLOAT_OES: + return GL_R16F; + case GL_SHORT: + return GL_R16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_R8; + case GL_UNSIGNED_SHORT: + return GL_R16_EXT; + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_R8I; + case GL_INT: + return GL_R32I; + case GL_SHORT: + return GL_R16I; + case GL_UNSIGNED_BYTE: + return GL_R8UI; + case GL_UNSIGNED_INT: + return GL_R32UI; + case GL_UNSIGNED_SHORT: + return GL_R16UI; + default: + break; + } + break; + + case GL_RG: + switch (type) + { + case GL_BYTE: + return GL_RG8_SNORM; + case GL_FLOAT: + return GL_RG32F; + case GL_HALF_FLOAT: + return GL_RG16F; + case GL_HALF_FLOAT_OES: + return GL_RG16F; + case GL_SHORT: + return GL_RG16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RG8; + case GL_UNSIGNED_SHORT: + return GL_RG16_EXT; + default: + break; + } + break; + + case GL_RGB: + switch (type) + { + case GL_BYTE: + return GL_RGB8_SNORM; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + case GL_HALF_FLOAT_OES: + return GL_RGB16F; + case GL_SHORT: + return GL_RGB16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + return GL_R11F_G11F_B10F; + case GL_UNSIGNED_INT_5_9_9_9_REV: + return GL_RGB9_E5; + case GL_UNSIGNED_SHORT: + return GL_RGB16_EXT; + case GL_UNSIGNED_SHORT_5_6_5: + return GL_RGB565; + default: + break; + } + break; + + case GL_RGBA: + switch (type) + { + case GL_BYTE: + return GL_RGBA8_SNORM; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + case GL_HALF_FLOAT_OES: + return GL_RGBA16F; + case GL_SHORT: + return GL_RGBA16_SNORM_EXT; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2; + case GL_UNSIGNED_SHORT: + return GL_RGBA16_EXT; + case GL_UNSIGNED_SHORT_4_4_4_4: + return GL_RGBA4; + case GL_UNSIGNED_SHORT_5_5_5_1: + return GL_RGB5_A1; + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RGBA8I; + case GL_INT: + return GL_RGBA32I; + case GL_SHORT: + return GL_RGBA16I; + case GL_UNSIGNED_BYTE: + return GL_RGBA8UI; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2UI; + case GL_UNSIGNED_SHORT: + return GL_RGBA16UI; + default: + break; + } + break; + + case GL_RGB_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RGB8I; + case GL_INT: + return GL_RGB32I; + case GL_SHORT: + return GL_RGB16I; + case GL_UNSIGNED_BYTE: + return GL_RGB8UI; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_UNSIGNED_SHORT: + return GL_RGB16UI; + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (type) + { + case GL_BYTE: + return GL_RG8I; + case GL_INT: + return GL_RG32I; + case GL_SHORT: + return GL_RG16I; + case GL_UNSIGNED_BYTE: + return GL_RG8UI; + case GL_UNSIGNED_INT: + return GL_RG32UI; + case GL_UNSIGNED_SHORT: + return GL_RG16UI; + default: + break; + } + break; + + case GL_SRGB_ALPHA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_SRGB8_ALPHA8; + default: + break; + } + break; + + case GL_SRGB_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_SRGB8; + default: + break; + } + break; + + case GL_STENCIL: + switch (type) + { + case GL_UNSIGNED_BYTE: + return GL_STENCIL_INDEX8; + default: + break; + } + break; + + case GL_NONE: + return GL_NONE; + + default: + break; + } + + return GL_NONE; +} + +bool ValidES3Format(GLenum format) +{ + switch (format) + { + case GL_ALPHA: + case GL_BGRA_EXT: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RED: + case GL_RED_INTEGER: + case GL_RG: + case GL_RGB: + case GL_RGBA: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB_EXT: + return true; + + default: + return false; + } +} + +bool ValidES3Type(GLenum type) +{ + switch (type) + { + case GL_BYTE: + case GL_FLOAT: + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + case GL_INT: + case GL_SHORT: + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5: + return true; + + default: + return false; + } +} + +bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat) +{ + ASSERT(ValidES3Format(format) && ValidES3Type(type)); + + switch (format) + { + case GL_RGB_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RGB32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGB16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGB16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGB8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGB8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RGB32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGBA_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RGBA32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16UI: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + { + switch (internalFormat) + { + case GL_RGB10_A2UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RGBA32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_INT_10F_11F_11F_REV: + { + switch (internalFormat) + { + case GL_R11F_G11F_B10F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGB16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGB16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB8: + case GL_RGB565: + case GL_SRGB8: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_5_6_5: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB565: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RGB: + case GL_RGB32F: + case GL_RGB16F: + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGB8_SNORM: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_5_9_9_9_REV: + { + switch (internalFormat) + { + case GL_RGB9_E5: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE8_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_ALPHA: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_ALPHA: + case GL_ALPHA16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + { + switch (internalFormat) + { + case GL_RGB10_A2: + case GL_RGB5_A1: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RGBA16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_4_4_4_4: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA4: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA8: + case GL_RGB5_A1: + case GL_RGBA4: + case GL_SRGB8_ALPHA8: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGBA32F: + case GL_RGBA16F: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RGBA8_SNORM: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_5_5_5_1: + { + switch (internalFormat) + { + case GL_RGBA: + case GL_RGB5_A1: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_LUMINANCE: + switch (type) + { + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE16F_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE32F_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE8_EXT: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_LUMINANCE: + case GL_LUMINANCE16F_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RG_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_RG32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RG16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RG16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RG8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RG8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_RG32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RED_INTEGER: + switch (type) + { + case GL_INT: + { + switch (internalFormat) + { + case GL_R32I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_R16UI: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_R16I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_R8UI: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_R8I: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_R32UI: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RED: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_R16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_R16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RED: + case GL_R32F: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RED: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RED: + case GL_R16F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RED: + case GL_R8: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_R8_SNORM: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_INT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT16: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_INT_24_8: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32_OES: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_DEPTH_STENCIL: + switch (type) + { + case GL_UNSIGNED_INT_24_8: + { + switch (internalFormat) + { + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return true; + default: + break; + } + break; + } + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + { + switch (internalFormat) + { + case GL_DEPTH32F_STENCIL8: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_SRGB_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_SRGB_EXT: + case GL_SRGB8: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_SRGB_ALPHA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_RG: + switch (type) + { + case GL_UNSIGNED_SHORT: + { + switch (internalFormat) + { + case GL_RG16_EXT: + return true; + default: + break; + } + break; + } + case GL_SHORT: + { + switch (internalFormat) + { + case GL_RG16_SNORM_EXT: + return true; + default: + break; + } + break; + } + case GL_FLOAT: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG32F: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT_OES: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_HALF_FLOAT: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG16F: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_RG: + case GL_RG8: + return true; + default: + break; + } + break; + } + case GL_BYTE: + { + switch (internalFormat) + { + case GL_RG8_SNORM: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + { + switch (internalFormat) + { + case GL_BGRA4_ANGLEX: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_BYTE: + { + switch (internalFormat) + { + case GL_BGRA8_EXT: + case GL_BGRA4_ANGLEX: + case GL_BGR5_A1_ANGLEX: + case GL_BGRA_EXT: + return true; + default: + break; + } + break; + } + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + { + switch (internalFormat) + { + case GL_BGR5_A1_ANGLEX: + return true; + default: + break; + } + break; + } + default: + break; + } + break; + + default: + UNREACHABLE(); + break; + } + + return false; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/format_map_data.json b/src/3rdparty/angle/src/libANGLE/format_map_data.json new file mode 100644 index 0000000000..a4f1c98b4d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/format_map_data.json @@ -0,0 +1,142 @@ +{ + "GL_RGBA": { + "GL_UNSIGNED_BYTE": "GL_RGBA8", + "GL_UNSIGNED_SHORT": "GL_RGBA16_EXT", + "GL_BYTE": "GL_RGBA8_SNORM", + "GL_SHORT": "GL_RGBA16_SNORM_EXT", + "GL_UNSIGNED_SHORT_4_4_4_4": "GL_RGBA4", + "GL_UNSIGNED_SHORT_5_5_5_1": "GL_RGB5_A1", + "GL_UNSIGNED_INT_2_10_10_10_REV": "GL_RGB10_A2", + "GL_FLOAT": "GL_RGBA32F", + "GL_HALF_FLOAT": "GL_RGBA16F", + "GL_HALF_FLOAT_OES": "GL_RGBA16F" + }, + "GL_RGBA_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RGBA8UI", + "GL_BYTE": "GL_RGBA8I", + "GL_UNSIGNED_SHORT": "GL_RGBA16UI", + "GL_SHORT": "GL_RGBA16I", + "GL_UNSIGNED_INT": "GL_RGBA32UI", + "GL_INT": "GL_RGBA32I", + "GL_UNSIGNED_INT_2_10_10_10_REV": "GL_RGB10_A2UI" + }, + "GL_RGB": { + "GL_UNSIGNED_BYTE": "GL_RGB8", + "GL_UNSIGNED_SHORT": "GL_RGB16_EXT", + "GL_BYTE": "GL_RGB8_SNORM", + "GL_SHORT": "GL_RGB16_SNORM_EXT", + "GL_UNSIGNED_SHORT_5_6_5": "GL_RGB565", + "GL_UNSIGNED_INT_10F_11F_11F_REV": "GL_R11F_G11F_B10F", + "GL_UNSIGNED_INT_5_9_9_9_REV": "GL_RGB9_E5", + "GL_FLOAT": "GL_RGB32F", + "GL_HALF_FLOAT": "GL_RGB16F", + "GL_HALF_FLOAT_OES": "GL_RGB16F" + }, + "GL_RGB_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RGB8UI", + "GL_BYTE": "GL_RGB8I", "GL_UNSIGNED_SHORT": "GL_RGB16UI", + "GL_SHORT": "GL_RGB16I", + "GL_UNSIGNED_INT": "GL_RGB32UI", + "GL_INT": "GL_RGB32I" + }, + "GL_RG": { + "GL_UNSIGNED_BYTE": "GL_RG8", + "GL_UNSIGNED_SHORT": "GL_RG16_EXT", + "GL_BYTE": "GL_RG8_SNORM", + "GL_SHORT": "GL_RG16_SNORM_EXT", + "GL_FLOAT": "GL_RG32F", + "GL_HALF_FLOAT": "GL_RG16F", + "GL_HALF_FLOAT_OES": "GL_RG16F" + }, + "GL_RG_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_RG8UI", + "GL_BYTE": "GL_RG8I", + "GL_UNSIGNED_SHORT": "GL_RG16UI", + "GL_SHORT": "GL_RG16I", + "GL_UNSIGNED_INT": "GL_RG32UI", + "GL_INT": "GL_RG32I" + }, + "GL_RED": { + "GL_UNSIGNED_BYTE": "GL_R8", + "GL_UNSIGNED_SHORT": "GL_R16_EXT", + "GL_BYTE": "GL_R8_SNORM", + "GL_SHORT": "GL_R16_SNORM_EXT", + "GL_FLOAT": "GL_R32F", + "GL_HALF_FLOAT": "GL_R16F", + "GL_HALF_FLOAT_OES": "GL_R16F" + }, + "GL_RED_INTEGER": { + "GL_UNSIGNED_BYTE": "GL_R8UI", + "GL_BYTE": "GL_R8I", + "GL_UNSIGNED_SHORT": "GL_R16UI", + "GL_SHORT": "GL_R16I", + "GL_UNSIGNED_INT": "GL_R32UI", + "GL_INT": "GL_R32I" + }, + "GL_LUMINANCE_ALPHA": { + "GL_UNSIGNED_BYTE": "GL_LUMINANCE8_ALPHA8_EXT", + "GL_FLOAT": "GL_LUMINANCE_ALPHA32F_EXT", + "GL_HALF_FLOAT": "GL_LUMINANCE_ALPHA16F_EXT", + "GL_HALF_FLOAT_OES": "GL_LUMINANCE_ALPHA16F_EXT" + }, + "GL_LUMINANCE": { + "GL_UNSIGNED_BYTE": "GL_LUMINANCE8_EXT", + "GL_FLOAT": "GL_LUMINANCE32F_EXT", + "GL_HALF_FLOAT": "GL_LUMINANCE16F_EXT", + "GL_HALF_FLOAT_OES": "GL_LUMINANCE16F_EXT" + }, + "GL_ALPHA": { + "GL_UNSIGNED_BYTE": "GL_ALPHA8_EXT", + "GL_FLOAT": "GL_ALPHA32F_EXT", + "GL_HALF_FLOAT": "GL_ALPHA16F_EXT", + "GL_HALF_FLOAT_OES": "GL_ALPHA16F_EXT" + }, + "GL_BGRA_EXT": { + "GL_UNSIGNED_BYTE": "GL_BGRA8_EXT", + "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": "GL_BGRA4_ANGLEX", + "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": "GL_BGR5_A1_ANGLEX", + "GL_UNSIGNED_SHORT_5_6_5": "GL_BGR565_ANGLEX" + }, + "GL_SRGB_EXT": { + "GL_UNSIGNED_BYTE": "GL_SRGB8" + }, + "GL_SRGB_ALPHA_EXT": { + "GL_UNSIGNED_BYTE": "GL_SRGB8_ALPHA8" + }, + "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGB_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE" + }, + "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE" + }, + "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT" + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT": { + "GL_UNSIGNED_BYTE": "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT" + }, + "GL_DEPTH_COMPONENT": { + "GL_UNSIGNED_SHORT": "GL_DEPTH_COMPONENT16", + "GL_UNSIGNED_INT": "GL_DEPTH_COMPONENT32_OES", + "GL_FLOAT": "GL_DEPTH_COMPONENT32F" + }, + "GL_STENCIL": { + "GL_UNSIGNED_BYTE": "GL_STENCIL_INDEX8" + }, + "GL_DEPTH_STENCIL": { + "GL_UNSIGNED_INT_24_8": "GL_DEPTH24_STENCIL8", + "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": "GL_DEPTH32F_STENCIL8" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.cpp b/src/3rdparty/angle/src/libANGLE/formatutils.cpp index f8b9a8bab8..67bb2efdea 100644 --- a/src/3rdparty/angle/src/libANGLE/formatutils.cpp +++ b/src/3rdparty/angle/src/libANGLE/formatutils.cpp @@ -6,11 +6,13 @@ // formatutils.cpp: Queries for GL image formats. -#include "common/mathutil.h" #include "libANGLE/formatutils.h" + +#include "common/mathutil.h" #include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" -#include "libANGLE/renderer/Renderer.h" + +using namespace angle; namespace gl { @@ -18,116 +20,28 @@ namespace gl // ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation // can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid // format and type combinations. +GLenum GetSizedFormatInternal(GLenum format, GLenum type); -typedef std::pair FormatTypePair; -typedef std::pair FormatPair; -typedef std::map FormatMap; - -// A helper function to insert data into the format map with fewer characters. -static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat) -{ - map->insert(FormatPair(FormatTypePair(format, type), internalFormat)); -} - -FormatMap BuildFormatMap() -{ - FormatMap map; - - // | Format | Type | Internal format | - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8); - InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2); - InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F); - InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F); - InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F); - - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI); - - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8); - InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5); - InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F); - InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F); - InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F); - - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I); - - InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8); - InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM); - InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F); - InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F); - InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F); - - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I); - - InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8); - InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM); - InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F); - InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F); - InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F); - - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I); - - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT); - InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT); - InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT); - InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT); - InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT); - InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT); - InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT); - InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT); - InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT); - - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT); - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX); - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX); - - InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8); - InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8); - - InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); - - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16); - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES); - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F); - - InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8); - - InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8); - InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8); +namespace +{ +using InternalFormatInfoMap = + std::unordered_map>; - return map; +} // anonymous namespace + +FormatType::FormatType() : format(GL_NONE), type(GL_NONE) +{ +} + +FormatType::FormatType(GLenum format_, GLenum type_) : format(format_), type(type_) +{ +} + +bool FormatType::operator<(const FormatType &other) const +{ + if (format != other.format) + return format < other.format; + return type < other.type; } Type::Type() @@ -158,20 +72,20 @@ bool operator<(const Type& a, const Type& b) } // Information about internal formats -static bool AlwaysSupported(GLuint, const Extensions &) +static bool AlwaysSupported(const Version &, const Extensions &) { return true; } -static bool NeverSupported(GLuint, const Extensions &) +static bool NeverSupported(const Version &, const Extensions &) { return false; } -template -static bool RequireES(GLuint clientVersion, const Extensions &) +template +static bool RequireES(const Version &clientVersion, const Extensions &) { - return clientVersion >= minCoreGLVersion; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion); } // Pointer to a boolean memeber of the Extensions struct @@ -179,96 +93,192 @@ typedef bool(Extensions::*ExtensionBool); // Check support for a single extension template -static bool RequireExt(GLuint, const Extensions & extensions) +static bool RequireExt(const Version &, const Extensions &extensions) { return extensions.*bool1; } // Check for a minimum client version or a single extension -template -static bool RequireESOrExt(GLuint clientVersion, const Extensions &extensions) +template +static bool RequireESOrExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || extensions.*bool1; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + extensions.*bool1; } // Check for a minimum client version or two extensions -template -static bool RequireESOrExtAndExt(GLuint clientVersion, const Extensions &extensions) +template +static bool RequireESOrExtAndExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || (extensions.*bool1 && extensions.*bool2); + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + (extensions.*bool1 && extensions.*bool2); } // Check for a minimum client version or at least one of two extensions -template -static bool RequireESOrExtOrExt(GLuint clientVersion, const Extensions &extensions) +template +static bool RequireESOrExtOrExt(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= minCoreGLVersion || extensions.*bool1 || extensions.*bool2; + return clientVersion >= Version(minCoreGLMajorVersion, minCoreGLMinorVersion) || + extensions.*bool1 || extensions.*bool2; } // Check support for two extensions template -static bool RequireExtAndExt(GLuint, const Extensions &extensions) +static bool RequireExtAndExt(const Version &, const Extensions &extensions) { return extensions.*bool1 && extensions.*bool2; } // Check support for either of two extensions template -static bool RequireExtOrExt(GLuint, const Extensions &extensions) +static bool RequireExtOrExt(const Version &, 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) +static bool HalfFloatSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || extensions.textureHalfFloat; + return clientVersion >= Version(3, 0) || extensions.textureHalfFloat; } -static bool HalfFloatRenderableSupport(GLuint clientVersion, const Extensions &extensions) +static bool HalfFloatRGBRenderableSupport(const Version &clientVersion, + const Extensions &extensions) { return HalfFloatSupport(clientVersion, extensions) && extensions.colorBufferHalfFloat; } +static bool HalfFloatRGBARenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return HalfFloatSupport(clientVersion, extensions) && + (extensions.colorBufferHalfFloat || extensions.colorBufferFloat); +} + // Special function for half float formats with one or two channels. -static bool HalfFloatSupportRG(GLuint clientVersion, const Extensions &extensions) + +// R16F, RG16F +static bool HalfFloatRGSupport(const Version &clientVersion, const Extensions &extensions) +{ + return clientVersion >= Version(3, 0) || (extensions.textureHalfFloat && extensions.textureRG); +} + +// R16F, RG16F +static bool HalfFloatRGRenderableSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || (extensions.textureHalfFloat && extensions.textureRG); + // It's unclear if EXT_color_buffer_half_float gives renderability to non-OES half float + // textures + return HalfFloatRGSupport(clientVersion, extensions) && + (extensions.colorBufferHalfFloat || extensions.colorBufferFloat); } -static bool HalfFloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions) +// RED + HALF_FLOAT_OES, RG + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRGSupport(const Version &, const Extensions &extensions) { - return HalfFloatSupportRG(clientVersion, extensions) && extensions.colorBufferHalfFloat; + return extensions.textureHalfFloat && extensions.textureRG; +} + +// RED + HALF_FLOAT_OES, RG + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRGRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedHalfFloatOESRGSupport(clientVersion, extensions) && + extensions.colorBufferHalfFloat; +} + +// RGB + HALF_FLOAT_OES, RGBA + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESSupport(const Version &clientVersion, const Extensions &extensions) +{ + return extensions.textureHalfFloat; +} + +// RGB + HALF_FLOAT_OES, RGBA + HALF_FLOAT_OES +static bool UnsizedHalfFloatOESRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedHalfFloatOESSupport(clientVersion, extensions) && extensions.colorBufferHalfFloat; } // Special function for float formats with three or four channels. -static bool FloatSupport(GLuint clientVersion, const Extensions &extensions) + +// RGB32F, RGBA32F +static bool FloatSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || extensions.textureFloat; + return clientVersion >= Version(3, 0) || extensions.textureFloat; } -static bool FloatRenderableSupport(GLuint clientVersion, const Extensions &extensions) +// RGB32F +static bool FloatRGBRenderableSupport(const Version &clientVersion, const Extensions &extensions) +{ + return FloatSupport(clientVersion, extensions) && extensions.colorBufferFloatRGB; +} + +// RGBA32F +static bool FloatRGBARenderableSupport(const Version &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); + (extensions.colorBufferFloat || extensions.colorBufferFloatRGBA); +} + +// RGB + FLOAT, RGBA + FLOAT +static bool UnsizedFloatSupport(const Version &clientVersion, const Extensions &extensions) +{ + return extensions.textureFloat; +} + +// RGB + FLOAT +static bool UnsizedFloatRGBRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedFloatSupport(clientVersion, extensions) && extensions.colorBufferFloatRGB; +} + +// RGBA + FLOAT +static bool UnsizedFloatRGBARenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return UnsizedFloatSupport(clientVersion, extensions) && + (extensions.colorBufferFloatRGBA || extensions.colorBufferFloat); } // Special function for float formats with one or two channels. -static bool FloatSupportRG(GLuint clientVersion, const Extensions &extensions) + +// R32F, RG32F +static bool FloatRGSupport(const Version &clientVersion, const Extensions &extensions) +{ + return clientVersion >= Version(3, 0) || (extensions.textureFloat && extensions.textureRG); +} + +// R32F, RG32F +static bool FloatRGRenderableSupport(const Version &clientVersion, const Extensions &extensions) { - return clientVersion >= 3 || (extensions.textureFloat && extensions.textureRG); + return FloatRGSupport(clientVersion, extensions) && extensions.colorBufferFloat; } -static bool FloatRenderableSupportRG(GLuint clientVersion, const Extensions &extensions) +// RED + FLOAT, RG + FLOAT +static bool UnsizedFloatRGSupport(const Version &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); + return extensions.textureFloat && extensions.textureRG; +} + +// RED + FLOAT, RG + FLOAT +static bool UnsizedFloatRGRenderableSupport(const Version &clientVersion, + const Extensions &extensions) +{ + return FloatRGSupport(clientVersion, extensions) && extensions.colorBufferFloat; } InternalFormat::InternalFormat() - : redBits(0), + : internalFormat(GL_NONE), + sized(false), + sizedInternalFormat(GL_NONE), + redBits(0), greenBits(0), blueBits(0), luminanceBits(0), @@ -291,32 +301,252 @@ InternalFormat::InternalFormat() { } -static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +InternalFormat::InternalFormat(const InternalFormat &other) = default; + +bool InternalFormat::isLUMA() const { - InternalFormat formatInfo; - formatInfo.format = format; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; + return ((redBits + greenBits + blueBits + depthBits + stencilBits) == 0 && + (luminanceBits + alphaBits) > 0); +} + +GLenum InternalFormat::getReadPixelsFormat() const +{ + return format; } -static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared, - GLenum format, GLenum type, GLenum componentType, bool srgb, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +GLenum InternalFormat::getReadPixelsType(const Version &version) const +{ + switch (type) + { + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + if (version < Version(3, 0)) + { + // The internal format may have a type of GL_HALF_FLOAT but when exposing this type + // as the IMPLEMENTATION_READ_TYPE, only HALF_FLOAT_OES is allowed by + // OES_texture_half_float. HALF_FLOAT becomes core in ES3 and is acceptable to use + // as an IMPLEMENTATION_READ_TYPE. + return GL_HALF_FLOAT_OES; + } + else + { + return GL_HALF_FLOAT; + } + + default: + return type; + } +} + +bool InternalFormat::isRequiredRenderbufferFormat(const Version &version) const +{ + // GLES 3.0.5 section 4.4.2.2: + // "Implementations are required to support the same internal formats for renderbuffers as the + // required formats for textures enumerated in section 3.8.3.1, with the exception of the color + // formats labelled "texture-only"." + if (!sized || compressed) + { + return false; + } + + // Luma formats. + if (isLUMA()) + { + return false; + } + + // Depth/stencil formats. + if (depthBits > 0 || stencilBits > 0) + { + // GLES 2.0.25 table 4.5. + // GLES 3.0.5 section 3.8.3.1. + // GLES 3.1 table 8.14. + + // Required formats in all versions. + switch (internalFormat) + { + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + // Note that STENCIL_INDEX8 is not mentioned in GLES 3.0.5 section 3.8.3.1, but it + // is in section 4.4.2.2. + return true; + default: + break; + } + if (version.major < 3) + { + return false; + } + // Required formats in GLES 3.0 and up. + switch (internalFormat) + { + case GL_DEPTH_COMPONENT32F: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH32F_STENCIL8: + case GL_DEPTH24_STENCIL8: + return true; + default: + return false; + } + } + + // RGBA formats. + // GLES 2.0.25 table 4.5. + // GLES 3.0.5 section 3.8.3.1. + // GLES 3.1 table 8.13. + + // Required formats in all versions. + switch (internalFormat) + { + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + return true; + default: + break; + } + if (version.major < 3) + { + return false; + } + + if (format == GL_BGRA_EXT) + { + return false; + } + + switch (componentType) + { + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + return false; + case GL_UNSIGNED_INT: + case GL_INT: + // Integer RGB formats are not required renderbuffer formats. + if (alphaBits == 0 && blueBits != 0) + { + return false; + } + // All integer R and RG formats are required. + // Integer RGBA formats including RGB10_A2_UI are required. + return true; + case GL_UNSIGNED_NORMALIZED: + if (internalFormat == GL_SRGB8) + { + return false; + } + return true; + default: + UNREACHABLE(); + return false; + } +} + +Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat)) +{ +} + +Format::Format(const InternalFormat &internalFormat) : info(&internalFormat) +{ +} + +Format::Format(GLenum internalFormat, GLenum type) + : info(&GetInternalFormatInfo(internalFormat, type)) +{ +} + +Format::Format(const Format &other) = default; +Format &Format::operator=(const Format &other) = default; + +bool Format::valid() const +{ + return info->internalFormat != GL_NONE; +} + +// static +bool Format::SameSized(const Format &a, const Format &b) +{ + return a.info->sizedInternalFormat == b.info->sizedInternalFormat; +} + +static GLenum EquivalentBlitInternalFormat(GLenum internalformat) +{ + // BlitFramebuffer works if the color channels are identically + // sized, even if there is a swizzle (for example, blitting from a + // multisampled RGBA8 renderbuffer to a BGRA8 texture). This could + // be expanded and/or autogenerated if that is found necessary. + if (internalformat == GL_BGRA8_EXT) + return GL_RGBA8; + return internalformat; +} + +// static +bool Format::EquivalentForBlit(const Format &a, const Format &b) +{ + return (EquivalentBlitInternalFormat(a.info->sizedInternalFormat) == + EquivalentBlitInternalFormat(b.info->sizedInternalFormat)); +} + +// static +Format Format::Invalid() +{ + static Format invalid(GL_NONE, GL_NONE); + return invalid; +} + +std::ostream &operator<<(std::ostream &os, const Format &fmt) +{ + // TODO(ynovikov): return string representation when available + return FmtHexShort(os, fmt.info->sizedInternalFormat); +} + +bool InternalFormat::operator==(const InternalFormat &other) const +{ + // We assume all internal formats are unique if they have the same internal format and type + return internalFormat == other.internalFormat && type == other.type; +} + +bool InternalFormat::operator!=(const InternalFormat &other) const +{ + return !(*this == other); +} + +void InsertFormatInfo(InternalFormatInfoMap *map, const InternalFormat &formatInfo) +{ + ASSERT(!formatInfo.sized || (*map).count(formatInfo.internalFormat) == 0); + ASSERT((*map)[formatInfo.internalFormat].count(formatInfo.type) == 0); + (*map)[formatInfo.internalFormat][formatInfo.type] = formatInfo; +} + +void AddRGBAFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + GLuint red, + GLuint green, + GLuint blue, + GLuint alpha, + GLuint shared, + GLenum format, + GLenum type, + GLenum componentType, + bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); formatInfo.redBits = red; formatInfo.greenBits = green; formatInfo.blueBits = blue; formatInfo.alphaBits = alpha; formatInfo.sharedBits = shared; formatInfo.pixelBytes = (red + green + blue + alpha + shared) / 8; - formatInfo.componentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.componentCount = + ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); formatInfo.format = format; formatInfo.type = type; formatInfo.componentType = componentType; @@ -324,15 +554,27 @@ static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint a formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, formatInfo); } -static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +static void AddLUMAFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + GLuint luminance, + GLuint alpha, + GLenum format, + GLenum type, + GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); formatInfo.luminanceBits = luminance; formatInfo.alphaBits = alpha; formatInfo.pixelBytes = (luminance + alpha) / 8; @@ -344,15 +586,28 @@ static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, formatInfo); } -static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format, - GLenum type, GLenum componentType, InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +void AddDepthStencilFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + bool sized, + GLuint depthBits, + GLuint stencilBits, + GLuint unusedBits, + GLenum format, + GLenum type, + GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = sized; + formatInfo.sizedInternalFormat = + sized ? internalFormat : GetSizedFormatInternal(internalFormat, type); formatInfo.depthBits = depthBits; formatInfo.stencilBits = stencilBits; formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8; @@ -364,16 +619,27 @@ static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, G formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; + + InsertFormatInfo(map, formatInfo); } -static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize, - GLuint componentCount, GLenum format, GLenum type, bool srgb, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) +void AddCompressedFormat(InternalFormatInfoMap *map, + GLenum internalFormat, + GLuint compressedBlockWidth, + GLuint compressedBlockHeight, + GLuint compressedBlockSize, + GLuint componentCount, + GLenum format, + GLenum type, + bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) { InternalFormat formatInfo; + formatInfo.internalFormat = internalFormat; + formatInfo.sized = true; + formatInfo.sizedInternalFormat = internalFormat; formatInfo.compressedBlockWidth = compressedBlockWidth; formatInfo.compressedBlockHeight = compressedBlockHeight; formatInfo.pixelBytes = compressedBlockSize / 8; @@ -386,189 +652,279 @@ static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compr formatInfo.textureSupport = textureSupport; formatInfo.renderSupport = renderSupport; formatInfo.filterSupport = filterSupport; - return formatInfo; -} -typedef std::pair InternalFormatInfoPair; -typedef std::map InternalFormatInfoMap; + InsertFormatInfo(map, formatInfo); +} static InternalFormatInfoMap BuildInternalFormatInfoMap() { InternalFormatInfoMap map; - // clang-format off // From ES 3.0.1 spec, table 3.12 - map.insert(InternalFormatInfoPair(GL_NONE, InternalFormat())); - - // | Internal format | | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_R8, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_R8_SNORM, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG8, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG8_SNORM, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8_SNORM, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB565, RGBAFormat( 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA4, RGBAFormat( 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB5_A1, RGBAFormat( 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - 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>, 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))); - map.insert(InternalFormatInfoPair(GL_RGB9_E5, RGBAFormat( 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_R8I, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R8UI, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R16I, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R16UI, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R32I, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R32UI, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG8I, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG8UI, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG16I, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG16UI, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG32I, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG32UI, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8I, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8UI, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB16I, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB16UI, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB32I, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB32UI, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8I, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8UI, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA16I, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA16UI, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA32I, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA32UI, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - - map.insert(InternalFormatInfoPair(GL_BGRA8_EXT, RGBAFormat( 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - 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))); + map[GL_NONE][GL_NONE] = InternalFormat(); + + // clang-format off + + // | Internal format |sized| R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_R8, true, 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::textureRG>, RequireESOrExt<3, 0, &Extensions::textureRG>, AlwaysSupported); + AddRGBAFormat(&map, GL_R8_SNORM, true, 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG8, true, 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::textureRG>, RequireESOrExt<3, 0, &Extensions::textureRG>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG8_SNORM, true, 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB8, true, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB8_SNORM, true, 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB565, true, 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA4, true, 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB5_A1, true, 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA8, true, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, RequireESOrExt<3, 0, &Extensions::rgb8rgba8>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA8_SNORM, true, 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB10_A2, true, 10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3, 0>, RequireES<3, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB10_A2UI, true, 10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_SRGB8, true, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, 0, &Extensions::sRGB>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_SRGB8_ALPHA8, true, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, 0, &Extensions::sRGB>, RequireESOrExt<3, 0, &Extensions::sRGB>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB9_E5, true, 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_R8I, true, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R8UI, true, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R16I, true, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R16UI, true, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R32I, true, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R32UI, true, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG8I, true, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG8UI, true, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG16I, true, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG16UI, true, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RG32I, true, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_R11F_G11F_B10F, true, 11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3, 0>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG32UI, true, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGB8I, true, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB8UI, true, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB16I, true, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB16UI, true, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB32I, true, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB32UI, true, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA8I, true, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA8UI, true, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA16I, true, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA16UI, true, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA32I, true, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + AddRGBAFormat(&map, GL_RGBA32UI, true, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, RequireES<3, 0>, NeverSupported); + + AddRGBAFormat(&map, GL_BGRA8_EXT, true, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported); + AddRGBAFormat(&map, GL_BGRA4_ANGLEX, true, 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported); + AddRGBAFormat(&map, GL_BGR5_A1_ANGLEX, true, 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); + + // Special format which is not really supported, so always false for all supports. + AddRGBAFormat(&map, GL_BGR565_ANGLEX, true, 5, 6, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported); // 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, 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> ))); + // | Internal format |sized| D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + // | | | | | | | type | | | | | + AddRGBAFormat(&map, GL_R16F, true, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatRGSupport, HalfFloatRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RG16F, true, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatRGSupport, HalfFloatRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGB16F, true, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRGBRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGBA16F, true, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, HalfFloatSupport, HalfFloatRGBARenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_R32F, true, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, FloatRGSupport, FloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RG32F, true, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, FloatRGSupport, FloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB32F, true, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRGBRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGBA32F, true, 32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, FloatSupport, FloatRGBARenderableSupport, 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, 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 ))); + // | Internal format |sized| D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT16, true, 16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT24, true, 24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3, 0>, RequireES<3, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT32F, true, 32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3, 0>, RequireES<3, 0>, RequireESOrExt<3, 0, &Extensions::depthTextures>); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT32_OES, true, 32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, RequireExtOrExt<&Extensions::depthTextures, &Extensions::depth32>, AlwaysSupported ); + AddDepthStencilFormat(&map, GL_DEPTH24_STENCIL8, true, 24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, 0, &Extensions::depthTextures>, RequireESOrExtOrExt<3, 0, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported ); + AddDepthStencilFormat(&map, GL_DEPTH32F_STENCIL8, true, 32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3, 0>, RequireES<3, 0>, AlwaysSupported ); // STENCIL_INDEX8 is special-cased, see around the bottom of the list. // Luminance alpha formats - // | Internal format | | L | A | Format | Type | Component type | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT, LUMAFormat( 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT, LUMAFormat( 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT, LUMAFormat( 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT, LUMAFormat(32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT, LUMAFormat( 0, 16, GL_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT, LUMAFormat(16, 0, GL_LUMINANCE, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT, LUMAFormat( 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - - // Unsized formats - // | Internal format | | Format | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_ALPHA, UnsizedFormat(GL_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE, UnsizedFormat(GL_LUMINANCE, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, UnsizedFormat(GL_LUMINANCE_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RED, UnsizedFormat(GL_RED, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG, UnsizedFormat(GL_RG, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB, UnsizedFormat(GL_RGB, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA, UnsizedFormat(GL_RGBA, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RED_INTEGER, UnsizedFormat(GL_RED_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RG_INTEGER, UnsizedFormat(GL_RG_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RGB_INTEGER, UnsizedFormat(GL_RGB_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER, UnsizedFormat(GL_RGBA_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_BGRA_EXT, UnsizedFormat(GL_BGRA_EXT, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, UnsizedFormat(GL_DEPTH_COMPONENT, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL, UnsizedFormat(GL_DEPTH_STENCIL, RequireESOrExt<3, &Extensions::packedDepthStencil>, RequireESOrExt<3, &Extensions::packedDepthStencil>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB_EXT, UnsizedFormat(GL_RGB, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, UnsizedFormat(GL_RGBA, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); + // | Internal format |sized| L | A | Format | Type | Component type | Supported | Renderable | Filterable | + AddLUMAFormat(&map, GL_ALPHA8_EXT, true, 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_LUMINANCE8_EXT, true, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_LUMINANCE8_ALPHA8_EXT, true, 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported); + AddLUMAFormat(&map, GL_ALPHA16F_EXT, true, 0, 16, GL_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE16F_EXT, true, 16, 0, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA16F_EXT, true, 16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_ALPHA32F_EXT, true, 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE32F_EXT, true, 32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA32F_EXT, true, 32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear>); // 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, 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))); + // | Internal format |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_R11_EAC, 4, 4, 64, 1, GL_RED, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SIGNED_R11_EAC, 4, 4, 64, 1, GL_RED, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RG11_EAC, 4, 4, 128, 2, GL_RG, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SIGNED_RG11_EAC, 4, 4, 128, 2, GL_RG, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireES<3, 0>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireES<3, 0>, 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 | + AddCompressedFormat(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 64, 4, GL_RGBA, 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))); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT3>, 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))); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, 4, 4, 128, 4, GL_RGBA, 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))); + AddCompressedFormat(&map, GL_ETC1_RGB8_OES, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::compressedETC1RGB8Texture>, NeverSupported, AlwaysSupported); + + // From GL_EXT_texture_compression_s3tc_srgb + // | Internal format |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 4, 4, 64, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::textureCompressionS3TCsRGB>, 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))); + // | Internal format | W | H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, 5, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, 5, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, 6, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, 6, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, 8, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, 8, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, 8, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, 10, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, 10, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, 10, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, 10, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, 12, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, 12, 12, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, 4, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, 5, 4, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, 5, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, 6, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, 6, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, 8, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, 8, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, 8, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, 10, 5, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, 10, 6, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, 10, 8, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 10, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 12, 10, 128, 4, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExtOrExt<&Extensions::textureCompressionASTCHDR, &Extensions::textureCompressionASTCLDR>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 12, 12, 128, 4, GL_RGBA, 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 // - All other stencil formats (all depth-stencil) are either float or normalized // - It affects only validation of internalformat in RenderbufferStorageMultisample. - // | 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))); + // | Internal format |sized|D |S |X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_STENCIL_INDEX8, true, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, 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))); + // | Internal format |W |H |BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + AddCompressedFormat(&map, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGB, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGBA, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + AddCompressedFormat(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, 4, 4, 64, 3, GL_RGBA, GL_UNSIGNED_BYTE, true, RequireExt<&Extensions::lossyETCDecode>, NeverSupported, AlwaysSupported); + + // From GL_EXT_texture_norm16 + // | Internal format |sized| R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_R16_EXT, true, 16, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_R16_SNORM_EXT, true, 16, 0, 0, 0, 0, GL_RED, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG16_EXT, true, 16, 16, 0, 0, 0, GL_RG, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_RG16_SNORM_EXT, true, 16, 16, 0, 0, 0, GL_RG, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB16_EXT, true, 16, 16, 16, 0, 0, GL_RGB, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB16_SNORM_EXT, true, 16, 16, 16, 0, 0, GL_RGB, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA16_EXT, true, 16, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, RequireExt<&Extensions::textureNorm16>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA16_SNORM_EXT, true, 16, 16, 16, 16, 0, GL_RGBA, GL_SHORT, GL_SIGNED_NORMALIZED, false, RequireExt<&Extensions::textureNorm16>, NeverSupported, AlwaysSupported); + // Unsized formats + // | Internal format |sized | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED, false, 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureRG>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RED, false, 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RG, false, 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureRG>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RG, false, 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, AlwaysSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB, false, 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddRGBAFormat(&map, GL_RGBA, false, 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_SRGB, false, 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, NeverSupported, AlwaysSupported); + AddRGBAFormat(&map, GL_SRGB_ALPHA_EXT, false, 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, RequireExt<&Extensions::sRGB>, AlwaysSupported); + + AddRGBAFormat(&map, GL_BGRA_EXT, false, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported); + + // Unsized integer formats + // |Internal format |sized | R | G | B | A |S | Format | Type | Component type | SRGB | Texture | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED_INTEGER, false, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RED_INTEGER, false, 32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RG_INTEGER, false, 32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGB_INTEGER, false, 32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + AddRGBAFormat(&map, GL_RGBA_INTEGER, false, 10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3, 0>, NeverSupported, NeverSupported); + + // Unsized floating point formats + // |Internal format |sized | R | G | B | A |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RED, false, 16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESRGSupport, UnsizedHalfFloatOESRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RG, false, 16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESRGSupport, UnsizedHalfFloatOESRGRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGB, false, 16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESSupport, UnsizedHalfFloatOESRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RGBA, false, 16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT_OES, GL_FLOAT, false, UnsizedHalfFloatOESSupport, UnsizedHalfFloatOESRenderableSupport, RequireESOrExt<3, 0, &Extensions::textureHalfFloatLinear>); + AddRGBAFormat(&map, GL_RED, false, 32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, UnsizedFloatRGSupport, UnsizedFloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RG, false, 32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, UnsizedFloatRGSupport, UnsizedFloatRGRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB, false, 32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, UnsizedFloatSupport, UnsizedFloatRGBRenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + AddRGBAFormat(&map, GL_RGB, false, 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGB, false, 11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, NeverSupported, NeverSupported, NeverSupported ); + AddRGBAFormat(&map, GL_RGBA, false, 32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, UnsizedFloatSupport, UnsizedFloatRGBARenderableSupport, RequireExt<&Extensions::textureFloatLinear> ); + + // Unsized luminance alpha formats + // | Internal format |sized | L | A | Format | Type | Component type | Supported | Renderable | Filterable | + AddLUMAFormat(&map, GL_ALPHA, false, 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_LUMINANCE, false, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA, false, 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, NeverSupported, AlwaysSupported ); + AddLUMAFormat(&map, GL_ALPHA, false, 0, 16, GL_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE, false, 16, 0, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA ,false, 16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_FLOAT, RequireExt<&Extensions::textureHalfFloat>, NeverSupported, RequireExt<&Extensions::textureHalfFloatLinear>); + AddLUMAFormat(&map, GL_ALPHA, false, 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + AddLUMAFormat(&map, GL_LUMINANCE, false, 32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + AddLUMAFormat(&map, GL_LUMINANCE_ALPHA, false, 32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExt<&Extensions::textureFloat>, NeverSupported, RequireExt<&Extensions::textureFloatLinear> ); + + // Unsized depth stencil formats + // | Internal format |sized | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_COMPONENT, false, 32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<2, 0>, RequireES<2, 0>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_STENCIL, false, 24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_DEPTH_STENCIL, false, 32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, RequireESOrExt<3, 0, &Extensions::packedDepthStencil>, AlwaysSupported); + AddDepthStencilFormat(&map, GL_STENCIL, false, 0, 8, 0, GL_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2, 0>, RequireES<2, 0>, NeverSupported); // clang-format on return map; @@ -584,12 +940,18 @@ static FormatSet BuildAllSizedInternalFormatSet() { FormatSet result; - const InternalFormatInfoMap &formats = GetInternalFormatMap(); - for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) + for (const auto &internalFormat : GetInternalFormatMap()) { - if (i->second.pixelBytes > 0) + for (const auto &type : internalFormat.second) { - result.insert(i->first); + if (type.second.sized) + { + // TODO(jmadill): Fix this hack. + if (internalFormat.first == GL_BGR565_ANGLEX) + continue; + + result.insert(internalFormat.first); + } } } @@ -652,107 +1014,199 @@ const Type &GetTypeInfo(GLenum type) } } -const InternalFormat GetInternalFormatInfo(GLenum internalFormat) +const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat) { + static const InternalFormat defaultInternalFormat; const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); - InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat); - if (iter != formatMap.end()) + auto iter = formatMap.find(internalFormat); + + // Sized internal formats only have one type per entry + if (iter == formatMap.end() || iter->second.size() != 1) { - return iter->second; + return defaultInternalFormat; } - else + + const InternalFormat &internalFormatInfo = iter->second.begin()->second; + if (!internalFormatInfo.sized) { - static const InternalFormat defaultInternalFormat; return defaultInternalFormat; } + + return internalFormatInfo; } -GLuint InternalFormat::computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type) { - ASSERT(alignment > 0 && isPow2(alignment)); - GLuint rowBytes; - if (rowLength > 0) + static const InternalFormat defaultInternalFormat; + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + + auto internalFormatIter = formatMap.find(internalFormat); + if (internalFormatIter == formatMap.end()) { - ASSERT(!compressed); - rowBytes = pixelBytes * rowLength; + return defaultInternalFormat; } - else + + // If the internal format is sized, simply return it without the type check. + if (internalFormatIter->second.size() == 1 && internalFormatIter->second.begin()->second.sized) { - rowBytes = computeBlockSize(formatType, width, 1); + return internalFormatIter->second.begin()->second; } - return rx::roundUp(rowBytes, static_cast(alignment)); + + auto typeIter = internalFormatIter->second.find(type); + if (typeIter == internalFormatIter->second.end()) + { + return defaultInternalFormat; + } + + return typeIter->second; +} + +GLuint InternalFormat::computePixelBytes(GLenum formatType) const +{ + const auto &typeInfo = GetTypeInfo(formatType); + GLuint components = typeInfo.specialInterpretation ? 1u : componentCount; + return components * typeInfo.bytes; } -GLuint InternalFormat::computeDepthPitch(GLenum formatType, - GLsizei width, - GLsizei height, - GLint alignment, - GLint rowLength, - GLint imageHeight) const +ErrorOrResult InternalFormat::computeRowPitch(GLenum formatType, + GLsizei width, + GLint alignment, + GLint rowLength) const { - GLuint rows; - if (imageHeight > 0) + // Compressed images do not use pack/unpack parameters. + if (compressed) { - rows = imageHeight; + ASSERT(rowLength == 0); + return computeCompressedImageSize(Extents(width, 1, 1)); } - else + + CheckedNumeric checkedWidth(rowLength > 0 ? rowLength : width); + CheckedNumeric checkedRowBytes = checkedWidth * computePixelBytes(formatType); + + ASSERT(alignment > 0 && isPow2(alignment)); + CheckedNumeric checkedAlignment(alignment); + auto aligned = rx::roundUp(checkedRowBytes, checkedAlignment); + ANGLE_TRY_CHECKED_MATH(aligned); + return aligned.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeDepthPitch(GLsizei height, + GLint imageHeight, + GLuint rowPitch) const +{ + GLuint rows = + (imageHeight > 0 ? static_cast(imageHeight) : static_cast(height)); + CheckedNumeric checkedRowPitch(rowPitch); + + auto depthPitch = checkedRowPitch * rows; + ANGLE_TRY_CHECKED_MATH(depthPitch); + return depthPitch.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeDepthPitch(GLenum formatType, + GLsizei width, + GLsizei height, + GLint alignment, + GLint rowLength, + GLint imageHeight) const +{ + GLuint rowPitch = 0; + ANGLE_TRY_RESULT(computeRowPitch(formatType, width, alignment, rowLength), rowPitch); + return computeDepthPitch(height, imageHeight, rowPitch); +} + +ErrorOrResult InternalFormat::computeCompressedImageSize(const Extents &size) const +{ + CheckedNumeric checkedWidth(size.width); + CheckedNumeric checkedHeight(size.height); + CheckedNumeric checkedDepth(size.depth); + CheckedNumeric checkedBlockWidth(compressedBlockWidth); + CheckedNumeric checkedBlockHeight(compressedBlockHeight); + + ASSERT(compressed); + auto numBlocksWide = (checkedWidth + checkedBlockWidth - 1u) / checkedBlockWidth; + auto numBlocksHigh = (checkedHeight + checkedBlockHeight - 1u) / checkedBlockHeight; + auto bytes = numBlocksWide * numBlocksHigh * pixelBytes * checkedDepth; + ANGLE_TRY_CHECKED_MATH(bytes); + return bytes.ValueOrDie(); +} + +ErrorOrResult InternalFormat::computeSkipBytes(GLuint rowPitch, + GLuint depthPitch, + const PixelStoreStateBase &state, + bool is3D) const +{ + CheckedNumeric checkedRowPitch(rowPitch); + CheckedNumeric checkedDepthPitch(depthPitch); + CheckedNumeric checkedSkipImages(static_cast(state.skipImages)); + CheckedNumeric checkedSkipRows(static_cast(state.skipRows)); + CheckedNumeric checkedSkipPixels(static_cast(state.skipPixels)); + CheckedNumeric checkedPixelBytes(pixelBytes); + auto checkedSkipImagesBytes = checkedSkipImages * checkedDepthPitch; + if (!is3D) { - rows = height; + checkedSkipImagesBytes = 0; } - return computeRowPitch(formatType, width, alignment, rowLength) * rows; + auto skipBytes = checkedSkipImagesBytes + checkedSkipRows * checkedRowPitch + + checkedSkipPixels * checkedPixelBytes; + ANGLE_TRY_CHECKED_MATH(skipBytes); + return skipBytes.ValueOrDie(); } -GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const +ErrorOrResult InternalFormat::computePackUnpackEndByte( + GLenum formatType, + const Extents &size, + const PixelStoreStateBase &state, + bool is3D) const { + GLuint rowPitch = 0; + ANGLE_TRY_RESULT(computeRowPitch(formatType, size.width, state.alignment, state.rowLength), + rowPitch); + + GLuint depthPitch = 0; + if (is3D) + { + ANGLE_TRY_RESULT(computeDepthPitch(size.height, state.imageHeight, rowPitch), depthPitch); + } + + CheckedNumeric checkedCopyBytes = 0; if (compressed) { - GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth; - GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight; - return (pixelBytes * numBlocksWide * numBlocksHight); + ANGLE_TRY_RESULT(computeCompressedImageSize(size), checkedCopyBytes); } - else + else if (size.height != 0 && (!is3D || size.depth != 0)) { - const Type &typeInfo = GetTypeInfo(formatType); - if (typeInfo.specialInterpretation) - { - return typeInfo.bytes * width * height; - } - else + CheckedNumeric bytes = computePixelBytes(formatType); + checkedCopyBytes += size.width * bytes; + + CheckedNumeric heightMinusOne = size.height - 1; + checkedCopyBytes += heightMinusOne * rowPitch; + + if (is3D) { - return componentCount * typeInfo.bytes * width * height; + CheckedNumeric depthMinusOne = size.depth - 1; + checkedCopyBytes += depthMinusOne * depthPitch; } } -} -GLuint InternalFormat::computeSkipPixels(GLint rowPitch, - GLint depthPitch, - GLint skipImages, - GLint skipRows, - GLint skipPixels) const -{ - return skipImages * depthPitch + skipRows * rowPitch + skipPixels * pixelBytes; + CheckedNumeric checkedSkipBytes = 0; + ANGLE_TRY_RESULT(computeSkipBytes(rowPitch, depthPitch, state, is3D), checkedSkipBytes); + + CheckedNumeric endByte = checkedCopyBytes + checkedSkipBytes; + + ANGLE_TRY_CHECKED_MATH(endByte); + return endByte.ValueOrDie(); } -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type) +GLenum GetUnsizedFormat(GLenum internalFormat) { - const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat); - if (formatInfo.pixelBytes > 0) + auto sizedFormatInfo = GetSizedInternalFormatInfo(internalFormat); + if (sizedFormatInfo.internalFormat != GL_NONE) { - return internalFormat; - } - else - { - static const FormatMap formatMap = BuildFormatMap(); - FormatMap::const_iterator iter = formatMap.find(FormatTypePair(internalFormat, type)); - if (iter != formatMap.end()) - { - return iter->second; - } - else - { - return GL_NONE; - } + return sizedFormatInfo.format; } + + return internalFormat; } const FormatSet &GetAllSizedInternalFormats() @@ -1543,6 +1997,129 @@ const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType) } } +size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType) +{ + switch (vertexFormatType) + { + case VERTEX_FORMAT_SBYTE1: + case VERTEX_FORMAT_SBYTE1_NORM: + case VERTEX_FORMAT_UBYTE1: + case VERTEX_FORMAT_UBYTE1_NORM: + case VERTEX_FORMAT_SBYTE1_INT: + case VERTEX_FORMAT_UBYTE1_INT: + return 1; + + case VERTEX_FORMAT_SBYTE2: + case VERTEX_FORMAT_SBYTE2_NORM: + case VERTEX_FORMAT_UBYTE2: + case VERTEX_FORMAT_UBYTE2_NORM: + case VERTEX_FORMAT_SBYTE2_INT: + case VERTEX_FORMAT_UBYTE2_INT: + case VERTEX_FORMAT_SSHORT1: + case VERTEX_FORMAT_SSHORT1_NORM: + case VERTEX_FORMAT_USHORT1: + case VERTEX_FORMAT_USHORT1_NORM: + case VERTEX_FORMAT_SSHORT1_INT: + case VERTEX_FORMAT_USHORT1_INT: + case VERTEX_FORMAT_HALF1: + return 2; + + case VERTEX_FORMAT_SBYTE3: + case VERTEX_FORMAT_SBYTE3_NORM: + case VERTEX_FORMAT_UBYTE3: + case VERTEX_FORMAT_UBYTE3_NORM: + case VERTEX_FORMAT_SBYTE3_INT: + case VERTEX_FORMAT_UBYTE3_INT: + return 3; + + case VERTEX_FORMAT_SBYTE4: + case VERTEX_FORMAT_SBYTE4_NORM: + case VERTEX_FORMAT_UBYTE4: + case VERTEX_FORMAT_UBYTE4_NORM: + case VERTEX_FORMAT_SBYTE4_INT: + case VERTEX_FORMAT_UBYTE4_INT: + case VERTEX_FORMAT_SSHORT2: + case VERTEX_FORMAT_SSHORT2_NORM: + case VERTEX_FORMAT_USHORT2: + case VERTEX_FORMAT_USHORT2_NORM: + case VERTEX_FORMAT_SSHORT2_INT: + case VERTEX_FORMAT_USHORT2_INT: + case VERTEX_FORMAT_SINT1: + case VERTEX_FORMAT_SINT1_NORM: + case VERTEX_FORMAT_UINT1: + case VERTEX_FORMAT_UINT1_NORM: + case VERTEX_FORMAT_SINT1_INT: + case VERTEX_FORMAT_UINT1_INT: + case VERTEX_FORMAT_HALF2: + case VERTEX_FORMAT_FIXED1: + case VERTEX_FORMAT_FLOAT1: + case VERTEX_FORMAT_SINT210: + case VERTEX_FORMAT_UINT210: + case VERTEX_FORMAT_SINT210_NORM: + case VERTEX_FORMAT_UINT210_NORM: + case VERTEX_FORMAT_SINT210_INT: + case VERTEX_FORMAT_UINT210_INT: + return 4; + + case VERTEX_FORMAT_SSHORT3: + case VERTEX_FORMAT_SSHORT3_NORM: + case VERTEX_FORMAT_USHORT3: + case VERTEX_FORMAT_USHORT3_NORM: + case VERTEX_FORMAT_SSHORT3_INT: + case VERTEX_FORMAT_USHORT3_INT: + case VERTEX_FORMAT_HALF3: + return 6; + + case VERTEX_FORMAT_SSHORT4: + case VERTEX_FORMAT_SSHORT4_NORM: + case VERTEX_FORMAT_USHORT4: + case VERTEX_FORMAT_USHORT4_NORM: + case VERTEX_FORMAT_SSHORT4_INT: + case VERTEX_FORMAT_USHORT4_INT: + case VERTEX_FORMAT_SINT2: + case VERTEX_FORMAT_SINT2_NORM: + case VERTEX_FORMAT_UINT2: + case VERTEX_FORMAT_UINT2_NORM: + case VERTEX_FORMAT_SINT2_INT: + case VERTEX_FORMAT_UINT2_INT: + case VERTEX_FORMAT_HALF4: + case VERTEX_FORMAT_FIXED2: + case VERTEX_FORMAT_FLOAT2: + return 8; + + case VERTEX_FORMAT_SINT3: + case VERTEX_FORMAT_SINT3_NORM: + case VERTEX_FORMAT_UINT3: + case VERTEX_FORMAT_UINT3_NORM: + case VERTEX_FORMAT_SINT3_INT: + case VERTEX_FORMAT_UINT3_INT: + case VERTEX_FORMAT_FIXED3: + case VERTEX_FORMAT_FLOAT3: + return 12; + + case VERTEX_FORMAT_SINT4: + case VERTEX_FORMAT_SINT4_NORM: + case VERTEX_FORMAT_UINT4: + case VERTEX_FORMAT_UINT4_NORM: + case VERTEX_FORMAT_SINT4_INT: + case VERTEX_FORMAT_UINT4_INT: + case VERTEX_FORMAT_FIXED4: + case VERTEX_FORMAT_FLOAT4: + return 16; + + case VERTEX_FORMAT_INVALID: + default: + UNREACHABLE(); + return 0; + } +} + +bool ValidES3InternalFormat(GLenum internalFormat) +{ + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + return internalFormat != GL_NONE && formatMap.find(internalFormat) != formatMap.end(); +} + VertexFormat::VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn) : type(typeIn), normalized(normalizedIn), diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.h b/src/3rdparty/angle/src/libANGLE/formatutils.h index 2165e6badd..dbfe590846 100644 --- a/src/3rdparty/angle/src/libANGLE/formatutils.h +++ b/src/3rdparty/angle/src/libANGLE/formatutils.h @@ -9,16 +9,32 @@ #ifndef LIBANGLE_FORMATUTILS_H_ #define LIBANGLE_FORMATUTILS_H_ -#include "libANGLE/Caps.h" -#include "libANGLE/angletypes.h" - -#include "angle_gl.h" - #include +#include #include +#include "angle_gl.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" +#include "libANGLE/Version.h" +#include "libANGLE/angletypes.h" + namespace gl { +struct VertexAttribute; + +struct FormatType final +{ + FormatType(); + FormatType(GLenum format_, GLenum type_); + FormatType(const FormatType &other) = default; + FormatType &operator=(const FormatType &other) = default; + + bool operator<(const FormatType &other) const; + + GLenum format; + GLenum type; +}; struct Type { @@ -30,9 +46,58 @@ struct Type }; const Type &GetTypeInfo(GLenum type); +// Information about an OpenGL internal format. Can be keyed on the internalFormat and type +// members. struct InternalFormat { InternalFormat(); + InternalFormat(const InternalFormat &other); + + GLuint computePixelBytes(GLenum formatType) const; + + ErrorOrResult computeRowPitch(GLenum formatType, + GLsizei width, + GLint alignment, + GLint rowLength) const; + ErrorOrResult computeDepthPitch(GLsizei height, + GLint imageHeight, + GLuint rowPitch) const; + ErrorOrResult computeDepthPitch(GLenum formatType, + GLsizei width, + GLsizei height, + GLint alignment, + GLint rowLength, + GLint imageHeight) const; + + ErrorOrResult computeCompressedImageSize(const Extents &size) const; + + ErrorOrResult computeSkipBytes(GLuint rowPitch, + GLuint depthPitch, + const PixelStoreStateBase &state, + bool is3D) const; + + ErrorOrResult computePackUnpackEndByte(GLenum formatType, + const Extents &size, + const PixelStoreStateBase &state, + bool is3D) const; + + bool isLUMA() const; + GLenum getReadPixelsFormat() const; + GLenum getReadPixelsType(const Version &version) const; + + // Return true if the format is a required renderbuffer format in the given version of the core + // spec. Note that it isn't always clear whether all the rules that apply to core required + // renderbuffer formats also apply to additional formats added by extensions. Because of this + // extension formats are conservatively not included. + bool isRequiredRenderbufferFormat(const Version &version) const; + + bool operator==(const InternalFormat &other) const; + bool operator!=(const InternalFormat &other) const; + + GLenum internalFormat; + + bool sized; + GLenum sizedInternalFormat; GLuint redBits; GLuint greenBits; @@ -60,28 +125,45 @@ struct InternalFormat GLenum componentType; GLenum colorEncoding; - typedef bool (*SupportCheckFunction)(GLuint, const Extensions &); + typedef bool (*SupportCheckFunction)(const Version &, const Extensions &); SupportCheckFunction textureSupport; SupportCheckFunction renderSupport; SupportCheckFunction filterSupport; +}; + +// A "Format" wraps an InternalFormat struct, querying it from either a sized internal format or +// unsized internal format and type. +// TODO(geofflang): Remove this, it doesn't add any more information than the InternalFormat object. +struct Format +{ + // Sized types only. + explicit Format(GLenum internalFormat); + + // Sized or unsized types. + explicit Format(const InternalFormat &internalFormat); + Format(GLenum internalFormat, GLenum type); + + Format(const Format &other); + Format &operator=(const Format &other); - GLuint computeRowPitch(GLenum formatType, GLsizei width, 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; + bool valid() const; + + static Format Invalid(); + static bool SameSized(const Format &a, const Format &b); + static bool EquivalentForBlit(const Format &a, const Format &b); + + friend std::ostream &operator<<(std::ostream &os, const Format &fmt); + + // This is the sized info. + const InternalFormat *info; }; -const InternalFormat GetInternalFormatInfo(GLenum internalFormat); -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type); +const InternalFormat &GetSizedInternalFormatInfo(GLenum internalFormat); +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type); + +// Strip sizing information from an internal format. Doesn't necessarily validate that the internal +// format is valid. +GLenum GetUnsizedFormat(GLenum internalFormat); typedef std::set FormatSet; const FormatSet &GetAllSizedInternalFormats(); @@ -212,9 +294,9 @@ enum VertexFormatType VERTEX_FORMAT_UINT210_INT, }; -typedef std::vector InputLayout; +typedef std::vector InputLayout; -struct VertexFormat : angle::NonCopyable +struct VertexFormat : private angle::NonCopyable { VertexFormat(GLenum typeIn, GLboolean normalizedIn, GLuint componentsIn, bool pureIntegerIn); @@ -228,6 +310,19 @@ VertexFormatType GetVertexFormatType(GLenum type, GLboolean normalized, GLuint c VertexFormatType GetVertexFormatType(const VertexAttribute &attrib); VertexFormatType GetVertexFormatType(const VertexAttribute &attrib, GLenum currentValueType); const VertexFormat &GetVertexFormatFromType(VertexFormatType vertexFormatType); +size_t GetVertexFormatTypeSize(VertexFormatType vertexFormatType); + +// Check if an internal format is ever valid in ES3. Makes no checks about support for a specific +// context. +bool ValidES3InternalFormat(GLenum internalFormat); + +// Implemented in format_map_autogen.cpp +bool ValidES3Format(GLenum format); +bool ValidES3Type(GLenum type); +bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat); + +// Implemented in es3_copy_conversion_table_autogen.cpp +bool ValidES3CopyConversion(GLenum textureFormat, GLenum framebufferFormat); } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/histogram_macros.h b/src/3rdparty/angle/src/libANGLE/histogram_macros.h index d1c952a6bd..fb428b46d2 100644 --- a/src/3rdparty/angle/src/libANGLE/histogram_macros.h +++ b/src/3rdparty/angle/src/libANGLE/histogram_macros.h @@ -41,18 +41,19 @@ #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_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ + ANGLEPlatformCurrent()->histogramCustomCounts(ANGLEPlatformCurrent(), 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) + ANGLEPlatformCurrent()->histogramBoolean(ANGLEPlatformCurrent(), name, sample) -#define ANGLE_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - ANGLEPlatformCurrent()->histogramEnumeration(name, sample, boundary_value) +#define ANGLE_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ + ANGLEPlatformCurrent()->histogramEnumeration(ANGLEPlatformCurrent(), name, sample, \ + boundary_value) #define ANGLE_HISTOGRAM_MEMORY_KB(name, sample) ANGLE_HISTOGRAM_CUSTOM_COUNTS( \ name, sample, 1000, 500000, 50) @@ -61,7 +62,7 @@ name, sample, 1, 1000, 50) #define ANGLE_HISTOGRAM_SPARSE_SLOWLY(name, sample) \ - ANGLEPlatformCurrent()->histogramSparse(name, sample) + ANGLEPlatformCurrent()->histogramSparse(ANGLEPlatformCurrent(), 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 @@ -79,29 +80,33 @@ #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_; \ +#define SCOPED_ANGLE_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \ + class ScopedHistogramTimer##key \ + { \ + public: \ + ScopedHistogramTimer##key() \ + : constructed_(ANGLEPlatformCurrent()->currentTime(ANGLEPlatformCurrent())) \ + { \ + } \ + ~ScopedHistogramTimer##key() \ + { \ + if (constructed_ == 0) \ + return; \ + auto *platform = ANGLEPlatformCurrent(); \ + double elapsed = platform->currentTime(platform) - 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_ +#endif // LIBANGLE_HISTOGRAM_MACROS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json b/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json new file mode 100644 index 0000000000..7e77de2f36 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/packed_gl_enums.json @@ -0,0 +1,35 @@ +{ + "BufferBinding": + { + "Array": "GL_ARRAY_BUFFER", + "AtomicCounter": "GL_ATOMIC_COUNTER_BUFFER", + "CopyRead": "GL_COPY_READ_BUFFER", + "CopyWrite": "GL_COPY_WRITE_BUFFER", + "DispatchIndirect": "GL_DISPATCH_INDIRECT_BUFFER", + "DrawIndirect": "GL_DRAW_INDIRECT_BUFFER", + "ElementArray": "GL_ELEMENT_ARRAY_BUFFER", + "PixelPack": "GL_PIXEL_PACK_BUFFER", + "PixelUnpack": "GL_PIXEL_UNPACK_BUFFER", + "ShaderStorage": "GL_SHADER_STORAGE_BUFFER", + "TransformFeedback": "GL_TRANSFORM_FEEDBACK_BUFFER", + "Uniform": "GL_UNIFORM_BUFFER" + }, + "BufferUsage": + { + "DynamicCopy": "GL_DYNAMIC_COPY", + "DynamicDraw": "GL_DYNAMIC_DRAW", + "DynamicRead": "GL_DYNAMIC_READ", + "StaticCopy": "GL_STATIC_COPY", + "StaticDraw": "GL_STATIC_DRAW", + "StaticRead": "GL_STATIC_READ", + "StreamCopy": "GL_STREAM_COPY", + "StreamDraw": "GL_STREAM_DRAW", + "StreamRead": "GL_STREAM_READ" + }, + "CullFaceMode": + { + "Back": "GL_BACK", + "Front": "GL_FRONT", + "FrontAndBack": "GL_FRONT_AND_BACK" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/params.cpp b/src/3rdparty/angle/src/libANGLE/params.cpp new file mode 100644 index 0000000000..a89d87e0a9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/params.cpp @@ -0,0 +1,68 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// params: +// Parameter wrapper structs for OpenGL ES. These helpers cache re-used values +// in entry point routines. + +#include "libANGLE/params.h" + +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ + +// static +constexpr ParamTypeInfo ParamsBase::TypeInfo; +constexpr ParamTypeInfo HasIndexRange::TypeInfo; + +HasIndexRange::HasIndexRange() + : ParamsBase(nullptr), mContext(nullptr), mCount(0), mType(GL_NONE), mIndices(nullptr) +{ +} + +HasIndexRange::HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices) + : ParamsBase(context), mContext(context), mCount(count), mType(type), mIndices(indices) +{ +} + +const Optional &HasIndexRange::getIndexRange() const +{ + if (mIndexRange.valid() || !mContext) + { + return mIndexRange; + } + + const State &state = mContext->getGLState(); + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + if (elementArrayBuffer) + { + uintptr_t offset = reinterpret_cast(mIndices); + IndexRange indexRange; + Error error = + elementArrayBuffer->getIndexRange(mContext, mType, static_cast(offset), mCount, + state.isPrimitiveRestartEnabled(), &indexRange); + if (error.isError()) + { + mContext->handleError(error); + return mIndexRange; + } + + mIndexRange = indexRange; + } + else + { + mIndexRange = ComputeIndexRange(mType, mIndices, mCount, state.isPrimitiveRestartEnabled()); + } + + return mIndexRange; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/params.h b/src/3rdparty/angle/src/libANGLE/params.h new file mode 100644 index 0000000000..27dba640ff --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/params.h @@ -0,0 +1,228 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// params: +// Parameter wrapper structs for OpenGL ES. These helpers cache re-used values +// in entry point routines. + +#ifndef LIBANGLE_PARAMS_H_ +#define LIBANGLE_PARAMS_H_ + +#include "angle_gl.h" +#include "common/Optional.h" +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/entry_points_enum_autogen.h" + +namespace gl +{ +class Context; + +template +struct EntryPointParam; + +template +using EntryPointParamType = typename EntryPointParam::Type; + +class ParamTypeInfo +{ + public: + constexpr ParamTypeInfo(const char *selfClass, const ParamTypeInfo *parentType) + : mSelfClass(selfClass), mParentTypeInfo(parentType) + { + } + + constexpr bool hasDynamicType(const ParamTypeInfo &typeInfo) const + { + return mSelfClass == typeInfo.mSelfClass || + (mParentTypeInfo && mParentTypeInfo->hasDynamicType(typeInfo)); + } + + constexpr bool isValid() const { return mSelfClass != nullptr; } + + private: + const char *mSelfClass; + const ParamTypeInfo *mParentTypeInfo; +}; + +#define ANGLE_PARAM_TYPE_INFO(NAME, BASENAME) \ + static constexpr ParamTypeInfo TypeInfo = {#NAME, &BASENAME::TypeInfo} + +class ParamsBase : angle::NonCopyable +{ + public: + ParamsBase(Context *context, ...){}; + + template + static void Factory(EntryPointParamType *objBuffer, ArgsT... args); + + static constexpr ParamTypeInfo TypeInfo = {nullptr, nullptr}; +}; + +// static +template +ANGLE_INLINE void ParamsBase::Factory(EntryPointParamType *objBuffer, ArgsT... args) +{ + new (objBuffer) EntryPointParamType(args...); +} + +class HasIndexRange : public ParamsBase +{ + public: + // Dummy placeholder that can't generate an index range. + HasIndexRange(); + HasIndexRange(Context *context, GLsizei count, GLenum type, const void *indices); + + template + static void Factory(HasIndexRange *objBuffer, ArgsT... args); + + const Optional &getIndexRange() const; + + ANGLE_PARAM_TYPE_INFO(HasIndexRange, ParamsBase); + + private: + Context *mContext; + GLsizei mCount; + GLenum mType; + const GLvoid *mIndices; + mutable Optional mIndexRange; +}; + +// Entry point funcs essentially re-map different entry point parameter arrays into +// the format the parameter type class expects. For example, for HasIndexRange, for the +// various indexed draw calls, they drop parameters that aren't useful and re-arrange +// the rest. +#define ANGLE_ENTRY_POINT_FUNC(NAME, CLASS, ...) \ + \ +template<> struct EntryPointParam \ + { \ + using Type = CLASS; \ + }; \ + \ +template<> inline void CLASS::Factory(__VA_ARGS__) + +ANGLE_ENTRY_POINT_FUNC(DrawElements, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices) +{ + return ParamsBase::Factory(objBuffer, context, count, type, indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawElementsInstanced, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices, + GLsizei /*instanceCount*/) +{ + return ParamsBase::Factory(objBuffer, context, count, type, + indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawElementsInstancedANGLE, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLsizei count, + GLenum type, + const void *indices, + GLsizei /*instanceCount*/) +{ + return ParamsBase::Factory(objBuffer, context, count, + type, indices); +} + +ANGLE_ENTRY_POINT_FUNC(DrawRangeElements, + HasIndexRange, + HasIndexRange *objBuffer, + Context *context, + GLenum /*mode*/, + GLuint /*start*/, + GLuint /*end*/, + GLsizei count, + GLenum type, + const void *indices) +{ + return ParamsBase::Factory(objBuffer, context, count, type, + indices); +} + +#undef ANGLE_ENTRY_POINT_FUNC + +template +struct EntryPointParam +{ + using Type = ParamsBase; +}; + +// A template struct for determining the default value to return for each entry point. +template +struct DefaultReturnValue; + +// Default return values for each basic return type. +template +struct DefaultReturnValue +{ + static constexpr GLint kValue = -1; +}; + +// This doubles as the GLenum return value. +template +struct DefaultReturnValue +{ + static constexpr GLuint kValue = 0; +}; + +template +struct DefaultReturnValue +{ + static constexpr GLboolean kValue = GL_FALSE; +}; + +// Catch-all rules for pointer types. +template +struct DefaultReturnValue +{ + static constexpr const PointerType *kValue = nullptr; +}; + +template +struct DefaultReturnValue +{ + static constexpr PointerType *kValue = nullptr; +}; + +// Overloaded to return invalid index +template <> +struct DefaultReturnValue +{ + static constexpr GLuint kValue = GL_INVALID_INDEX; +}; + +// Specialized enum error value. +template <> +struct DefaultReturnValue +{ + static constexpr GLenum kValue = GL_WAIT_FAILED; +}; + +template +constexpr ANGLE_INLINE ReturnType GetDefaultReturnValue() +{ + return DefaultReturnValue::kValue; +} + +} // namespace gl + +#endif // LIBANGLE_PARAMS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp index 3a6059a89c..78d219365e 100644 --- a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp @@ -24,18 +24,9 @@ GLint64 ExpandFloatToInteger(GLfloat value) return static_cast((static_cast(0xFFFFFFFFULL) * value - 1.0) / 2.0); } -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) +QueryT CastFromStateValueToInt(GLenum pname, NativeT value) { - GLenum queryType = GLTypeToGLenum::value; GLenum nativeType = GLTypeToGLenum::value; if (nativeType == GL_FLOAT) @@ -43,37 +34,68 @@ QueryT CastStateValueToInt(GLenum pname, NativeT value) // 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 ClampToQueryRange(ExpandFloatToInteger(static_cast(value))); + return clampCast(ExpandFloatToInteger(static_cast(value))); } else { - return gl::iround(static_cast(value)); + return clampCast(std::round(value)); } } - // Clamp 64-bit int values when casting to int - if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) + return clampCast(value); +} + +template +NativeT CastQueryValueToInt(GLenum pname, QueryT value) +{ + GLenum queryType = GLTypeToGLenum::value; + + if (queryType == GL_FLOAT) { - GLint64 minIntValue = static_cast(std::numeric_limits::min()); - GLint64 maxIntValue = static_cast(std::numeric_limits::max()); - GLint64 clampedValue = std::max(std::min(static_cast(value), maxIntValue), minIntValue); - return static_cast(clampedValue); + return static_cast(std::round(value)); } - return static_cast(value); + return static_cast(value); +} + +} // anonymous namespace + +// ES 3.10 Section 2.2.2 +// When querying bitmasks(such as SAMPLE_MASK_VALUE or STENCIL_WRITEMASK) with GetIntegerv, the +// mask value is treated as a signed integer, so that mask values with the high bit set will not be +// clamped when returned as signed integers. +GLint CastMaskValue(const Context *context, GLuint value) +{ + return (context->getClientVersion() >= Version(3, 1) ? static_cast(value) + : clampCast(value)); +} + +template +QueryT CastFromGLintStateValue(GLenum pname, InternalT value) +{ + return CastFromStateValue(pname, clampCast(value)); } +template GLfloat CastFromGLintStateValue(GLenum pname, GLenum value); +template GLint CastFromGLintStateValue(GLenum pname, GLenum value); +template GLint64 CastFromGLintStateValue(GLenum pname, GLenum value); +template GLuint CastFromGLintStateValue(GLenum pname, GLenum value); +template GLfloat CastFromGLintStateValue(GLenum pname, bool value); +template GLuint CastFromGLintStateValue(GLenum pname, bool value); +template GLint CastFromGLintStateValue(GLenum pname, bool value); + template -QueryT CastStateValue(GLenum pname, NativeT value) +QueryT CastFromStateValue(GLenum pname, NativeT value) { GLenum queryType = GLTypeToGLenum::value; switch (queryType) { case GL_INT: - return CastStateValueToInt(pname, value); case GL_INT_64_ANGLEX: - return CastStateValueToInt(pname, value); + case GL_UNSIGNED_INT: + case GL_UINT_64_ANGLEX: + return CastFromStateValueToInt(pname, value); case GL_FLOAT: return static_cast(value); case GL_BOOL: @@ -83,19 +105,50 @@ QueryT CastStateValue(GLenum pname, NativeT value) return 0; } } +template GLint CastFromStateValue(GLenum pname, GLint value); +template GLint CastFromStateValue(GLenum pname, GLint64 value); +template GLint64 CastFromStateValue(GLenum pname, GLint value); +template GLint64 CastFromStateValue(GLenum pname, GLint64 value); +template GLfloat CastFromStateValue(GLenum pname, GLint value); +template GLfloat CastFromStateValue(GLenum pname, GLfloat value); +template GLint CastFromStateValue(GLenum pname, GLfloat value); +template GLuint CastFromStateValue(GLenum pname, GLint value); +template GLuint CastFromStateValue(GLenum pname, GLuint value); +template GLint CastFromStateValue(GLenum pname, GLboolean value); +template GLint64 CastFromStateValue(GLenum pname, GLboolean value); +template GLint CastFromStateValue(GLenum pname, GLuint value); +template GLint64 CastFromStateValue(GLenum pname, GLuint value); +template GLuint64 CastFromStateValue(GLenum pname, GLuint value); -} // anonymous namespace +template +NativeT CastQueryValueTo(GLenum pname, QueryT value) +{ + GLenum nativeType = GLTypeToGLenum::value; + + switch (nativeType) + { + case GL_INT: + case GL_INT_64_ANGLEX: + case GL_UNSIGNED_INT: + case GL_UINT_64_ANGLEX: + return CastQueryValueToInt(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; + } +} -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 GLint CastQueryValueTo(GLenum pname, GLfloat value); +template GLboolean CastQueryValueTo(GLenum pname, GLint value); +template GLint CastQueryValueTo(GLenum pname, GLint value); +template GLfloat CastQueryValueTo(GLenum pname, GLint value); +template GLfloat CastQueryValueTo(GLenum pname, GLfloat value); +template GLuint CastQueryValueTo(GLenum pname, GLint value); +template GLuint CastQueryValueTo(GLenum pname, GLfloat value); template void CastStateValues(Context *context, GLenum nativeType, GLenum pname, @@ -104,17 +157,17 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, if (nativeType == GL_INT) { std::vector intParams(numParams, 0); - context->getIntegerv(pname, intParams.data()); + context->getIntegervImpl(pname, intParams.data()); for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, intParams[i]); + outParams[i] = CastFromStateValue(pname, intParams[i]); } } else if (nativeType == GL_BOOL) { std::vector boolParams(numParams, GL_FALSE); - context->getBooleanv(pname, boolParams.data()); + context->getBooleanvImpl(pname, boolParams.data()); for (unsigned int i = 0; i < numParams; ++i) { @@ -124,11 +177,11 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, else if (nativeType == GL_FLOAT) { std::vector floatParams(numParams, 0.0f); - context->getFloatv(pname, floatParams.data()); + context->getFloatvImpl(pname, floatParams.data()); for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, floatParams[i]); + outParams[i] = CastFromStateValue(pname, floatParams[i]); } } else if (nativeType == GL_INT_64_ANGLEX) @@ -138,7 +191,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, for (unsigned int i = 0; i < numParams; ++i) { - outParams[i] = CastStateValue(pname, int64Params[i]); + outParams[i] = CastFromStateValue(pname, int64Params[i]); } } else UNREACHABLE(); @@ -146,7 +199,7 @@ void CastStateValues(Context *context, GLenum nativeType, GLenum pname, // Explicit template instantiation (how we export template functions in different files) // The calls below will make CastStateValues successfully link with the GL state query types -// The GL state query API types are: bool, int, uint, float, int64 +// The GL state query API types are: bool, int, uint, float, int64, uint64 template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLboolean *); template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint *); @@ -154,4 +207,77 @@ template void CastStateValues(Context *, GLenum, GLenum, unsigned int, G template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLfloat *); template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint64 *); +template +void CastIndexedStateValues(Context *context, + GLenum nativeType, + GLenum pname, + GLuint index, + unsigned int numParams, + QueryT *outParams) +{ + if (nativeType == GL_INT) + { + std::vector intParams(numParams, 0); + context->getIntegeri_v(pname, index, intParams.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastFromStateValue(pname, intParams[i]); + } + } + else if (nativeType == GL_BOOL) + { + std::vector boolParams(numParams, GL_FALSE); + context->getBooleani_v(pname, index, boolParams.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = + (boolParams[i] == GL_FALSE ? static_cast(0) : static_cast(1)); + } + } + else if (nativeType == GL_INT_64_ANGLEX) + { + std::vector int64Params(numParams, 0); + context->getInteger64i_v(pname, index, int64Params.data()); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastFromStateValue(pname, int64Params[i]); + } + } + else + UNREACHABLE(); +} + +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLboolean *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLint *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLuint *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLfloat *); +template void CastIndexedStateValues(Context *, + GLenum, + GLenum, + GLuint index, + unsigned int, + GLint64 *); } diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.h b/src/3rdparty/angle/src/libANGLE/queryconversions.h index e0fdbe17e0..805f36cf02 100644 --- a/src/3rdparty/angle/src/libANGLE/queryconversions.h +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.h @@ -18,19 +18,100 @@ 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. +// We restrict our use to CastFromStateValue and CastQueryValueTo, where it eliminates +// duplicate parameters. template struct GLTypeToGLenum { - static GLenum value; + // static constexpr GLenum value; }; -// The GL state query API types are: bool, int, uint, float, int64 +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_INT; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_UNSIGNED_INT; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_BOOL; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_INT_64_ANGLEX; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_UINT_64_ANGLEX; +}; +template <> +struct GLTypeToGLenum +{ + static constexpr GLenum value = GL_FLOAT; +}; + +GLint CastMaskValue(const Context *context, GLuint value); + +template +QueryT CastFromGLintStateValue(GLenum pname, InternalT value); + +template +QueryT CastFromStateValue(GLenum pname, NativeT value); + +template +NativeT CastQueryValueTo(GLenum pname, QueryT value); + +template +GLenum ConvertToGLenum(GLenum pname, ParamType param) +{ + return static_cast(CastQueryValueTo(pname, param)); +} + +template +GLenum ConvertToGLenum(ParamType param) +{ + return ConvertToGLenum(GL_NONE, param); +} + +template +GLenum ConvertToGLint(ParamType param) +{ + return CastQueryValueTo(GL_NONE, param); +} + +template +bool ConvertToBool(ParamType param) +{ + return param != GL_FALSE; +} + +template +GLboolean ConvertToGLBoolean(ParamType param) +{ + return param ? GL_TRUE : GL_FALSE; +} + +// The GL state query API types are: bool, int, uint, float, int64, uint64 template void CastStateValues(Context *context, GLenum nativeType, GLenum pname, unsigned int numParams, QueryT *outParams); +// The GL state query API types are: bool, int, uint, float, int64, uint64 +template +void CastIndexedStateValues(Context *context, + GLenum nativeType, + GLenum pname, + GLuint index, + unsigned int numParams, + QueryT *outParams); } #endif // LIBANGLE_QUERY_CONVERSIONS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryutils.cpp b/src/3rdparty/angle/src/libANGLE/queryutils.cpp new file mode 100644 index 0000000000..16a989c688 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryutils.cpp @@ -0,0 +1,1916 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryutils.cpp: Utilities for querying values from GL objects + +#include "libANGLE/queryutils.h" + +#include "common/utilities.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/queryconversions.h" + +namespace gl +{ + +namespace +{ + +template +void QueryTexLevelParameterBase(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + ParamType *params) +{ + ASSERT(texture != nullptr); + const InternalFormat *info = texture->getTextureState().getImageDesc(target, level).format.info; + + switch (pname) + { + case GL_TEXTURE_RED_TYPE: + *params = CastFromGLintStateValue( + pname, info->redBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_GREEN_TYPE: + *params = CastFromGLintStateValue( + pname, info->greenBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_BLUE_TYPE: + *params = CastFromGLintStateValue( + pname, info->blueBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_ALPHA_TYPE: + *params = CastFromGLintStateValue( + pname, info->alphaBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_DEPTH_TYPE: + *params = CastFromGLintStateValue( + pname, info->depthBits ? info->componentType : GL_NONE); + break; + case GL_TEXTURE_RED_SIZE: + *params = CastFromGLintStateValue(pname, info->redBits); + break; + case GL_TEXTURE_GREEN_SIZE: + *params = CastFromGLintStateValue(pname, info->greenBits); + break; + case GL_TEXTURE_BLUE_SIZE: + *params = CastFromGLintStateValue(pname, info->blueBits); + break; + case GL_TEXTURE_ALPHA_SIZE: + *params = CastFromGLintStateValue(pname, info->alphaBits); + break; + case GL_TEXTURE_DEPTH_SIZE: + *params = CastFromGLintStateValue(pname, info->depthBits); + break; + case GL_TEXTURE_STENCIL_SIZE: + *params = CastFromGLintStateValue(pname, info->stencilBits); + break; + case GL_TEXTURE_SHARED_SIZE: + *params = CastFromGLintStateValue(pname, info->sharedBits); + break; + case GL_TEXTURE_INTERNAL_FORMAT: + *params = CastFromGLintStateValue( + pname, info->internalFormat ? info->internalFormat : GL_RGBA); + break; + case GL_TEXTURE_WIDTH: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getWidth(target, level))); + break; + case GL_TEXTURE_HEIGHT: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getHeight(target, level))); + break; + case GL_TEXTURE_DEPTH: + *params = CastFromGLintStateValue( + pname, static_cast(texture->getDepth(target, level))); + break; + case GL_TEXTURE_SAMPLES: + *params = CastFromStateValue(pname, texture->getSamples(target, level)); + break; + case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: + *params = CastFromStateValue( + pname, static_cast(texture->getFixedSampleLocations(target, level))); + break; + case GL_TEXTURE_COMPRESSED: + *params = CastFromStateValue(pname, static_cast(info->compressed)); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QueryTexParameterBase(const Texture *texture, GLenum pname, ParamType *params) +{ + ASSERT(texture != nullptr); + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = CastFromGLintStateValue(pname, texture->getMagFilter()); + break; + case GL_TEXTURE_MIN_FILTER: + *params = CastFromGLintStateValue(pname, texture->getMinFilter()); + break; + case GL_TEXTURE_WRAP_S: + *params = CastFromGLintStateValue(pname, texture->getWrapS()); + break; + case GL_TEXTURE_WRAP_T: + *params = CastFromGLintStateValue(pname, texture->getWrapT()); + break; + case GL_TEXTURE_WRAP_R: + *params = CastFromGLintStateValue(pname, texture->getWrapR()); + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + *params = CastFromGLintStateValue(pname, texture->getImmutableFormat()); + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + *params = CastFromGLintStateValue(pname, texture->getImmutableLevels()); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = CastFromGLintStateValue(pname, texture->getUsage()); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + *params = CastFromStateValue(pname, texture->getMaxAnisotropy()); + break; + case GL_TEXTURE_SWIZZLE_R: + *params = CastFromGLintStateValue(pname, texture->getSwizzleRed()); + break; + case GL_TEXTURE_SWIZZLE_G: + *params = CastFromGLintStateValue(pname, texture->getSwizzleGreen()); + break; + case GL_TEXTURE_SWIZZLE_B: + *params = CastFromGLintStateValue(pname, texture->getSwizzleBlue()); + break; + case GL_TEXTURE_SWIZZLE_A: + *params = CastFromGLintStateValue(pname, texture->getSwizzleAlpha()); + break; + case GL_TEXTURE_BASE_LEVEL: + *params = CastFromGLintStateValue(pname, texture->getBaseLevel()); + break; + case GL_TEXTURE_MAX_LEVEL: + *params = CastFromGLintStateValue(pname, texture->getMaxLevel()); + break; + case GL_TEXTURE_MIN_LOD: + *params = CastFromStateValue(pname, texture->getSamplerState().minLod); + break; + case GL_TEXTURE_MAX_LOD: + *params = CastFromStateValue(pname, texture->getSamplerState().maxLod); + break; + case GL_TEXTURE_COMPARE_MODE: + *params = CastFromGLintStateValue(pname, texture->getCompareMode()); + break; + case GL_TEXTURE_COMPARE_FUNC: + *params = CastFromGLintStateValue(pname, texture->getCompareFunc()); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + *params = CastFromGLintStateValue(pname, texture->getSRGBDecode()); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const ParamType *params) +{ + ASSERT(texture != nullptr); + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + texture->setWrapS(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_T: + texture->setWrapT(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_R: + texture->setWrapR(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_FILTER: + texture->setMinFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAG_FILTER: + texture->setMagFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_USAGE_ANGLE: + texture->setUsage(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + texture->setMaxAnisotropy(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_MODE: + texture->setCompareMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_FUNC: + texture->setCompareFunc(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_R: + texture->setSwizzleRed(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_G: + texture->setSwizzleGreen(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_B: + texture->setSwizzleBlue(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SWIZZLE_A: + texture->setSwizzleAlpha(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_BASE_LEVEL: + { + context->handleError(texture->setBaseLevel( + context, clampCast(CastQueryValueTo(pname, params[0])))); + break; + } + case GL_TEXTURE_MAX_LEVEL: + texture->setMaxLevel(clampCast(CastQueryValueTo(pname, params[0]))); + break; + case GL_TEXTURE_MIN_LOD: + texture->setMinLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_MAX_LOD: + texture->setMaxLod(CastQueryValueTo(pname, params[0])); + break; + case GL_DEPTH_STENCIL_TEXTURE_MODE: + texture->setDepthStencilTextureMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + texture->setSRGBDecode(ConvertToGLenum(pname, params[0])); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QuerySamplerParameterBase(const Sampler *sampler, GLenum pname, ParamType *params) +{ + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: + *params = CastFromGLintStateValue(pname, sampler->getMinFilter()); + break; + case GL_TEXTURE_MAG_FILTER: + *params = CastFromGLintStateValue(pname, sampler->getMagFilter()); + break; + case GL_TEXTURE_WRAP_S: + *params = CastFromGLintStateValue(pname, sampler->getWrapS()); + break; + case GL_TEXTURE_WRAP_T: + *params = CastFromGLintStateValue(pname, sampler->getWrapT()); + break; + case GL_TEXTURE_WRAP_R: + *params = CastFromGLintStateValue(pname, sampler->getWrapR()); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + *params = CastFromStateValue(pname, sampler->getMaxAnisotropy()); + break; + case GL_TEXTURE_MIN_LOD: + *params = CastFromStateValue(pname, sampler->getMinLod()); + break; + case GL_TEXTURE_MAX_LOD: + *params = CastFromStateValue(pname, sampler->getMaxLod()); + break; + case GL_TEXTURE_COMPARE_MODE: + *params = CastFromGLintStateValue(pname, sampler->getCompareMode()); + break; + case GL_TEXTURE_COMPARE_FUNC: + *params = CastFromGLintStateValue(pname, sampler->getCompareFunc()); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + *params = CastFromGLintStateValue(pname, sampler->getSRGBDecode()); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void SetSamplerParameterBase(Sampler *sampler, GLenum pname, const ParamType *params) +{ + switch (pname) + { + case GL_TEXTURE_WRAP_S: + sampler->setWrapS(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_T: + sampler->setWrapT(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_WRAP_R: + sampler->setWrapR(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_FILTER: + sampler->setMinFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAG_FILTER: + sampler->setMagFilter(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + sampler->setMaxAnisotropy(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_MODE: + sampler->setCompareMode(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_COMPARE_FUNC: + sampler->setCompareFunc(ConvertToGLenum(pname, params[0])); + break; + case GL_TEXTURE_MIN_LOD: + sampler->setMinLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_MAX_LOD: + sampler->setMaxLod(CastQueryValueTo(pname, params[0])); + break; + case GL_TEXTURE_SRGB_DECODE_EXT: + sampler->setSRGBDecode(ConvertToGLenum(pname, params[0])); + break; + default: + UNREACHABLE(); + break; + } +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +template +void QueryVertexAttribBase(const VertexAttribute &attrib, + const VertexBinding &binding, + const CurrentDataType (¤tValueData)[CurrentValueCount], + GLenum pname, + ParamType *params) +{ + switch (pname) + { + case GL_CURRENT_VERTEX_ATTRIB: + for (size_t i = 0; i < CurrentValueCount; ++i) + { + params[i] = CastFromStateValue(pname, currentValueData[i]); + } + break; + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = CastFromStateValue(pname, static_cast(attrib.enabled)); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = CastFromGLintStateValue(pname, attrib.size); + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = CastFromGLintStateValue(pname, attrib.vertexAttribArrayStride); + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = CastFromGLintStateValue(pname, attrib.type); + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = CastFromStateValue(pname, static_cast(attrib.normalized)); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = CastFromGLintStateValue(pname, binding.getBuffer().id()); + break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + *params = CastFromGLintStateValue(pname, binding.getDivisor()); + break; + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + *params = CastFromGLintStateValue(pname, attrib.pureInteger); + break; + case GL_VERTEX_ATTRIB_BINDING: + *params = CastFromGLintStateValue(pname, attrib.bindingIndex); + break; + case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: + *params = CastFromGLintStateValue(pname, attrib.relativeOffset); + break; + default: + UNREACHABLE(); + break; + } +} + +template +void QueryBufferParameterBase(const Buffer *buffer, GLenum pname, ParamType *params) +{ + ASSERT(buffer != nullptr); + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = CastFromGLintStateValue(pname, ToGLenum(buffer->getUsage())); + break; + case GL_BUFFER_SIZE: + *params = CastFromStateValue(pname, buffer->getSize()); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = CastFromGLintStateValue(pname, buffer->getAccessFlags()); + break; + case GL_BUFFER_ACCESS_OES: + *params = CastFromGLintStateValue(pname, buffer->getAccess()); + break; + case GL_BUFFER_MAPPED: + *params = CastFromStateValue(pname, buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = CastFromStateValue(pname, buffer->getMapOffset()); + break; + case GL_BUFFER_MAP_LENGTH: + *params = CastFromStateValue(pname, buffer->getMapLength()); + break; + default: + UNREACHABLE(); + break; + } +} + +GLint GetCommonVariableProperty(const sh::ShaderVariable &var, GLenum prop) +{ + switch (prop) + { + case GL_TYPE: + return clampCast(var.type); + + case GL_ARRAY_SIZE: + // Queryable variables are guaranteed not to be arrays of arrays or arrays of structs, + // see GLES 3.1 spec section 7.3.1.1 page 77. + return clampCast(var.getBasicTypeElementCount()); + + case GL_NAME_LENGTH: + // ES31 spec p84: This counts the terminating null char. + return clampCast(var.name.size() + 1u); + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop) +{ + const auto &attribute = program->getInputResource(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(attribute, prop); + + case GL_LOCATION: + return program->getAttributeLocation(attribute.name); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return 1; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + return 0; + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &outputVariable = program->getOutputResource(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(outputVariable, prop); + + case GL_LOCATION: + return program->getFragDataLocation(outputVariable.name); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return 0; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return 1; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return 0; + + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +GLint QueryProgramInterfaceActiveResources(const Program *program, GLenum programInterface) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return clampCast(program->getAttributes().size()); + + case GL_PROGRAM_OUTPUT: + return clampCast(program->getState().getOutputVariables().size()); + + case GL_UNIFORM: + return clampCast(program->getState().getUniforms().size()); + + case GL_UNIFORM_BLOCK: + return clampCast(program->getState().getUniformBlocks().size()); + + case GL_ATOMIC_COUNTER_BUFFER: + return clampCast(program->getState().getAtomicCounterBuffers().size()); + + case GL_BUFFER_VARIABLE: + return clampCast(program->getState().getBufferVariables().size()); + + case GL_SHADER_STORAGE_BLOCK: + return clampCast(program->getState().getShaderStorageBlocks().size()); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return 0; + + default: + UNREACHABLE(); + return 0; + } +} + +template +GLint FindMaxSize(const std::vector &resources, M member) +{ + GLint max = 0; + for (const T &resource : resources) + { + max = std::max(max, clampCast((resource.*member).size())); + } + return max; +} + +GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programInterface) +{ + GLint maxNameLength = 0; + switch (programInterface) + { + case GL_PROGRAM_INPUT: + maxNameLength = FindMaxSize(program->getAttributes(), &sh::Attribute::name); + break; + + case GL_PROGRAM_OUTPUT: + maxNameLength = + FindMaxSize(program->getState().getOutputVariables(), &sh::OutputVariable::name); + break; + + case GL_UNIFORM: + maxNameLength = FindMaxSize(program->getState().getUniforms(), &LinkedUniform::name); + break; + + case GL_UNIFORM_BLOCK: + maxNameLength = + FindMaxSize(program->getState().getUniformBlocks(), &InterfaceBlock::name); + break; + + case GL_BUFFER_VARIABLE: + maxNameLength = + FindMaxSize(program->getState().getBufferVariables(), &BufferVariable::name); + break; + + case GL_SHADER_STORAGE_BLOCK: + maxNameLength = + FindMaxSize(program->getState().getShaderStorageBlocks(), &InterfaceBlock::name); + break; + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return 0; + + default: + UNREACHABLE(); + return 0; + } + // This length includes an extra character for the null terminator. + return (maxNameLength == 0 ? 0 : maxNameLength + 1); +} + +GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM_BLOCK: + return FindMaxSize(program->getState().getUniformBlocks(), + &InterfaceBlock::memberIndexes); + case GL_ATOMIC_COUNTER_BUFFER: + return FindMaxSize(program->getState().getAtomicCounterBuffers(), + &AtomicCounterBuffer::memberIndexes); + + case GL_SHADER_STORAGE_BLOCK: + return FindMaxSize(program->getState().getShaderStorageBlocks(), + &InterfaceBlock::memberIndexes); + + default: + UNREACHABLE(); + return 0; + } +} + +GLenum GetUniformPropertyEnum(GLenum prop) +{ + switch (prop) + { + case GL_UNIFORM_TYPE: + return GL_TYPE; + case GL_UNIFORM_SIZE: + return GL_ARRAY_SIZE; + case GL_UNIFORM_NAME_LENGTH: + return GL_NAME_LENGTH; + case GL_UNIFORM_BLOCK_INDEX: + return GL_BLOCK_INDEX; + case GL_UNIFORM_OFFSET: + return GL_OFFSET; + case GL_UNIFORM_ARRAY_STRIDE: + return GL_ARRAY_STRIDE; + case GL_UNIFORM_MATRIX_STRIDE: + return GL_MATRIX_STRIDE; + case GL_UNIFORM_IS_ROW_MAJOR: + return GL_IS_ROW_MAJOR; + + default: + return prop; + } +} + +GLenum GetUniformBlockPropertyEnum(GLenum prop) +{ + switch (prop) + { + case GL_UNIFORM_BLOCK_BINDING: + return GL_BUFFER_BINDING; + + case GL_UNIFORM_BLOCK_DATA_SIZE: + return GL_BUFFER_DATA_SIZE; + + case GL_UNIFORM_BLOCK_NAME_LENGTH: + return GL_NAME_LENGTH; + + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + return GL_NUM_ACTIVE_VARIABLES; + + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + return GL_ACTIVE_VARIABLES; + + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + return GL_REFERENCED_BY_VERTEX_SHADER; + + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + return GL_REFERENCED_BY_FRAGMENT_SHADER; + + default: + return prop; + } +} + +void GetShaderVariableBufferResourceProperty(const ShaderVariableBuffer &buffer, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + switch (pname) + { + case GL_BUFFER_BINDING: + params[(*outputPosition)++] = buffer.binding; + break; + case GL_BUFFER_DATA_SIZE: + params[(*outputPosition)++] = clampCast(buffer.dataSize); + break; + case GL_NUM_ACTIVE_VARIABLES: + params[(*outputPosition)++] = buffer.numActiveVariables(); + break; + case GL_ACTIVE_VARIABLES: + for (size_t memberIndex = 0; + memberIndex < buffer.memberIndexes.size() && *outputPosition < bufSize; + ++memberIndex) + { + params[(*outputPosition)++] = clampCast(buffer.memberIndexes[memberIndex]); + } + break; + case GL_REFERENCED_BY_VERTEX_SHADER: + params[(*outputPosition)++] = static_cast(buffer.vertexStaticUse); + break; + case GL_REFERENCED_BY_FRAGMENT_SHADER: + params[(*outputPosition)++] = static_cast(buffer.fragmentStaticUse); + break; + case GL_REFERENCED_BY_COMPUTE_SHADER: + params[(*outputPosition)++] = static_cast(buffer.computeStaticUse); + break; + default: + UNREACHABLE(); + break; + } +} + +void GetInterfaceBlockResourceProperty(const InterfaceBlock &block, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) +{ + if (pname == GL_NAME_LENGTH) + { + params[(*outputPosition)++] = clampCast(block.nameWithArrayIndex().size() + 1); + return; + } + GetShaderVariableBufferResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetUniformBlockResourceProperty(const Program *program, + GLuint blockIndex, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &block = program->getUniformBlockByIndex(blockIndex); + GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetShaderStorageBlockResourceProperty(const Program *program, + GLuint blockIndex, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &block = program->getShaderStorageBlockByIndex(blockIndex); + GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); +} + +void GetAtomicCounterBufferResourceProperty(const Program *program, + GLuint index, + GLenum pname, + GLint *params, + GLsizei bufSize, + GLsizei *outputPosition) + +{ + ASSERT(*outputPosition < bufSize); + const auto &buffer = program->getState().getAtomicCounterBuffers()[index]; + GetShaderVariableBufferResourceProperty(buffer, pname, params, bufSize, outputPosition); +} + +} // anonymous namespace + +void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer, + GLenum attachment, + GLenum pname, + GLint *params) +{ + ASSERT(framebuffer); + + const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + if (attachmentObject == nullptr) + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. + + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = GL_NONE; + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + *params = 0; + break; + + default: + UNREACHABLE(); + break; + } + + return; + } + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObject->type(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + *params = attachmentObject->id(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + *params = attachmentObject->mipLevel(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + *params = attachmentObject->cubeMapFace(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + *params = attachmentObject->getRedSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + *params = attachmentObject->getGreenSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + *params = attachmentObject->getBlueSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + *params = attachmentObject->getAlphaSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + *params = attachmentObject->getDepthSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + *params = attachmentObject->getStencilSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + *params = attachmentObject->getComponentType(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + *params = attachmentObject->getColorEncoding(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + *params = attachmentObject->layer(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE: + *params = attachmentObject->getNumViews(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE: + *params = static_cast(attachmentObject->getMultiviewLayout()); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE: + *params = attachmentObject->getBaseViewIndex(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE: + { + const std::vector &offsets = attachmentObject->getMultiviewViewportOffsets(); + for (size_t i = 0u; i < offsets.size(); ++i) + { + params[i * 2u] = offsets[i].x; + params[i * 2u + 1u] = offsets[i].y; + } + } + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params) +{ + QueryBufferParameterBase(buffer, pname, params); +} + +void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params) +{ + QueryBufferParameterBase(buffer, pname, params); +} + +void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params) +{ + switch (pname) + { + case GL_BUFFER_MAP_POINTER: + *params = buffer->getMapPointer(); + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryProgramiv(const Context *context, const Program *program, GLenum pname, GLint *params) +{ + ASSERT(program != nullptr); + + switch (pname) + { + case GL_DELETE_STATUS: + *params = program->isFlaggedForDeletion(); + return; + case GL_LINK_STATUS: + *params = program->isLinked(); + return; + case GL_VALIDATE_STATUS: + *params = program->isValidated(); + return; + case GL_INFO_LOG_LENGTH: + *params = program->getInfoLogLength(); + return; + case GL_ATTACHED_SHADERS: + *params = program->getAttachedShadersCount(); + return; + case GL_ACTIVE_ATTRIBUTES: + *params = program->getActiveAttributeCount(); + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = program->getActiveAttributeMaxLength(); + return; + case GL_ACTIVE_UNIFORMS: + *params = program->getActiveUniformCount(); + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = program->getActiveUniformMaxLength(); + return; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = program->getBinaryLength(context); + return; + case GL_ACTIVE_UNIFORM_BLOCKS: + *params = program->getActiveUniformBlockCount(); + return; + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + *params = program->getActiveUniformBlockMaxLength(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = program->getTransformFeedbackBufferMode(); + break; + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = program->getTransformFeedbackVaryingCount(); + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = program->getTransformFeedbackVaryingMaxLength(); + break; + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + *params = program->getBinaryRetrievableHint(); + break; + case GL_PROGRAM_SEPARABLE: + *params = program->isSeparable(); + break; + case GL_COMPUTE_WORK_GROUP_SIZE: + { + const sh::WorkGroupSize &localSize = program->getComputeShaderLocalSize(); + params[0] = localSize[0]; + params[1] = localSize[1]; + params[2] = localSize[2]; + } + break; + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + *params = program->getActiveAtomicCounterBufferCount(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryRenderbufferiv(const Context *context, + const Renderbuffer *renderbuffer, + GLenum pname, + GLint *params) +{ + ASSERT(renderbuffer != nullptr); + + switch (pname) + { + case GL_RENDERBUFFER_WIDTH: + *params = renderbuffer->getWidth(); + break; + case GL_RENDERBUFFER_HEIGHT: + *params = renderbuffer->getHeight(); + break; + case GL_RENDERBUFFER_INTERNAL_FORMAT: + // Special case the WebGL 1 DEPTH_STENCIL format. + if (context->isWebGL1() && + renderbuffer->getFormat().info->internalFormat == GL_DEPTH24_STENCIL8) + { + *params = GL_DEPTH_STENCIL; + } + else + { + *params = renderbuffer->getFormat().info->internalFormat; + } + break; + case GL_RENDERBUFFER_RED_SIZE: + *params = renderbuffer->getRedSize(); + break; + case GL_RENDERBUFFER_GREEN_SIZE: + *params = renderbuffer->getGreenSize(); + break; + case GL_RENDERBUFFER_BLUE_SIZE: + *params = renderbuffer->getBlueSize(); + break; + case GL_RENDERBUFFER_ALPHA_SIZE: + *params = renderbuffer->getAlphaSize(); + break; + case GL_RENDERBUFFER_DEPTH_SIZE: + *params = renderbuffer->getDepthSize(); + break; + case GL_RENDERBUFFER_STENCIL_SIZE: + *params = renderbuffer->getStencilSize(); + break; + case GL_RENDERBUFFER_SAMPLES_ANGLE: + *params = renderbuffer->getSamples(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryShaderiv(const Context *context, Shader *shader, GLenum pname, GLint *params) +{ + ASSERT(shader != nullptr); + + switch (pname) + { + case GL_SHADER_TYPE: + *params = shader->getType(); + return; + case GL_DELETE_STATUS: + *params = shader->isFlaggedForDeletion(); + return; + case GL_COMPILE_STATUS: + *params = shader->isCompiled(context) ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + *params = shader->getInfoLogLength(context); + return; + case GL_SHADER_SOURCE_LENGTH: + *params = shader->getSourceLength(); + return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shader->getTranslatedSourceWithDebugInfoLength(context); + return; + default: + UNREACHABLE(); + break; + } +} + +void QueryTexLevelParameterfv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params) +{ + QueryTexLevelParameterBase(texture, target, level, pname, params); +} + +void QueryTexLevelParameteriv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLint *params) +{ + QueryTexLevelParameterBase(texture, target, level, pname, params); +} + +void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params) +{ + QueryTexParameterBase(texture, pname, params); +} + +void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params) +{ + QueryTexParameterBase(texture, pname, params); +} + +void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params) +{ + QuerySamplerParameterBase(sampler, pname, params); +} + +void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params) +{ + QuerySamplerParameterBase(sampler, pname, params); +} + +void QueryVertexAttribfv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLfloat *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.FloatValues, pname, params); +} + +void QueryVertexAttribiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.FloatValues, pname, params); +} + +void QueryVertexAttribPointerv(const VertexAttribute &attrib, GLenum pname, void **pointer) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_POINTER: + *pointer = const_cast(attrib.pointer); + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryVertexAttribIiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.IntValues, pname, params); +} + +void QueryVertexAttribIuiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLuint *params) +{ + QueryVertexAttribBase(attrib, binding, currentValueData.UnsignedIntValues, pname, params); +} + +void QueryActiveUniformBlockiv(const Program *program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + GLenum prop = GetUniformBlockPropertyEnum(pname); + QueryProgramResourceiv(program, GL_UNIFORM_BLOCK, uniformBlockIndex, 1, &prop, + std::numeric_limits::max(), nullptr, params); +} + +void QueryInternalFormativ(const TextureCaps &format, GLenum pname, GLsizei bufSize, GLint *params) +{ + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + if (bufSize != 0) + { + *params = clampCast(format.sampleCounts.size()); + } + break; + + case GL_SAMPLES: + { + size_t returnCount = std::min(bufSize, format.sampleCounts.size()); + auto sampleReverseIt = format.sampleCounts.rbegin(); + for (size_t sampleIndex = 0; sampleIndex < returnCount; ++sampleIndex) + { + params[sampleIndex] = *sampleReverseIt++; + } + } + break; + + default: + UNREACHABLE(); + break; + } +} + +void QueryFramebufferParameteriv(const Framebuffer *framebuffer, GLenum pname, GLint *params) +{ + ASSERT(framebuffer); + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + *params = framebuffer->getDefaultWidth(); + break; + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + *params = framebuffer->getDefaultHeight(); + break; + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + *params = framebuffer->getDefaultSamples(); + break; + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + *params = ConvertToGLBoolean(framebuffer->getDefaultFixedSampleLocations()); + break; + default: + UNREACHABLE(); + break; + } +} + +Error QuerySynciv(const Sync *sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +{ + ASSERT(sync); + + // All queries return one value, exit early if the buffer can't fit anything. + if (bufSize < 1) + { + if (length != nullptr) + { + *length = 0; + } + return NoError(); + } + + switch (pname) + { + case GL_OBJECT_TYPE: + *values = clampCast(GL_SYNC_FENCE); + break; + case GL_SYNC_CONDITION: + *values = clampCast(sync->getCondition()); + break; + case GL_SYNC_FLAGS: + *values = clampCast(sync->getFlags()); + break; + case GL_SYNC_STATUS: + ANGLE_TRY(sync->getStatus(values)); + break; + + default: + UNREACHABLE(); + break; + } + + if (length != nullptr) + { + *length = 1; + } + + return NoError(); +} + +void SetTexParameterf(Context *context, Texture *texture, GLenum pname, GLfloat param) +{ + SetTexParameterBase(context, texture, pname, ¶m); +} + +void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const GLfloat *params) +{ + SetTexParameterBase(context, texture, pname, params); +} + +void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param) +{ + SetTexParameterBase(context, texture, pname, ¶m); +} + +void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params) +{ + SetTexParameterBase(context, texture, pname, params); +} + +void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param) +{ + SetSamplerParameterBase(sampler, pname, ¶m); +} + +void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params) +{ + SetSamplerParameterBase(sampler, pname, params); +} + +void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param) +{ + SetSamplerParameterBase(sampler, pname, ¶m); +} + +void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params) +{ + SetSamplerParameterBase(sampler, pname, params); +} + +void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param) +{ + ASSERT(framebuffer); + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + framebuffer->setDefaultWidth(param); + break; + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + framebuffer->setDefaultHeight(param); + break; + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + framebuffer->setDefaultSamples(param); + break; + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + framebuffer->setDefaultFixedSampleLocations(ConvertToBool(param)); + break; + default: + UNREACHABLE(); + break; + } +} + +void SetProgramParameteri(Program *program, GLenum pname, GLint value) +{ + ASSERT(program); + + switch (pname) + { + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + program->setBinaryRetrievableHint(ConvertToBool(value)); + break; + case GL_PROGRAM_SEPARABLE: + program->setSeparable(ConvertToBool(value)); + break; + default: + UNREACHABLE(); + break; + } +} + +GLint GetUniformResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &uniform = program->getUniformByIndex(index); + GLenum resourceProp = GetUniformPropertyEnum(prop); + switch (resourceProp) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(uniform, resourceProp); + + case GL_LOCATION: + return program->getUniformLocation(uniform.name); + + case GL_BLOCK_INDEX: + return (uniform.isAtomicCounter() ? -1 : uniform.bufferIndex); + + case GL_OFFSET: + return uniform.blockInfo.offset; + + case GL_ARRAY_STRIDE: + return uniform.blockInfo.arrayStride; + + case GL_MATRIX_STRIDE: + return uniform.blockInfo.matrixStride; + + case GL_IS_ROW_MAJOR: + return static_cast(uniform.blockInfo.isRowMajorMatrix); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return uniform.vertexStaticUse; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return uniform.fragmentStaticUse; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return uniform.computeStaticUse; + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + return (uniform.isAtomicCounter() ? uniform.bufferIndex : -1); + + default: + UNREACHABLE(); + return 0; + } +} + +GLint GetBufferVariableResourceProperty(const Program *program, GLuint index, const GLenum prop) +{ + const auto &bufferVariable = program->getBufferVariableByIndex(index); + switch (prop) + { + case GL_TYPE: + case GL_ARRAY_SIZE: + case GL_NAME_LENGTH: + return GetCommonVariableProperty(bufferVariable, prop); + + case GL_BLOCK_INDEX: + return bufferVariable.bufferIndex; + + case GL_OFFSET: + return bufferVariable.blockInfo.offset; + + case GL_ARRAY_STRIDE: + return bufferVariable.blockInfo.arrayStride; + + case GL_MATRIX_STRIDE: + return bufferVariable.blockInfo.matrixStride; + + case GL_IS_ROW_MAJOR: + return static_cast(bufferVariable.blockInfo.isRowMajorMatrix); + + case GL_REFERENCED_BY_VERTEX_SHADER: + return bufferVariable.vertexStaticUse; + + case GL_REFERENCED_BY_FRAGMENT_SHADER: + return bufferVariable.fragmentStaticUse; + + case GL_REFERENCED_BY_COMPUTE_SHADER: + return bufferVariable.computeStaticUse; + + case GL_TOP_LEVEL_ARRAY_SIZE: + return bufferVariable.topLevelArraySize; + + case GL_TOP_LEVEL_ARRAY_STRIDE: + return bufferVariable.blockInfo.topLevelArrayStride; + + default: + UNREACHABLE(); + return 0; + } +} + +GLuint QueryProgramResourceIndex(const Program *program, + GLenum programInterface, + const GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return program->getInputResourceIndex(name); + + case GL_PROGRAM_OUTPUT: + return program->getOutputResourceIndex(name); + + case GL_UNIFORM: + return program->getState().getUniformIndexFromName(name); + + case GL_BUFFER_VARIABLE: + return program->getState().getBufferVariableIndexFromName(name); + + case GL_SHADER_STORAGE_BLOCK: + return program->getShaderStorageBlockIndex(name); + + case GL_UNIFORM_BLOCK: + return program->getUniformBlockIndex(name); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return GL_INVALID_INDEX; + + default: + UNREACHABLE(); + return GL_INVALID_INDEX; + } +} + +void QueryProgramResourceName(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + program->getInputResourceName(index, bufSize, length, name); + break; + + case GL_PROGRAM_OUTPUT: + program->getOutputResourceName(index, bufSize, length, name); + break; + + case GL_UNIFORM: + program->getUniformResourceName(index, bufSize, length, name); + break; + + case GL_BUFFER_VARIABLE: + program->getBufferVariableResourceName(index, bufSize, length, name); + break; + + case GL_SHADER_STORAGE_BLOCK: + program->getActiveShaderStorageBlockName(index, bufSize, length, name); + break; + + case GL_UNIFORM_BLOCK: + program->getActiveUniformBlockName(index, bufSize, length, name); + break; + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + } +} + +GLint QueryProgramResourceLocation(const Program *program, + GLenum programInterface, + const GLchar *name) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return program->getAttributeLocation(name); + + case GL_PROGRAM_OUTPUT: + return program->getFragDataLocation(name); + + case GL_UNIFORM: + return program->getUniformLocation(name); + + default: + UNREACHABLE(); + return -1; + } +} + +void QueryProgramResourceiv(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!program->isLinked()) + { + if (length != nullptr) + { + *length = 0; + } + return; + } + + GLsizei pos = 0; + for (GLsizei i = 0; i < propCount; i++) + { + switch (programInterface) + { + case GL_PROGRAM_INPUT: + params[i] = GetInputResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_PROGRAM_OUTPUT: + params[i] = GetOutputResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_UNIFORM: + params[i] = GetUniformResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_BUFFER_VARIABLE: + params[i] = GetBufferVariableResourceProperty(program, index, props[i]); + ++pos; + break; + + case GL_UNIFORM_BLOCK: + GetUniformBlockResourceProperty(program, index, props[i], params, bufSize, &pos); + break; + + case GL_SHADER_STORAGE_BLOCK: + GetShaderStorageBlockResourceProperty(program, index, props[i], params, bufSize, + &pos); + break; + + case GL_ATOMIC_COUNTER_BUFFER: + GetAtomicCounterBufferResourceProperty(program, index, props[i], params, bufSize, + &pos); + break; + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + params[i] = GL_INVALID_VALUE; + break; + + default: + UNREACHABLE(); + params[i] = GL_INVALID_VALUE; + } + if (pos == bufSize) + { + // Most properties return one value, but GL_ACTIVE_VARIABLES returns an array of values. + // This checks not to break buffer bounds for such case. + break; + } + } + + if (length != nullptr) + { + *length = pos; + } +} + +void QueryProgramInterfaceiv(const Program *program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + switch (pname) + { + case GL_ACTIVE_RESOURCES: + *params = QueryProgramInterfaceActiveResources(program, programInterface); + break; + + case GL_MAX_NAME_LENGTH: + *params = QueryProgramInterfaceMaxNameLength(program, programInterface); + break; + + case GL_MAX_NUM_ACTIVE_VARIABLES: + *params = QueryProgramInterfaceMaxNumActiveVariables(program, programInterface); + break; + + default: + UNREACHABLE(); + } +} + +} // namespace gl + +namespace egl +{ + +void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value) +{ + ASSERT(config != nullptr); + switch (attribute) + { + case EGL_BUFFER_SIZE: + *value = config->bufferSize; + break; + case EGL_ALPHA_SIZE: + *value = config->alphaSize; + break; + case EGL_BLUE_SIZE: + *value = config->blueSize; + break; + case EGL_GREEN_SIZE: + *value = config->greenSize; + break; + case EGL_RED_SIZE: + *value = config->redSize; + break; + case EGL_DEPTH_SIZE: + *value = config->depthSize; + break; + case EGL_STENCIL_SIZE: + *value = config->stencilSize; + break; + case EGL_CONFIG_CAVEAT: + *value = config->configCaveat; + break; + case EGL_CONFIG_ID: + *value = config->configID; + break; + case EGL_LEVEL: + *value = config->level; + break; + case EGL_NATIVE_RENDERABLE: + *value = config->nativeRenderable; + break; + case EGL_NATIVE_VISUAL_ID: + *value = config->nativeVisualID; + break; + case EGL_NATIVE_VISUAL_TYPE: + *value = config->nativeVisualType; + break; + case EGL_SAMPLES: + *value = config->samples; + break; + case EGL_SAMPLE_BUFFERS: + *value = config->sampleBuffers; + break; + case EGL_SURFACE_TYPE: + *value = config->surfaceType; + break; + case EGL_TRANSPARENT_TYPE: + *value = config->transparentType; + break; + case EGL_TRANSPARENT_BLUE_VALUE: + *value = config->transparentBlueValue; + break; + case EGL_TRANSPARENT_GREEN_VALUE: + *value = config->transparentGreenValue; + break; + case EGL_TRANSPARENT_RED_VALUE: + *value = config->transparentRedValue; + break; + case EGL_BIND_TO_TEXTURE_RGB: + *value = config->bindToTextureRGB; + break; + case EGL_BIND_TO_TEXTURE_RGBA: + *value = config->bindToTextureRGBA; + break; + case EGL_MIN_SWAP_INTERVAL: + *value = config->minSwapInterval; + break; + case EGL_MAX_SWAP_INTERVAL: + *value = config->maxSwapInterval; + break; + case EGL_LUMINANCE_SIZE: + *value = config->luminanceSize; + break; + case EGL_ALPHA_MASK_SIZE: + *value = config->alphaMaskSize; + break; + case EGL_COLOR_BUFFER_TYPE: + *value = config->colorBufferType; + break; + case EGL_RENDERABLE_TYPE: + *value = config->renderableType; + break; + case EGL_MATCH_NATIVE_PIXMAP: + *value = false; + UNIMPLEMENTED(); + break; + case EGL_CONFORMANT: + *value = config->conformant; + break; + case EGL_MAX_PBUFFER_WIDTH: + *value = config->maxPBufferWidth; + break; + case EGL_MAX_PBUFFER_HEIGHT: + *value = config->maxPBufferHeight; + break; + case EGL_MAX_PBUFFER_PIXELS: + *value = config->maxPBufferPixels; + break; + case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: + *value = config->optimalOrientation; + break; + case EGL_COLOR_COMPONENT_TYPE_EXT: + *value = config->colorComponentType; + break; + default: + UNREACHABLE(); + break; + } +} + +void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_CONFIG_ID: + *value = context->getConfig()->configID; + break; + case EGL_CONTEXT_CLIENT_TYPE: + *value = context->getClientType(); + break; + case EGL_CONTEXT_CLIENT_VERSION: + *value = context->getClientMajorVersion(); + break; + case EGL_RENDER_BUFFER: + *value = context->getRenderBuffer(); + break; + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *value = context->isRobustResourceInitEnabled(); + break; + default: + UNREACHABLE(); + break; + } +} + +void QuerySurfaceAttrib(const Surface *surface, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_GL_COLORSPACE: + *value = surface->getGLColorspace(); + break; + case EGL_VG_ALPHA_FORMAT: + *value = surface->getVGAlphaFormat(); + break; + case EGL_VG_COLORSPACE: + *value = surface->getVGColorspace(); + break; + case EGL_CONFIG_ID: + *value = surface->getConfig()->configID; + break; + case EGL_HEIGHT: + *value = surface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + *value = surface->getHorizontalResolution(); + break; + case EGL_LARGEST_PBUFFER: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getLargestPbuffer(); + } + break; + case EGL_MIPMAP_TEXTURE: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getMipmapTexture(); + } + break; + case EGL_MIPMAP_LEVEL: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getMipmapLevel(); + } + break; + case EGL_MULTISAMPLE_RESOLVE: + *value = surface->getMultisampleResolve(); + break; + case EGL_PIXEL_ASPECT_RATIO: + *value = surface->getPixelAspectRatio(); + break; + case EGL_RENDER_BUFFER: + *value = surface->getRenderBuffer(); + break; + case EGL_SWAP_BEHAVIOR: + *value = surface->getSwapBehavior(); + break; + case EGL_TEXTURE_FORMAT: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getTextureFormat(); + } + break; + case EGL_TEXTURE_TARGET: + // The EGL spec states that value is not written if the surface is not a pbuffer + if (surface->getType() == EGL_PBUFFER_BIT) + { + *value = surface->getTextureTarget(); + } + break; + case EGL_VERTICAL_RESOLUTION: + *value = surface->getVerticalResolution(); + break; + case EGL_WIDTH: + *value = surface->getWidth(); + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + *value = surface->isPostSubBufferSupported(); + break; + case EGL_FIXED_SIZE_ANGLE: + *value = surface->isFixedSize(); + break; + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + *value = surface->flexibleSurfaceCompatibilityRequested(); + break; + case EGL_SURFACE_ORIENTATION_ANGLE: + *value = surface->getOrientation(); + break; + case EGL_DIRECT_COMPOSITION_ANGLE: + *value = surface->directComposition(); + break; + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + *value = surface->isRobustResourceInitEnabled(); + break; + default: + UNREACHABLE(); + break; + } +} + +void SetSurfaceAttrib(Surface *surface, EGLint attribute, EGLint value) +{ + switch (attribute) + { + case EGL_MIPMAP_LEVEL: + surface->setMipmapLevel(value); + break; + case EGL_MULTISAMPLE_RESOLVE: + surface->setMultisampleResolve(value); + break; + case EGL_SWAP_BEHAVIOR: + surface->setSwapBehavior(value); + break; + default: + UNREACHABLE(); + break; + } +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/queryutils.h b/src/3rdparty/angle/src/libANGLE/queryutils.h new file mode 100644 index 0000000000..990cbc169e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryutils.h @@ -0,0 +1,162 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// queryutils.h: Utilities for querying values from GL objects + +#ifndef LIBANGLE_QUERYUTILS_H_ +#define LIBANGLE_QUERYUTILS_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" + +#include + +namespace gl +{ +class Buffer; +class Context; +class Error; +class Sync; +class Framebuffer; +class Program; +class Renderbuffer; +class Sampler; +class Shader; +class Texture; +struct TextureCaps; +struct UniformBlock; +struct VertexAttribute; +class VertexBinding; +struct VertexAttribCurrentValueData; + +void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer, + GLenum attachment, + GLenum pname, + GLint *params); +void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params); +void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params); +void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params); +void QueryProgramiv(const Context *context, const Program *program, GLenum pname, GLint *params); +void QueryRenderbufferiv(const Context *context, + const Renderbuffer *renderbuffer, + GLenum pname, + GLint *params); +void QueryShaderiv(const Context *context, Shader *shader, GLenum pname, GLint *params); +void QueryTexLevelParameterfv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params); +void QueryTexLevelParameteriv(const Texture *texture, + GLenum target, + GLint level, + GLenum pname, + GLint *params); +void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params); +void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params); +void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params); +void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params); + +// Warning: you should ensure binding really matches attrib.bindingIndex before using the following +// functions. +void QueryVertexAttribfv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLfloat *params); + +void QueryVertexAttribiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params); + +void QueryVertexAttribPointerv(const VertexAttribute &attrib, GLenum pname, void **pointer); + +void QueryVertexAttribIiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLint *params); + +void QueryVertexAttribIuiv(const VertexAttribute &attrib, + const VertexBinding &binding, + const VertexAttribCurrentValueData ¤tValueData, + GLenum pname, + GLuint *params); + +void QueryActiveUniformBlockiv(const Program *program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); + +void QueryInternalFormativ(const TextureCaps &format, GLenum pname, GLsizei bufSize, GLint *params); + +void QueryFramebufferParameteriv(const Framebuffer *framebuffer, GLenum pname, GLint *params); + +Error QuerySynciv(const Sync *sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); + +void SetTexParameterf(Context *context, Texture *texture, GLenum pname, GLfloat param); +void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const GLfloat *params); +void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param); +void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params); + +void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param); +void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params); +void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param); +void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params); + +void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param); + +void SetProgramParameteri(Program *program, GLenum pname, GLint value); + +GLint GetUniformResourceProperty(const Program *program, GLuint index, const GLenum prop); + +GLuint QueryProgramResourceIndex(const Program *program, + GLenum programInterface, + const GLchar *name); + +void QueryProgramResourceName(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); + +GLint QueryProgramResourceLocation(const Program *program, + GLenum programInterface, + const GLchar *name); +void QueryProgramResourceiv(const Program *program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +void QueryProgramInterfaceiv(const Program *program, + GLenum programInterface, + GLenum pname, + GLint *params); + +} // namespace gl + +namespace egl +{ +struct Config; +class Surface; + +void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value); + +void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value); + +void QuerySurfaceAttrib(const Surface *surface, EGLint attribute, EGLint *value); +void SetSurfaceAttrib(Surface *surface, EGLint attribute, EGLint value); + +} // namespace egl + +#endif // LIBANGLE_QUERYUTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h index d77f06cf09..f76fcdc8d7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h @@ -12,31 +12,58 @@ #include "common/angleutils.h" #include "common/mathutil.h" #include "libANGLE/Error.h" +#include "libANGLE/PackedGLEnums.h" #include -namespace rx +namespace gl { +class BufferState; +class Context; +} +namespace rx +{ class BufferImpl : angle::NonCopyable { public: - virtual ~BufferImpl() { } + BufferImpl(const gl::BufferState &state) : mState(state) {} + virtual ~BufferImpl() {} + virtual void destroy(const gl::Context *context) {} - 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(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 setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) = 0; + virtual gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) = 0; + virtual gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) = 0; + virtual gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) = 0; + virtual gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) = 0; + virtual gl::Error unmap(const gl::Context *context, GLboolean *result) = 0; - virtual gl::Error getIndexRange(GLenum type, + virtual gl::Error getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) = 0; -}; + protected: + const gl::BufferState &mState; +}; } -#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ +#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h index a6387661ce..5a4e21003c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl_mock.h @@ -11,28 +11,38 @@ #include "gmock/gmock.h" +#include "libANGLE/Buffer.h" #include "libANGLE/renderer/BufferImpl.h" namespace rx { - class MockBufferImpl : public BufferImpl { public: + MockBufferImpl() : BufferImpl(mMockState) {} ~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_METHOD5( + setData, + gl::Error(const gl::Context *, gl::BufferBinding, const void *, size_t, gl::BufferUsage)); + MOCK_METHOD5(setSubData, + gl::Error(const gl::Context *, gl::BufferBinding, const void *, size_t, size_t)); + MOCK_METHOD5( + copySubData, + gl::Error(const gl::Context *contextImpl, BufferImpl *, GLintptr, GLintptr, GLsizeiptr)); + MOCK_METHOD3(map, gl::Error(const gl::Context *contextImpl, GLenum, void **)); + MOCK_METHOD5(mapRange, + gl::Error(const gl::Context *contextImpl, size_t, size_t, GLbitfield, void **)); + MOCK_METHOD2(unmap, gl::Error(const gl::Context *contextImpl, GLboolean *result)); + + MOCK_METHOD6(getIndexRange, + gl::Error(const gl::Context *, GLenum, size_t, size_t, bool, gl::IndexRange *)); MOCK_METHOD0(destructor, void()); -}; + protected: + gl::BufferState mMockState; +}; } -#endif // LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_ +#endif // LIBANGLE_RENDERER_BUFFERIMPLMOCK_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp new file mode 100644 index 0000000000..8d3df291d3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ContextImpl: +// Implementation-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ + +ContextImpl::ContextImpl(const gl::ContextState &state) + : mState(state), mMemoryProgramCache(nullptr) +{ +} + +ContextImpl::~ContextImpl() +{ +} + +void ContextImpl::stencilFillPath(const gl::Path *path, GLenum fillMode, GLuint mask) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilStrokePath(const gl::Path *path, GLint reference, GLuint mask) +{ + UNREACHABLE(); +} + +void ContextImpl::coverFillPath(const gl::Path *path, GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::coverStrokePath(const gl::Path *path, GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverFillPath(const gl::Path *path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverStrokePath(const gl::Path *path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + UNREACHABLE(); +} + +void ContextImpl::coverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::coverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilFillPathInstanced(const std::vector &paths, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilStrokePathInstanced(const std::vector &paths, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::stencilThenCoverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + UNREACHABLE(); +} + +void ContextImpl::setMemoryProgramCache(gl::MemoryProgramCache *memoryProgramCache) +{ + mMemoryProgramCache = memoryProgramCache; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h new file mode 100644 index 0000000000..7ba4b5ad2d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ContextImpl.h @@ -0,0 +1,186 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ContextImpl: +// Implementation-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_CONTEXTIMPL_H_ +#define LIBANGLE_RENDERER_CONTEXTIMPL_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/ContextState.h" +#include "libANGLE/renderer/GLImplFactory.h" + +namespace gl +{ +class MemoryProgramCache; +class Path; +struct Workarounds; +} + +namespace rx +{ +class ContextImpl : public GLImplFactory +{ + public: + ContextImpl(const gl::ContextState &state); + ~ContextImpl() override; + + virtual void onDestroy(const gl::Context *context) {} + + virtual gl::Error initialize() = 0; + + // Flush and finish. + virtual gl::Error flush(const gl::Context *context) = 0; + virtual gl::Error finish(const gl::Context *context) = 0; + + // Drawing methods. + virtual gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) = 0; + virtual gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) = 0; + + virtual gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) = 0; + virtual gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) = 0; + virtual gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) = 0; + + virtual gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) = 0; + virtual gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) = 0; + + // CHROMIUM_path_rendering path drawing methods. + virtual void stencilFillPath(const gl::Path *path, GLenum fillMode, GLuint mask); + virtual void stencilStrokePath(const gl::Path *path, GLint reference, GLuint mask); + virtual void coverFillPath(const gl::Path *path, GLenum coverMode); + virtual void coverStrokePath(const gl::Path *path, GLenum coverMode); + virtual void stencilThenCoverFillPath(const gl::Path *path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); + + virtual void stencilThenCoverStrokePath(const gl::Path *path, + GLint reference, + GLuint mask, + GLenum coverMode); + + virtual void coverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + virtual void coverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilFillPathInstanced(const std::vector &paths, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilStrokePathInstanced(const std::vector &paths, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilThenCoverFillPathInstanced(const std::vector &paths, + GLenum coverMode, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + virtual void stencilThenCoverStrokePathInstanced(const std::vector &paths, + GLenum coverMode, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); + + // Device loss + virtual GLenum getResetStatus() = 0; + + // Vendor and description strings. + virtual std::string getVendorString() const = 0; + virtual std::string getRendererDescription() const = 0; + + // EXT_debug_marker + virtual void insertEventMarker(GLsizei length, const char *marker) = 0; + virtual void pushGroupMarker(GLsizei length, const char *marker) = 0; + virtual void popGroupMarker() = 0; + + // KHR_debug + virtual void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) = 0; + virtual void popDebugGroup() = 0; + + // State sync with dirty bits. + virtual void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) = 0; + + // Disjoint timer queries + virtual GLint getGPUDisjoint() = 0; + virtual GLint64 getTimestamp() = 0; + + // Context switching + virtual void onMakeCurrent(const gl::Context *context) = 0; + + // Native capabilities, unmodified by gl::Context. + virtual const gl::Caps &getNativeCaps() const = 0; + virtual const gl::TextureCapsMap &getNativeTextureCaps() const = 0; + virtual const gl::Extensions &getNativeExtensions() const = 0; + virtual const gl::Limitations &getNativeLimitations() const = 0; + + virtual void applyNativeWorkarounds(gl::Workarounds *workarounds) const {} + + virtual gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) = 0; + + const gl::ContextState &getContextState() { return mState; } + int getClientMajorVersion() const { return mState.getClientMajorVersion(); } + int getClientMinorVersion() const { return mState.getClientMinorVersion(); } + const gl::State &getGLState() const { return mState.getState(); } + const gl::Caps &getCaps() const { return mState.getCaps(); } + const gl::TextureCapsMap &getTextureCaps() const { return mState.getTextureCaps(); } + const gl::Extensions &getExtensions() const { return mState.getExtensions(); } + const gl::Limitations &getLimitations() const { return mState.getLimitations(); } + + // A common GL driver behaviour is to trigger dynamic shader recompilation on a draw call, + // based on the current render states. We store a mutable pointer to the program cache so + // on draw calls we can store the refreshed shaders in the cache. + void setMemoryProgramCache(gl::MemoryProgramCache *memoryProgramCache); + + protected: + const gl::ContextState &mState; + gl::MemoryProgramCache *mMemoryProgramCache; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_CONTEXTIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp index 8061189f0a..5cc9da96dc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp @@ -8,26 +8,20 @@ #include "libANGLE/renderer/DisplayImpl.h" +#include "libANGLE/Display.h" #include "libANGLE/Surface.h" namespace rx { -DisplayImpl::DisplayImpl() - : mExtensionsInitialized(false), - mCapsInitialized(false) +DisplayImpl::DisplayImpl(const egl::DisplayState &state) + : mState(state), mExtensionsInitialized(false), mCapsInitialized(false) { } DisplayImpl::~DisplayImpl() { - ASSERT(mSurfaceSet.empty()); -} - -void DisplayImpl::destroySurface(egl::Surface *surface) -{ - mSurfaceSet.erase(surface); - surface->onDestroy(); + ASSERT(mState.surfaceSet.empty()); } const egl::DisplayExtensions &DisplayImpl::getExtensions() const @@ -41,6 +35,15 @@ const egl::DisplayExtensions &DisplayImpl::getExtensions() const return mExtensions; } +egl::Error DisplayImpl::validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + UNREACHABLE(); + return egl::EglBadDisplay() << "DisplayImpl::validateClientBuffer unimplemented."; +} + const egl::Caps &DisplayImpl::getCaps() const { if (!mCapsInitialized) @@ -52,4 +55,4 @@ const egl::Caps &DisplayImpl::getCaps() const return mCaps; } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h index 9e38f63370..b1c49d9bc8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h @@ -13,7 +13,9 @@ #include "libANGLE/Caps.h" #include "libANGLE/Config.h" #include "libANGLE/Error.h" -#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/EGLImplFactory.h" +#include "libANGLE/Stream.h" +#include "libANGLE/Version.h" #include #include @@ -22,9 +24,11 @@ namespace egl { class AttributeMap; class Display; +struct DisplayState; struct Config; class Surface; class ImageSibling; +class Thread; } namespace gl @@ -38,69 +42,43 @@ class SurfaceImpl; class ImageImpl; struct ConfigDesc; class DeviceImpl; +class StreamProducerImpl; -class DisplayImpl : angle::NonCopyable +class DisplayImpl : public EGLImplFactory { public: - DisplayImpl(); - virtual ~DisplayImpl(); + DisplayImpl(const egl::DisplayState &state); + ~DisplayImpl() override; virtual egl::Error initialize(egl::Display *display) = 0; virtual void terminate() = 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; - virtual egl::ConfigSet generateConfigs() const = 0; + virtual egl::ConfigSet generateConfigs() = 0; - virtual bool isDeviceLost() const = 0; virtual bool testDeviceLost() = 0; - virtual egl::Error restoreLostDevice() = 0; + virtual egl::Error restoreLostDevice(const egl::Display *display) = 0; virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + virtual egl::Error validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const; 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; - + virtual egl::Error waitClient(const gl::Context *context) const = 0; + virtual egl::Error waitNative(const gl::Context *context, EGLint engine) const = 0; + virtual gl::Version getMaxSupportedESVersion() const = 0; const egl::Caps &getCaps() const; - typedef std::set SurfaceSet; - const SurfaceSet &getSurfaceSet() const { return mSurfaceSet; } - SurfaceSet &getSurfaceSet() { return mSurfaceSet; } - - void destroySurface(egl::Surface *surface); - const egl::DisplayExtensions &getExtensions() const; protected: - // Place the surface set here so it can be accessible for handling - // context loss events. (It is shared between the Display and Impl.) - SurfaceSet mSurfaceSet; + const egl::DisplayState &mState; private: virtual void generateExtensions(egl::DisplayExtensions *outExtensions) const = 0; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h new file mode 100644 index 0000000000..0433364cd3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/EGLImplFactory.h @@ -0,0 +1,68 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// EGLImplFactory.h: +// Factory interface for EGL Impl objects. +// + +#ifndef LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ +#define LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ + +#include "libANGLE/Stream.h" + +namespace egl +{ +class AttributeMap; +struct Config; +class ImageSibling; +struct ImageState; +struct SurfaceState; +} + +namespace gl +{ +class Context; +class ContextState; +} + +namespace rx +{ +class ContextImpl; +class ImageImpl; +class SurfaceImpl; + +class EGLImplFactory : angle::NonCopyable +{ + public: + EGLImplFactory() {} + virtual ~EGLImplFactory() {} + + virtual SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) = 0; + virtual SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, + NativePixmapType nativePixmap, + const egl::AttributeMap &attribs) = 0; + + virtual ImageImpl *createImage(const egl::ImageState &state, + EGLenum target, + const egl::AttributeMap &attribs) = 0; + + virtual ContextImpl *createContext(const gl::ContextState &state) = 0; + + virtual StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_EGLIMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h deleted file mode 100644 index 6b78e69d47..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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. -// - -// FenceSyncImpl.h: Defines the rx::FenceSyncImpl class. - -#ifndef LIBANGLE_RENDERER_FENCESYNCIMPL_H_ -#define LIBANGLE_RENDERER_FENCESYNCIMPL_H_ - -#include "libANGLE/Error.h" - -#include "common/angleutils.h" - -#include "angle_gl.h" - -namespace rx -{ - -class FenceSyncImpl : angle::NonCopyable -{ - public: - FenceSyncImpl() { }; - virtual ~FenceSyncImpl() { }; - - 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; -}; - -} - -#endif // LIBANGLE_RENDERER_FENCESYNCIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Format.h b/src/3rdparty/angle/src/libANGLE/renderer/Format.h new file mode 100644 index 0000000000..66bdace3e9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format.h @@ -0,0 +1,105 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Format: +// A universal description of typed GPU storage. Across multiple +// renderer back-ends, there are common formats and some distinct +// permutations, this enum encapsulates them all. Formats apply to +// textures, but could also apply to any typed data. + +#ifndef LIBANGLE_RENDERER_FORMAT_H_ +#define LIBANGLE_RENDERER_FORMAT_H_ + +#include "libANGLE/renderer/renderer_utils.h" + +namespace angle +{ + +struct Format final : private angle::NonCopyable +{ + enum class ID; + + constexpr Format(ID id, + GLenum glFormat, + GLenum fboFormat, + rx::MipGenerationFunction mipGen, + const rx::FastCopyFunctionMap &fastCopyFunctions, + rx::ColorReadFunction colorRead, + rx::ColorWriteFunction colorWrite, + GLenum componentType, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint depthBits, + GLuint stencilBits); + + static const Format &Get(ID id); + static ID InternalFormatToID(GLenum internalFormat); + + ID id; + + // The closest matching GL internal format for the storage this format uses. Note that this + // may be a different internal format than the one this ANGLE format is used for. + GLenum glInternalFormat; + + // The format we should report to the GL layer when querying implementation formats from a FBO. + // This might not be the same as the glInternalFormat, since some DXGI formats don't have + // matching GL format enums, like BGRA4, BGR5A1 and B5G6R6. + GLenum fboImplementationInternalFormat; + + rx::MipGenerationFunction mipGenerationFunction; + rx::ColorReadFunction colorReadFunction; + rx::ColorWriteFunction colorWriteFunction; + + // A map from a gl::FormatType to a fast pixel copy function for this format. + const rx::FastCopyFunctionMap &fastCopyFunctions; + + GLenum componentType; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint depthBits; + GLuint stencilBits; +}; + +constexpr Format::Format(ID id, + GLenum glFormat, + GLenum fboFormat, + rx::MipGenerationFunction mipGen, + const rx::FastCopyFunctionMap &fastCopyFunctions, + rx::ColorReadFunction colorRead, + rx::ColorWriteFunction colorWrite, + GLenum componentType, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint depthBits, + GLuint stencilBits) + : id(id), + glInternalFormat(glFormat), + fboImplementationInternalFormat(fboFormat), + mipGenerationFunction(mipGen), + colorReadFunction(colorRead), + colorWriteFunction(colorWrite), + fastCopyFunctions(fastCopyFunctions), + componentType(componentType), + redBits(redBits), + greenBits(greenBits), + blueBits(blueBits), + alphaBits(alphaBits), + depthBits(depthBits), + stencilBits(stencilBits) +{ +} + +} // namespace angle + +#include "libANGLE/renderer/Format_ID_autogen.inl" + +#endif // LIBANGLE_RENDERER_FORMAT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl b/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl new file mode 100644 index 0000000000..b2cbfb0410 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format_ID_autogen.inl @@ -0,0 +1,147 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_angle_format_table.py using data from angle_format_data.json +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ANGLE format enumeration. + +namespace angle +{ + +enum class Format::ID +{ + NONE, + A16_FLOAT, + A32_FLOAT, + A8_UNORM, + ASTC_10x10_SRGB_BLOCK, + ASTC_10x10_UNORM_BLOCK, + ASTC_10x5_SRGB_BLOCK, + ASTC_10x5_UNORM_BLOCK, + ASTC_10x6_SRGB_BLOCK, + ASTC_10x6_UNORM_BLOCK, + ASTC_10x8_SRGB_BLOCK, + ASTC_10x8_UNORM_BLOCK, + ASTC_12x10_SRGB_BLOCK, + ASTC_12x10_UNORM_BLOCK, + ASTC_12x12_SRGB_BLOCK, + ASTC_12x12_UNORM_BLOCK, + ASTC_4x4_SRGB_BLOCK, + ASTC_4x4_UNORM_BLOCK, + ASTC_5x4_SRGB_BLOCK, + ASTC_5x4_UNORM_BLOCK, + ASTC_5x5_SRGB_BLOCK, + ASTC_5x5_UNORM_BLOCK, + ASTC_6x5_SRGB_BLOCK, + ASTC_6x5_UNORM_BLOCK, + ASTC_6x6_SRGB_BLOCK, + ASTC_6x6_UNORM_BLOCK, + ASTC_8x5_SRGB_BLOCK, + ASTC_8x5_UNORM_BLOCK, + ASTC_8x6_SRGB_BLOCK, + ASTC_8x6_UNORM_BLOCK, + ASTC_8x8_SRGB_BLOCK, + ASTC_8x8_UNORM_BLOCK, + B4G4R4A4_UNORM, + B5G5R5A1_UNORM, + B5G6R5_UNORM, + B8G8R8A8_UNORM, + B8G8R8A8_UNORM_SRGB, + B8G8R8X8_UNORM, + BC1_RGBA_UNORM_BLOCK, + BC1_RGBA_UNORM_SRGB_BLOCK, + BC1_RGB_UNORM_BLOCK, + BC1_RGB_UNORM_SRGB_BLOCK, + BC2_RGBA_UNORM_BLOCK, + BC2_RGBA_UNORM_SRGB_BLOCK, + BC3_RGBA_UNORM_BLOCK, + BC3_RGBA_UNORM_SRGB_BLOCK, + D16_UNORM, + D24_UNORM, + D24_UNORM_S8_UINT, + D32_FLOAT, + D32_FLOAT_S8X24_UINT, + D32_UNORM, + EAC_R11G11_SNORM_BLOCK, + EAC_R11G11_UNORM_BLOCK, + EAC_R11_SNORM_BLOCK, + EAC_R11_UNORM_BLOCK, + ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, + ETC1_R8G8B8_UNORM_BLOCK, + ETC2_R8G8B8A1_SRGB_BLOCK, + ETC2_R8G8B8A1_UNORM_BLOCK, + ETC2_R8G8B8A8_SRGB_BLOCK, + ETC2_R8G8B8A8_UNORM_BLOCK, + ETC2_R8G8B8_SRGB_BLOCK, + ETC2_R8G8B8_UNORM_BLOCK, + L16A16_FLOAT, + L16_FLOAT, + L32A32_FLOAT, + L32_FLOAT, + L8A8_UNORM, + L8_UNORM, + R10G10B10A2_UINT, + R10G10B10A2_UNORM, + R11G11B10_FLOAT, + R16G16B16A16_FLOAT, + R16G16B16A16_SINT, + R16G16B16A16_SNORM, + R16G16B16A16_UINT, + R16G16B16A16_UNORM, + R16G16B16_FLOAT, + R16G16B16_SINT, + R16G16B16_SNORM, + R16G16B16_UINT, + R16G16B16_UNORM, + R16G16_FLOAT, + R16G16_SINT, + R16G16_SNORM, + R16G16_UINT, + R16G16_UNORM, + R16_FLOAT, + R16_SINT, + R16_SNORM, + R16_UINT, + R16_UNORM, + R32G32B32A32_FLOAT, + R32G32B32A32_SINT, + R32G32B32A32_UINT, + R32G32B32_FLOAT, + R32G32B32_SINT, + R32G32B32_UINT, + R32G32_FLOAT, + R32G32_SINT, + R32G32_UINT, + R32_FLOAT, + R32_SINT, + R32_UINT, + R4G4B4A4_UNORM, + R5G5B5A1_UNORM, + R5G6B5_UNORM, + R8G8B8A8_SINT, + R8G8B8A8_SNORM, + R8G8B8A8_UINT, + R8G8B8A8_UNORM, + R8G8B8A8_UNORM_SRGB, + R8G8B8_SINT, + R8G8B8_SNORM, + R8G8B8_UINT, + R8G8B8_UNORM, + R8G8B8_UNORM_SRGB, + R8G8_SINT, + R8G8_SNORM, + R8G8_UINT, + R8G8_UNORM, + R8_SINT, + R8_SNORM, + R8_UINT, + R8_UNORM, + R9G9B9E5_SHAREDEXP, + S8_UINT +}; + +constexpr uint32_t kNumANGLEFormats = 128; + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp new file mode 100644 index 0000000000..ecb3ad231a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Format_table_autogen.cpp @@ -0,0 +1,434 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_angle_format_table.py using data from angle_format_data.json +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ANGLE Format table: +// Queries for typed format information from the ANGLE format enum. + +#include "libANGLE/renderer/Format.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + +namespace angle +{ + +static constexpr rx::FastCopyFunctionMap::Entry BGRAEntry = {GL_RGBA, GL_UNSIGNED_BYTE, + CopyBGRA8ToRGBA8}; +static constexpr rx::FastCopyFunctionMap BGRACopyFunctions = {&BGRAEntry, 1}; +static constexpr rx::FastCopyFunctionMap NoCopyFunctions; + +constexpr Format g_formatInfoTable[] = { + // clang-format off + { Format::ID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0 }, + { Format::ID::A16_FLOAT, GL_ALPHA16F_EXT, GL_ALPHA16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 16, 0, 0 }, + { Format::ID::A32_FLOAT, GL_ALPHA32F_EXT, GL_ALPHA32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 32, 0, 0 }, + { Format::ID::A8_UNORM, GL_ALPHA8_EXT, GL_ALPHA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 8, 0, 0 }, + { Format::ID::ASTC_10x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_10x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x12_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_12x12_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_4x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_4x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_5x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_6x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::ASTC_8x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::B4G4R4A4_UNORM, GL_BGRA4_ANGLEX, GL_RGBA4, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 4, 4, 4, 4, 0, 0 }, + { Format::ID::B5G5R5A1_UNORM, GL_BGR5_A1_ANGLEX, GL_RGB5_A1, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0 }, + { Format::ID::B5G6R5_UNORM, GL_BGR565_ANGLEX, GL_RGB565, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 6, 5, 0, 0, 0 }, + { Format::ID::B8G8R8A8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip, BGRACopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::B8G8R8A8_UNORM_SRGB, GL_BGRA8_SRGB_ANGLEX, GL_BGRA8_SRGB_ANGLEX, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::B8G8R8X8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::BC1_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGB_UNORM_BLOCK, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC2_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC3_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::D16_UNORM, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 16, 0 }, + { Format::ID::D24_UNORM, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT24, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 24, 0 }, + { Format::ID::D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 24, 8 }, + { Format::ID::D32_FLOAT, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32F, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 32, 0 }, + { Format::ID::D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 32, 8 }, + { Format::ID::D32_UNORM, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT32_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 32, 0 }, + { Format::ID::EAC_R11G11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0 }, + { Format::ID::EAC_R11G11_UNORM_BLOCK, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0 }, + { Format::ID::EAC_R11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0 }, + { Format::ID::EAC_R11_UNORM_BLOCK, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0 }, + { Format::ID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC1_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC2_R8G8B8A1_SRGB_BLOCK, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0 }, + { Format::ID::ETC2_R8G8B8A1_UNORM_BLOCK, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0 }, + { Format::ID::ETC2_R8G8B8A8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::ETC2_R8G8B8A8_UNORM_BLOCK, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::ETC2_R8G8B8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::ETC2_R8G8B8_UNORM_BLOCK, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::L16A16_FLOAT, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 16, 0, 0 }, + { Format::ID::L16_FLOAT, GL_LUMINANCE16F_EXT, GL_LUMINANCE16F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 0, 0, 0 }, + { Format::ID::L32A32_FLOAT, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 32, 0, 0 }, + { Format::ID::L32_FLOAT, GL_LUMINANCE32F_EXT, GL_LUMINANCE32F_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 0, 0, 0, 0, 0, 0 }, + { Format::ID::L8A8_UNORM, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 8, 0, 0 }, + { Format::ID::L8_UNORM, GL_LUMINANCE8_EXT, GL_LUMINANCE8_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0 }, + { Format::ID::R10G10B10A2_UINT, GL_RGB10_A2UI, GL_RGB10_A2UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 10, 10, 10, 2, 0, 0 }, + { Format::ID::R10G10B10A2_UNORM, GL_RGB10_A2, GL_RGB10_A2, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 10, 10, 10, 2, 0, 0 }, + { Format::ID::R11G11B10_FLOAT, GL_R11F_G11F_B10F, GL_R11F_G11F_B10F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 11, 11, 10, 0, 0, 0 }, + { Format::ID::R16G16B16A16_FLOAT, GL_RGBA16F, GL_RGBA16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_SINT, GL_RGBA16I, GL_RGBA16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_SNORM, GL_RGBA16_SNORM_EXT, GL_RGBA16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_UINT, GL_RGBA16UI, GL_RGBA16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16A16_UNORM, GL_RGBA16_EXT, GL_RGBA16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 16, 16, 0, 0 }, + { Format::ID::R16G16B16_FLOAT, GL_RGB16F, GL_RGB16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_SINT, GL_RGB16I, GL_RGB16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_SNORM, GL_RGB16_SNORM_EXT, GL_RGB16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_UINT, GL_RGB16UI, GL_RGB16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16B16_UNORM, GL_RGB16_EXT, GL_RGB16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 16, 0, 0, 0 }, + { Format::ID::R16G16_FLOAT, GL_RG16F, GL_RG16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_SINT, GL_RG16I, GL_RG16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_SNORM, GL_RG16_SNORM_EXT, GL_RG16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_UINT, GL_RG16UI, GL_RG16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16G16_UNORM, GL_RG16_EXT, GL_RG16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 16, 0, 0, 0, 0 }, + { Format::ID::R16_FLOAT, GL_R16F, GL_R16F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_SINT, GL_R16I, GL_R16I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_SNORM, GL_R16_SNORM_EXT, GL_R16_SNORM_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_UINT, GL_R16UI, GL_R16UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R16_UNORM, GL_R16_EXT, GL_R16_EXT, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 16, 0, 0, 0, 0, 0 }, + { Format::ID::R32G32B32A32_FLOAT, GL_RGBA32F, GL_RGBA32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32A32_SINT, GL_RGBA32I, GL_RGBA32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32A32_UINT, GL_RGBA32UI, GL_RGBA32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 32, 32, 0, 0 }, + { Format::ID::R32G32B32_FLOAT, GL_RGB32F, GL_RGB32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32B32_SINT, GL_RGB32I, GL_RGB32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32B32_UINT, GL_RGB32UI, GL_RGB32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 32, 0, 0, 0 }, + { Format::ID::R32G32_FLOAT, GL_RG32F, GL_RG32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32G32_SINT, GL_RG32I, GL_RG32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32G32_UINT, GL_RG32UI, GL_RG32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 32, 0, 0, 0, 0 }, + { Format::ID::R32_FLOAT, GL_R32F, GL_R32F, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R32_SINT, GL_R32I, GL_R32I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R32_UINT, GL_R32UI, GL_R32UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 32, 0, 0, 0, 0, 0 }, + { Format::ID::R4G4B4A4_UNORM, GL_RGBA4, GL_RGBA4, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 4, 4, 4, 4, 0, 0 }, + { Format::ID::R5G5B5A1_UNORM, GL_RGB5_A1, GL_RGB5_A1, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0 }, + { Format::ID::R5G6B5_UNORM, GL_RGB565, GL_RGB565, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 5, 6, 5, 0, 0, 0 }, + { Format::ID::R8G8B8A8_SINT, GL_RGBA8I, GL_RGBA8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_SNORM, GL_RGBA8_SNORM, GL_RGBA8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UINT, GL_RGBA8UI, GL_RGBA8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UNORM, GL_RGBA8, GL_RGBA8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0 }, + { Format::ID::R8G8B8_SINT, GL_RGB8I, GL_RGB8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_SNORM, GL_RGB8_SNORM, GL_RGB8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UINT, GL_RGB8UI, GL_RGB8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UNORM, GL_RGB8, GL_RGB8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8B8_UNORM_SRGB, GL_SRGB8, GL_SRGB8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0 }, + { Format::ID::R8G8_SINT, GL_RG8I, GL_RG8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_SNORM, GL_RG8_SNORM, GL_RG8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_UINT, GL_RG8UI, GL_RG8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8G8_UNORM, GL_RG8, GL_RG8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 8, 0, 0, 0, 0 }, + { Format::ID::R8_SINT, GL_R8I, GL_R8I, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_INT, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_SNORM, GL_R8_SNORM, GL_R8_SNORM, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_SIGNED_NORMALIZED, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_UINT, GL_R8UI, GL_R8UI, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_INT, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R8_UNORM, GL_R8, GL_R8, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_UNSIGNED_NORMALIZED, 8, 0, 0, 0, 0, 0 }, + { Format::ID::R9G9B9E5_SHAREDEXP, GL_RGB9_E5, GL_RGB9_E5, GenerateMip, NoCopyFunctions, ReadColor, WriteColor, GL_FLOAT, 9, 9, 9, 0, 0, 0 }, + { Format::ID::S8_UINT, GL_STENCIL_INDEX8, GL_STENCIL_INDEX8, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_INT, 0, 0, 0, 0, 0, 8 }, + // clang-format on +}; + +// static +Format::ID Format::InternalFormatToID(GLenum internalFormat) +{ + switch (internalFormat) + { + case GL_RGBA16_EXT: + return Format::ID::R16G16B16A16_UNORM; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + return Format::ID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK; + case GL_RG8I: + return Format::ID::R8G8_SINT; + case GL_R16F: + return Format::ID::R16_FLOAT; + case GL_RGBA8I: + return Format::ID::R8G8B8A8_SINT; + case GL_RG8UI: + return Format::ID::R8G8_UINT; + case GL_RGBA8_SNORM: + return Format::ID::R8G8B8A8_SNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + return Format::ID::ASTC_12x10_SRGB_BLOCK; + case GL_RG8_SNORM: + return Format::ID::R8G8_SNORM; + case GL_BGR565_ANGLEX: + return Format::ID::B5G6R5_UNORM; + case GL_DEPTH_COMPONENT24: + return Format::ID::D24_UNORM; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return Format::ID::ETC2_R8G8B8A1_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + return Format::ID::ASTC_10x10_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + return Format::ID::ASTC_8x6_SRGB_BLOCK; + case GL_RGB32UI: + return Format::ID::R32G32B32_UINT; + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + return Format::ID::ASTC_6x5_UNORM_BLOCK; + case GL_ALPHA32F_EXT: + return Format::ID::A32_FLOAT; + case GL_R16UI: + return Format::ID::R16_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + return Format::ID::ASTC_5x4_SRGB_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + return Format::ID::ASTC_5x5_SRGB_BLOCK; + case GL_COMPRESSED_R11_EAC: + return Format::ID::EAC_R11_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + return Format::ID::ASTC_10x10_SRGB_BLOCK; + case GL_RGBA32UI: + return Format::ID::R32G32B32A32_UINT; + case GL_R8_SNORM: + return Format::ID::R8_SNORM; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + return Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK; + case GL_LUMINANCE32F_EXT: + return Format::ID::L32_FLOAT; + case GL_RG16_EXT: + return Format::ID::R16G16_UNORM; + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return Format::ID::ETC2_R8G8B8A1_SRGB_BLOCK; + case GL_SRGB8: + return Format::ID::R8G8B8_UNORM_SRGB; + case GL_LUMINANCE8_ALPHA8_EXT: + return Format::ID::L8A8_UNORM; + case GL_BGRX8_ANGLEX: + return Format::ID::B8G8R8X8_UNORM; + case GL_RGB16_SNORM_EXT: + return Format::ID::R16G16B16_SNORM; + case GL_RGBA8UI: + return Format::ID::R8G8B8A8_UINT; + case GL_BGRA4_ANGLEX: + return Format::ID::B4G4R4A4_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + return Format::ID::ETC2_R8G8B8A8_SRGB_BLOCK; + case GL_LUMINANCE8_EXT: + return Format::ID::L8_UNORM; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return Format::ID::BC3_RGBA_UNORM_BLOCK; + case GL_R16I: + return Format::ID::R16_SINT; + case GL_RGB5_A1: + return Format::ID::R5G5B5A1_UNORM; + case GL_RGB16UI: + return Format::ID::R16G16B16_UINT; + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + return Format::ID::ASTC_4x4_UNORM_BLOCK; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + return Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK; + case GL_R16_SNORM_EXT: + return Format::ID::R16_SNORM; + case GL_COMPRESSED_RGB8_ETC2: + return Format::ID::ETC2_R8G8B8_UNORM_BLOCK; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return Format::ID::BC1_RGB_UNORM_SRGB_BLOCK; + case GL_RGBA32F: + return Format::ID::R32G32B32A32_FLOAT; + case GL_RGBA32I: + return Format::ID::R32G32B32A32_SINT; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + return Format::ID::ASTC_8x5_UNORM_BLOCK; + case GL_RG8: + return Format::ID::R8G8_UNORM; + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + return Format::ID::ASTC_8x8_UNORM_BLOCK; + case GL_RGB10_A2: + return Format::ID::R10G10B10A2_UNORM; + case GL_COMPRESSED_SIGNED_RG11_EAC: + return Format::ID::EAC_R11G11_SNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + return Format::ID::ASTC_6x6_SRGB_BLOCK; + case GL_DEPTH_COMPONENT16: + return Format::ID::D16_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + return Format::ID::ASTC_10x5_SRGB_BLOCK; + case GL_RGB32I: + return Format::ID::R32G32B32_SINT; + case GL_R8: + return Format::ID::R8_UNORM; + case GL_RGB32F: + return Format::ID::R32G32B32_FLOAT; + case GL_R16_EXT: + return Format::ID::R16_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + return Format::ID::ASTC_8x8_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + return Format::ID::ASTC_10x5_UNORM_BLOCK; + case GL_R11F_G11F_B10F: + return Format::ID::R11G11B10_FLOAT; + case GL_RGB8: + return Format::ID::R8G8B8_UNORM; + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + return Format::ID::ASTC_5x5_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + return Format::ID::ASTC_8x5_SRGB_BLOCK; + case GL_RGBA16I: + return Format::ID::R16G16B16A16_SINT; + case GL_R8I: + return Format::ID::R8_SINT; + case GL_RGB8_SNORM: + return Format::ID::R8G8B8_SNORM; + case GL_RG32F: + return Format::ID::R32G32_FLOAT; + case GL_DEPTH_COMPONENT32F: + return Format::ID::D32_FLOAT; + case GL_RG32I: + return Format::ID::R32G32_SINT; + case GL_ALPHA8_EXT: + return Format::ID::A8_UNORM; + case GL_RGB16_EXT: + return Format::ID::R16G16B16_UNORM; + case GL_BGRA8_EXT: + return Format::ID::B8G8R8A8_UNORM; + case GL_RG32UI: + return Format::ID::R32G32_UINT; + case GL_RGBA16UI: + return Format::ID::R16G16B16A16_UINT; + case GL_COMPRESSED_RGBA8_ETC2_EAC: + return Format::ID::ETC2_R8G8B8A8_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return Format::ID::BC1_RGBA_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + return Format::ID::ASTC_10x6_UNORM_BLOCK; + case GL_COMPRESSED_SRGB8_ETC2: + return Format::ID::ETC2_R8G8B8_SRGB_BLOCK; + case GL_BGRA8_SRGB_ANGLEX: + return Format::ID::B8G8R8A8_UNORM_SRGB; + case GL_DEPTH32F_STENCIL8: + return Format::ID::D32_FLOAT_S8X24_UINT; + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + return Format::ID::ASTC_6x6_UNORM_BLOCK; + case GL_R32UI: + return Format::ID::R32_UINT; + case GL_BGR5_A1_ANGLEX: + return Format::ID::B5G5R5A1_UNORM; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + return Format::ID::ASTC_12x12_SRGB_BLOCK; + case GL_COMPRESSED_RG11_EAC: + return Format::ID::EAC_R11G11_UNORM_BLOCK; + case GL_SRGB8_ALPHA8: + return Format::ID::R8G8B8A8_UNORM_SRGB; + case GL_LUMINANCE_ALPHA16F_EXT: + return Format::ID::L16A16_FLOAT; + case GL_RGBA: + return Format::ID::R8G8B8A8_UNORM; + case GL_ETC1_RGB8_OES: + return Format::ID::ETC1_R8G8B8_UNORM_BLOCK; + case GL_DEPTH24_STENCIL8: + return Format::ID::D24_UNORM_S8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + return Format::ID::ASTC_4x4_SRGB_BLOCK; + case GL_RGB16I: + return Format::ID::R16G16B16_SINT; + case GL_R8UI: + return Format::ID::R8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + return Format::ID::ASTC_10x6_SRGB_BLOCK; + case GL_RGBA16F: + return Format::ID::R16G16B16A16_FLOAT; + case GL_COMPRESSED_SIGNED_R11_EAC: + return Format::ID::EAC_R11_SNORM_BLOCK; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return Format::ID::BC1_RGB_UNORM_BLOCK; + case GL_RGB8I: + return Format::ID::R8G8B8_SINT; + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + return Format::ID::ASTC_8x6_UNORM_BLOCK; + case GL_STENCIL_INDEX8: + return Format::ID::S8_UINT; + case GL_LUMINANCE_ALPHA32F_EXT: + return Format::ID::L32A32_FLOAT; + case GL_ALPHA16F_EXT: + return Format::ID::A16_FLOAT; + case GL_RGB8UI: + return Format::ID::R8G8B8_UINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + return Format::ID::ASTC_10x8_SRGB_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + return Format::ID::ASTC_12x10_UNORM_BLOCK; + case GL_RGB9_E5: + return Format::ID::R9G9B9E5_SHAREDEXP; + case GL_RGBA16_SNORM_EXT: + return Format::ID::R16G16B16A16_SNORM; + case GL_R32I: + return Format::ID::R32_SINT; + case GL_DEPTH_COMPONENT32_OES: + return Format::ID::D32_UNORM; + case GL_R32F: + return Format::ID::R32_FLOAT; + case GL_NONE: + return Format::ID::NONE; + case GL_RG16F: + return Format::ID::R16G16_FLOAT; + case GL_RGB: + return Format::ID::R8G8B8_UNORM; + case GL_RGB565: + return Format::ID::R5G6B5_UNORM; + case GL_LUMINANCE16F_EXT: + return Format::ID::L16_FLOAT; + case GL_RG16UI: + return Format::ID::R16G16_UINT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return Format::ID::BC2_RGBA_UNORM_BLOCK; + case GL_RG16I: + return Format::ID::R16G16_SINT; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + return Format::ID::ASTC_6x5_SRGB_BLOCK; + case GL_RG16_SNORM_EXT: + return Format::ID::R16G16_SNORM; + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + return Format::ID::ASTC_12x12_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + return Format::ID::ASTC_5x4_UNORM_BLOCK; + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + return Format::ID::ASTC_10x8_UNORM_BLOCK; + case GL_RGBA4: + return Format::ID::R4G4B4A4_UNORM; + case GL_RGBA8: + return Format::ID::R8G8B8A8_UNORM; + case GL_RGB16F: + return Format::ID::R16G16B16_FLOAT; + case GL_RGB10_A2UI: + return Format::ID::R10G10B10A2_UINT; + default: + return Format::ID::NONE; + } +} + +// static +const Format &Format::Get(ID id) +{ + return g_formatInfoTable[static_cast(id)]; +} + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h new file mode 100644 index 0000000000..056ddc833a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferAttachmentObjectImpl.h @@ -0,0 +1,54 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// FramebufferAttachmentObjectImpl.h: +// Common ancenstor for all implementations of FBO attachable-objects. +// This means Surfaces, Textures and Renderbuffers. +// + +#ifndef LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ +#define LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ + +#include "libANGLE/FramebufferAttachment.h" + +namespace rx +{ + +class FramebufferAttachmentObjectImpl : angle::NonCopyable +{ + public: + FramebufferAttachmentObjectImpl() {} + virtual ~FramebufferAttachmentObjectImpl() {} + + virtual gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, + FramebufferAttachmentRenderTarget **rtOut); + + virtual gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex); +}; + +inline gl::Error FramebufferAttachmentObjectImpl::getAttachmentRenderTarget( + const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, + FramebufferAttachmentRenderTarget **rtOut) +{ + UNIMPLEMENTED(); + return gl::OutOfMemory() << "getAttachmentRenderTarget not supported."; +} + +inline gl::Error FramebufferAttachmentObjectImpl::initializeContents( + const gl::Context *context, + const gl::ImageIndex &imageIndex) +{ + UNIMPLEMENTED(); + return gl::OutOfMemory() << "initialize not supported."; +} + +} // namespace rx + +#endif // LIBANGLE_RENDERER_FRAMEBUFFER_ATTACHMENT_OBJECT_IMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h index 680122d0ed..ebb166ca80 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h @@ -24,53 +24,72 @@ struct Rectangle; namespace rx { +class DisplayImpl; class FramebufferImpl : angle::NonCopyable { public: - explicit FramebufferImpl(const gl::Framebuffer::Data &data) : mData(data) { } - virtual ~FramebufferImpl() { } - - 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::Data &data, + explicit FramebufferImpl(const gl::FramebufferState &state) : mState(state) {} + virtual ~FramebufferImpl() {} + virtual void destroy(const gl::Context *context) {} + virtual void destroyDefault(const egl::Display *display) {} + + virtual gl::Error discard(const gl::Context *context, + size_t count, + const GLenum *attachments) = 0; + virtual gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) = 0; + virtual gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) = 0; + + virtual gl::Error clear(const gl::Context *context, GLbitfield mask) = 0; + virtual gl::Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; - virtual gl::Error clearBufferuiv(const gl::Data &data, + virtual gl::Error clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; - virtual gl::Error clearBufferiv(const gl::Data &data, + virtual gl::Error clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; - virtual gl::Error clearBufferfi(const gl::Data &data, + virtual gl::Error clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0; - virtual GLenum getImplementationColorReadFormat() const = 0; - virtual GLenum getImplementationColorReadType() const = 0; - virtual gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const = 0; + virtual GLenum getImplementationColorReadFormat(const gl::Context *context) const = 0; + virtual GLenum getImplementationColorReadType(const gl::Context *context) const = 0; + virtual gl::Error readPixels(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + void *pixels) = 0; - 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 gl::Error blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) = 0; - virtual bool checkStatus() const = 0; + virtual bool checkStatus(const gl::Context *context) const = 0; - virtual void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) = 0; + virtual void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) = 0; - const gl::Framebuffer::Data &getData() const { return mData; } + virtual gl::Error getSamplePosition(size_t index, GLfloat *xy) const = 0; + + const gl::FramebufferState &getState() const { return mState; } protected: - const gl::Framebuffer::Data &mData; + const gl::FramebufferState &mState; }; - } -#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ +#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h index 57c95342d7..c2d069676e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl_mock.h @@ -20,38 +20,39 @@ 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 &, + MockFramebufferImpl() : rx::FramebufferImpl(gl::FramebufferState()) {} + virtual ~MockFramebufferImpl() { destructor(); } + + MOCK_METHOD3(discard, gl::Error(const gl::Context *, size_t, const GLenum *)); + MOCK_METHOD3(invalidate, gl::Error(const gl::Context *, size_t, const GLenum *)); + MOCK_METHOD4(invalidateSub, + gl::Error(const gl::Context *, size_t, const GLenum *, const gl::Rectangle &)); + + MOCK_METHOD2(clear, gl::Error(const gl::Context *, GLbitfield)); + MOCK_METHOD4(clearBufferfv, gl::Error(const gl::Context *, GLenum, GLint, const GLfloat *)); + MOCK_METHOD4(clearBufferuiv, gl::Error(const gl::Context *, GLenum, GLint, const GLuint *)); + MOCK_METHOD4(clearBufferiv, gl::Error(const gl::Context *, GLenum, GLint, const GLint *)); + MOCK_METHOD5(clearBufferfi, gl::Error(const gl::Context *, GLenum, GLint, GLfloat, GLint)); + + MOCK_CONST_METHOD1(getImplementationColorReadFormat, GLenum(const gl::Context *)); + MOCK_CONST_METHOD1(getImplementationColorReadType, GLenum(const gl::Context *)); + MOCK_METHOD5(readPixels, + gl::Error(const gl::Context *, const gl::Rectangle &, GLenum, GLenum, void *)); + + MOCK_CONST_METHOD2(getSamplePosition, gl::Error(size_t, GLfloat *)); + + MOCK_METHOD5(blit, + gl::Error(const gl::Context *, const gl::Rectangle &, const gl::Rectangle &, GLbitfield, - GLenum, - const gl::Framebuffer *)); + GLenum)); - MOCK_CONST_METHOD0(checkStatus, bool()); + MOCK_CONST_METHOD1(checkStatus, bool(const gl::Context *)); - MOCK_METHOD1(syncState, void(const gl::Framebuffer::DirtyBits &)); + MOCK_METHOD2(syncState, void(const gl::Context *, const gl::Framebuffer::DirtyBits &)); - MOCK_METHOD0(destroy, void()); + MOCK_METHOD0(destructor, void()); }; inline ::testing::NiceMock *MakeFramebufferMock() @@ -59,10 +60,10 @@ 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)); + ON_CALL(*framebufferImpl, checkStatus(testing::_)).WillByDefault(::testing::Return(true)); // We must mock the destructor since NiceMock doesn't work for destructors. - EXPECT_CALL(*framebufferImpl, destroy()).Times(1).RetiresOnSaturation(); + EXPECT_CALL(*framebufferImpl, destructor()).Times(1).RetiresOnSaturation(); return framebufferImpl; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h new file mode 100644 index 0000000000..b9a135f596 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/GLImplFactory.h @@ -0,0 +1,93 @@ +// +// 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. +// +// GLImplFactory.h: +// Factory interface for OpenGL ES Impl objects. +// + +#ifndef LIBANGLE_RENDERER_GLIMPLFACTORY_H_ +#define LIBANGLE_RENDERER_GLIMPLFACTORY_H_ + +#include + +#include "angle_gl.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/ProgramPipeline.h" +#include "libANGLE/Shader.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ +class ContextState; +} + +namespace rx +{ +class BufferImpl; +class CompilerImpl; +class ContextImpl; +class FenceNVImpl; +class SyncImpl; +class FramebufferImpl; +class PathImpl; +class ProgramImpl; +class ProgramPipelineImpl; +class QueryImpl; +class RenderbufferImpl; +class SamplerImpl; +class ShaderImpl; +class TextureImpl; +class TransformFeedbackImpl; +class VertexArrayImpl; + +class GLImplFactory : angle::NonCopyable +{ + public: + GLImplFactory() {} + virtual ~GLImplFactory() {} + + // Shader creation + virtual CompilerImpl *createCompiler() = 0; + virtual ShaderImpl *createShader(const gl::ShaderState &data) = 0; + virtual ProgramImpl *createProgram(const gl::ProgramState &data) = 0; + + // Framebuffer creation + virtual FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) = 0; + + // Texture creation + virtual TextureImpl *createTexture(const gl::TextureState &state) = 0; + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer() = 0; + + // Buffer creation + virtual BufferImpl *createBuffer(const gl::BufferState &state) = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) = 0; + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type) = 0; + virtual FenceNVImpl *createFenceNV() = 0; + virtual SyncImpl *createSync() = 0; + + // Transform Feedback creation + virtual TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) = 0; + + // Sampler object creation + virtual SamplerImpl *createSampler(const gl::SamplerState &state) = 0; + + // Program Pipeline object creation + virtual ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) = 0; + + virtual std::vector createPaths(GLsizei range) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_GLIMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Image.h b/src/3rdparty/angle/src/libANGLE/renderer/Image.h deleted file mode 100644 index 62d854c9b6..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Image.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Image.h: Defines the rx::Image class, an abstract base class for the -// renderer-specific classes which will define the interface to the underlying -// surfaces or resources. - -#ifndef LIBANGLE_RENDERER_IMAGE_H_ -#define LIBANGLE_RENDERER_IMAGE_H_ - -#include "common/debug.h" -#include "libANGLE/Error.h" - -#include - -namespace gl -{ -class Framebuffer; -struct Rectangle; -struct Extents; -struct Box; -struct Offset; -struct ImageIndex; -} - -namespace rx -{ -class RendererD3D; -class RenderTarget; -class TextureStorage; - -class Image -{ - public: - Image(); - virtual ~Image() {}; - - GLsizei getWidth() const { return mWidth; } - GLsizei getHeight() const { return mHeight; } - GLsizei getDepth() const { return mDepth; } - GLenum getInternalFormat() const { return mInternalFormat; } - GLenum getTarget() const { return mTarget; } - bool isRenderableFormat() const { return mRenderable; } - - void markDirty() {mDirty = true;} - void markClean() {mDirty = false;} - virtual bool isDirty() const = 0; - - virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; - - virtual gl::Error loadData(const gl::Box &area, GLint unpackAlignment, GLenum type, const void *input) = 0; - virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; - - virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; - virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, - const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; - - protected: - GLsizei mWidth; - GLsizei mHeight; - GLsizei mDepth; - GLenum mInternalFormat; - bool mRenderable; - GLenum mTarget; - - bool mDirty; - - private: - DISALLOW_COPY_AND_ASSIGN(Image); -}; - -} - -#endif // LIBANGLE_RENDERER_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h index e48f1946a8..79694eaebf 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl.h @@ -12,21 +12,31 @@ #include "common/angleutils.h" #include "libANGLE/Error.h" +namespace gl +{ +class Context; +} // namespace gl + namespace egl { class ImageSibling; -} +struct ImageState; +} // namespace egl namespace rx { class ImageImpl : angle::NonCopyable { public: + ImageImpl(const egl::ImageState &state) : mState(state) {} virtual ~ImageImpl() {} virtual egl::Error initialize() = 0; - virtual gl::Error orphan(egl::ImageSibling *sibling) = 0; + virtual gl::Error orphan(const gl::Context *context, egl::ImageSibling *sibling) = 0; + + protected: + const egl::ImageState &mState; }; -} +} // namespace rx #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 index 27fe6a3947..30c0cc2594 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImageImpl_mock.h @@ -18,11 +18,17 @@ namespace rx class MockImageImpl : public ImageImpl { public: + MockImageImpl(const egl::ImageState &state, + EGLenum /*target*/, + const egl::AttributeMap & /*attribs*/) + : ImageImpl(state) + { + } virtual ~MockImageImpl() { destructor(); } MOCK_METHOD0(initialize, egl::Error(void)); - MOCK_METHOD1(orphan, gl::Error(egl::ImageSibling *)); + MOCK_METHOD2(orphan, gl::Error(const gl::Context *, egl::ImageSibling *)); MOCK_METHOD0(destructor, void()); }; -} +} // namespace rx #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 deleted file mode 100644 index b988fcf97f..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// 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. -// -// ImplFactory.h: -// Factory interface for Impl objects. -// - -#ifndef LIBANGLE_RENDERER_IMPLFACTORY_H_ -#define LIBANGLE_RENDERER_IMPLFACTORY_H_ - -#include "libANGLE/Framebuffer.h" -#include "libANGLE/Program.h" -#include "libANGLE/Shader.h" -#include "libANGLE/VertexArray.h" - -namespace rx -{ -class BufferImpl; -class CompilerImpl; -class FenceNVImpl; -class FenceSyncImpl; -class FramebufferImpl; -class ProgramImpl; -class QueryImpl; -class RenderbufferImpl; -class SamplerImpl; -class ShaderImpl; -class TextureImpl; -class TransformFeedbackImpl; -class VertexArrayImpl; - -class ImplFactory : angle::NonCopyable -{ - public: - ImplFactory() {} - virtual ~ImplFactory() {} - - // Shader creation - 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 *createFramebuffer(const gl::Framebuffer::Data &data) = 0; - - // Texture creation - virtual TextureImpl *createTexture(GLenum target) = 0; - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer() = 0; - - // Buffer creation - virtual BufferImpl *createBuffer() = 0; - - // Vertex Array creation - virtual VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) = 0; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type) = 0; - virtual FenceNVImpl *createFenceNV() = 0; - virtual FenceSyncImpl *createFenceSync() = 0; - - // Transform Feedback creation - virtual TransformFeedbackImpl *createTransformFeedback() = 0; - - // Sampler object creation - virtual SamplerImpl *createSampler() = 0; -}; - -} - -#endif // LIBANGLE_RENDERER_IMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h new file mode 100644 index 0000000000..3607f69a2b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/PathImpl.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// PathImpl.h: Defines the Path implementation interface for +// CHROMIUM_path_rendering path objects. + +#ifndef LIBANGLE_RENDERER_PATHIMPL_H_ +#define LIBANGLE_RENDERER_PATHIMPL_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +namespace rx +{ + +class PathImpl : angle::NonCopyable +{ + public: + virtual ~PathImpl() {} + + virtual gl::Error setCommands(GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) = 0; + + virtual void setPathParameter(GLenum pname, GLfloat value) = 0; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_PATHIMPL_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp deleted file mode 100644 index 8fbc53768f..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. - -#include "libANGLE/renderer/ProgramImpl.h" - -#include "common/utilities.h" - -namespace rx -{ - -namespace -{ - -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->substr(open + 1).c_str()); - name->erase(open); - } - - return subscript; -} - -} - -LinkResult::LinkResult(bool linkSuccess, const gl::Error &error) - : linkSuccess(linkSuccess), - error(error) -{ -} - -ProgramImpl::~ProgramImpl() -{ - // Ensure that reset was called by the inherited class during destruction - ASSERT(mUniformIndex.size() == 0); -} - -gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const -{ - ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); - return mUniforms[mUniformIndex[location].index]; -} - -gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const -{ - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - if (mUniforms[uniformIndex]->name == name) - { - return mUniforms[uniformIndex]; - } - } - - return NULL; -} - -gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const -{ - ASSERT(blockIndex < mUniformBlocks.size()); - return mUniformBlocks[blockIndex]; -} - -GLint ProgramImpl::getUniformLocation(std::string name) -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniforms = mUniformIndex.size(); - for (unsigned int location = 0; location < numUniforms; location++) - { - if (mUniformIndex[location].name == name) - { - const int index = mUniformIndex[location].index; - const bool isArray = mUniforms[index]->isArray(); - - if ((isArray && mUniformIndex[location].element == subscript) || - (subscript == GL_INVALID_INDEX)) - { - return location; - } - } - } - - return -1; -} - -GLuint ProgramImpl::getUniformIndex(std::string name) -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - // 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; - } - - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) - { - if (mUniforms[index]->name == name) - { - if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) - { - return index; - } - } - } - - return GL_INVALID_INDEX; -} - -GLuint ProgramImpl::getUniformBlockIndex(std::string name) const -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniformBlocks = mUniformBlocks.size(); - for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) - { - const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; - if (uniformBlock.name == name) - { - const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); - if (subscript == uniformBlock.elementIndex || arrayElementZero) - { - return blockIndex; - } - } - } - - return GL_INVALID_INDEX; -} - -void ProgramImpl::reset() -{ - std::fill(mSemanticIndex, mSemanticIndex + ArraySize(mSemanticIndex), -1); - SafeDeleteContainer(mUniforms); - mUniformIndex.clear(); - SafeDeleteContainer(mUniformBlocks); - mTransformFeedbackLinkedVaryings.clear(); -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h index 1e688045a1..2371b2759c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h @@ -14,32 +14,39 @@ #include "libANGLE/Constants.h" #include "libANGLE/Program.h" #include "libANGLE/Shader.h" -#include "libANGLE/renderer/Renderer.h" #include -namespace rx +namespace gl { +class Context; +struct ProgramLinkedResources; +} -struct LinkResult +namespace sh { - LinkResult(bool linkSuccess, const gl::Error &error) : linkSuccess(linkSuccess), error(error) {} - - bool linkSuccess; - gl::Error error; -}; +struct BlockMemberInfo; +} +namespace rx +{ class ProgramImpl : angle::NonCopyable { public: - ProgramImpl(const gl::Program::Data &data) : mData(data) {} + ProgramImpl(const gl::ProgramState &state) : mState(state) {} virtual ~ProgramImpl() {} + virtual void destroy(const gl::Context *context) {} - virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; - virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; + virtual gl::LinkResult load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) = 0; + virtual void save(const gl::Context *context, gl::BinaryOutputStream *stream) = 0; virtual void setBinaryRetrievableHint(bool retrievable) = 0; + virtual void setSeparable(bool separable) = 0; - virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) = 0; + virtual gl::LinkResult link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + 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; @@ -64,22 +71,37 @@ 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; + // Done in the back-end to avoid having to keep a system copy of uniform data. + virtual void getUniformfv(const gl::Context *context, + GLint location, + GLfloat *params) const = 0; + virtual void getUniformiv(const gl::Context *context, GLint location, GLint *params) const = 0; + virtual void getUniformuiv(const gl::Context *context, + GLint location, + GLuint *params) const = 0; + // TODO: synchronize in syncState when dirty bits exist. virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0; - // 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; + // CHROMIUM_path_rendering + // Set parameters to control fragment shader input variable interpolation + virtual void setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) = 0; + + // Implementation-specific method for ignoring unreferenced uniforms. Some implementations may + // perform more extensive analysis and ignore some locations that ANGLE doesn't detect as + // unreferenced. This method is not required to be overriden by a back-end. + virtual void markUnusedUniformLocations(std::vector *uniformLocations, + std::vector *samplerBindings) + { + } protected: - const gl::Program::Data &mData; + const gl::ProgramState &mState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_PROGRAMIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h index d6aa238f64..4717ab8843 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl_mock.h @@ -12,6 +12,7 @@ #include "gmock/gmock.h" +#include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/renderer/ProgramImpl.h" namespace rx @@ -20,14 +21,18 @@ namespace rx class MockProgramImpl : public rx::ProgramImpl { public: - MockProgramImpl() : ProgramImpl(gl::Program::Data()) {} - virtual ~MockProgramImpl() { destroy(); } + MockProgramImpl() : ProgramImpl(gl::ProgramState()) {} + virtual ~MockProgramImpl() { destructor(); } - MOCK_METHOD2(load, LinkResult(gl::InfoLog &, gl::BinaryInputStream *)); - MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *)); + MOCK_METHOD3(load, gl::LinkResult(const gl::Context *, gl::InfoLog &, gl::BinaryInputStream *)); + MOCK_METHOD2(save, void(const gl::Context *, gl::BinaryOutputStream *)); MOCK_METHOD1(setBinaryRetrievableHint, void(bool)); + MOCK_METHOD1(setSeparable, void(bool)); - MOCK_METHOD2(link, LinkResult(const gl::Data &, gl::InfoLog &)); + MOCK_METHOD3(link, + gl::LinkResult(const gl::Context *, + const gl::ProgramLinkedResources &, + gl::InfoLog &)); MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *)); MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *)); @@ -53,11 +58,15 @@ class MockProgramImpl : public rx::ProgramImpl MOCK_METHOD4(setUniformMatrix3x4fv, void(GLint, GLsizei, GLboolean, const GLfloat *)); MOCK_METHOD4(setUniformMatrix4x3fv, void(GLint, GLsizei, GLboolean, const GLfloat *)); + MOCK_CONST_METHOD3(getUniformfv, void(const gl::Context *, GLint, GLfloat *)); + MOCK_CONST_METHOD3(getUniformiv, void(const gl::Context *, GLint, GLint *)); + MOCK_CONST_METHOD3(getUniformuiv, void(const gl::Context *, GLint, GLuint *)); + 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_METHOD4(setPathFragmentInputGen, + void(const std::string &, GLenum, GLint, const GLfloat *)); - MOCK_METHOD0(destroy, void()); + MOCK_METHOD0(destructor, void()); }; inline ::testing::NiceMock *MakeProgramMock() @@ -65,7 +74,7 @@ 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(); + EXPECT_CALL(*programImpl, destructor()).Times(1).RetiresOnSaturation(); return programImpl; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h new file mode 100644 index 0000000000..242e9260f1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramPipelineImpl.h @@ -0,0 +1,32 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramPipelineImpl.h: Defines the abstract rx::ProgramPipelineImpl class. + +#ifndef LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ +#define LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/ProgramPipeline.h" + +namespace rx +{ +class ContextImpl; + +class ProgramPipelineImpl : public angle::NonCopyable +{ + public: + ProgramPipelineImpl(const gl::ProgramPipelineState &state) : mState(state) {} + virtual ~ProgramPipelineImpl() {} + virtual void destroy(const ContextImpl *contextImpl) {} + + protected: + const gl::ProgramPipelineState &mState; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_PROGRAMPIPELINEIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp deleted file mode 100644 index ea5a40a21a..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// RenderbufferImpl.h: Implements the shared methods of the abstract class gl::RenderbufferImpl - -#include "libANGLE/renderer/RenderbufferImpl.h" - -namespace rx -{ -RenderbufferImpl::RenderbufferImpl() -{ -} - -RenderbufferImpl::~RenderbufferImpl() -{ -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h index 75b4cdcfee..a70ab1d0f0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h @@ -12,7 +12,7 @@ #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" namespace egl { @@ -26,13 +26,25 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl { public: 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; + ~RenderbufferImpl() override {} + virtual gl::Error onDestroy(const gl::Context *context); + + virtual gl::Error setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) = 0; + virtual gl::Error setStorageMultisample(const gl::Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height) = 0; + virtual gl::Error setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) = 0; }; +inline gl::Error RenderbufferImpl::onDestroy(const gl::Context *context) +{ + return gl::NoError(); +} } #endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h index c2c67cc76a..408b9a5fe9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl_mock.h @@ -21,11 +21,16 @@ 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_METHOD4(setStorage, gl::Error(const gl::Context *, GLenum, size_t, size_t)); + MOCK_METHOD5(setStorageMultisample, + gl::Error(const gl::Context *, size_t, GLenum, size_t, size_t)); + MOCK_METHOD2(setStorageEGLImageTarget, gl::Error(const gl::Context *, egl::Image *)); + + MOCK_METHOD4(getAttachmentRenderTarget, + gl::Error(const gl::Context *, + GLenum, + const gl::ImageIndex &, + FramebufferAttachmentRenderTarget **)); MOCK_METHOD0(destructor, void()); }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp deleted file mode 100644 index f3f7f55bb9..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances. - -#include "common/utilities.h" -#include "libANGLE/AttributeMap.h" -#include "libANGLE/renderer/Renderer.h" - -#include - -namespace rx -{ -Renderer::Renderer() : mCapsInitialized(false) -{ -} - -Renderer::~Renderer() -{ -} - -void Renderer::ensureCapsInitialized() const -{ - if (!mCapsInitialized) - { - generateCaps(&mCaps, &mTextureCaps, &mExtensions, &mLimitations); - mCapsInitialized = true; - } -} - -const gl::Caps &Renderer::getRendererCaps() const -{ - ensureCapsInitialized(); - - return mCaps; -} - -const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const -{ - ensureCapsInitialized(); - - return mTextureCaps; -} - -const gl::Extensions &Renderer::getRendererExtensions() const -{ - ensureCapsInitialized(); - - return mExtensions; -} - -const gl::Limitations &Renderer::getRendererLimitations() const -{ - ensureCapsInitialized(); - - return mLimitations; -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h deleted file mode 100644 index d0da2b140c..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Renderer.h: Defines a back-end specific class that hides the details of the -// implementation-specific renderer. - -#ifndef LIBANGLE_RENDERER_RENDERER_H_ -#define LIBANGLE_RENDERER_RENDERER_H_ - -#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 "common/mathutil.h" - -#include - -#include - -namespace egl -{ -class AttributeMap; -class Display; -class Surface; -} - -namespace rx -{ -struct TranslatedIndexData; -struct SourceIndexData; -struct WorkaroundsD3D; -class DisplayImpl; - -class Renderer : public ImplFactory -{ - public: - Renderer(); - virtual ~Renderer(); - - virtual gl::Error flush() = 0; - virtual gl::Error finish() = 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 - virtual void notifyDeviceLost() = 0; - virtual bool isDeviceLost() const = 0; - virtual bool testDeviceLost() = 0; - virtual bool testDeviceResettable() = 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 gl::Limitations &getRendererLimitations() const; - - private: - 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 gl::Limitations mLimitations; -}; - -} -#endif // LIBANGLE_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h index 85383cf8e5..66e1079b64 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/SamplerImpl.h @@ -11,15 +11,29 @@ #include "common/angleutils.h" +namespace gl +{ +class Context; +struct SamplerState; +} // namespace gl + namespace rx { -class SamplerImpl : public angle::NonCopyable +class SamplerImpl : angle::NonCopyable { public: - SamplerImpl() {} + SamplerImpl(const gl::SamplerState &state) : mState(state) {} virtual ~SamplerImpl() {} + + virtual void syncState(const gl::Context *context) + { + // Default implementation: no-op. + } + + protected: + const gl::SamplerState &mState; }; -} +} // namespace rx #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 5a466377a5..77e02d0237 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h @@ -18,21 +18,21 @@ namespace rx class ShaderImpl : angle::NonCopyable { public: - ShaderImpl(const gl::Shader::Data &data) : mData(data) {} + ShaderImpl(const gl::ShaderState &data) : mData(data) {} virtual ~ShaderImpl() { } - // Returns additional ShCompile options. - virtual int prepareSourceAndReturnOptions(std::stringstream *sourceStream, - std::string *sourcePath) = 0; + // Returns additional sh::Compile options. + virtual ShCompileOptions 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; virtual std::string getDebugInfo() const = 0; - const gl::Shader::Data &getData() const { return mData; } + const gl::ShaderState &getData() const { return mData; } protected: - const gl::Shader::Data &mData; + const gl::ShaderState &mData; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h new file mode 100644 index 0000000000..1915bf75d3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/StreamProducerImpl.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// StreamProducerImpl.h: Defines the abstract rx::StreamProducerImpl class. + +#ifndef LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ +#define LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Stream.h" + +namespace rx +{ + +class StreamProducerImpl : angle::NonCopyable +{ + public: + explicit StreamProducerImpl() {} + virtual ~StreamProducerImpl() {} + + // Validates the ability for the producer to accept an arbitrary pointer to a frame. All + // pointers should be validated through this function before being used to produce a frame. + virtual egl::Error validateD3DNV12Texture(void *pointer) const = 0; + + // Constructs a frame from an arbitrary external pointer that points to producer specific frame + // data. Replaces the internal frame with the new one. + virtual void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) = 0; + + // Returns an OpenGL texture interpretation of some frame attributes for the purpose of + // constructing an OpenGL texture from a frame. Depending on the producer and consumer, some + // frames may have multiple "planes" with different OpenGL texture representations. + virtual egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) = 0; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_STREAMPRODUCERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp index 36f5fdca3f..cd2fa3dde6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp @@ -11,7 +11,7 @@ namespace rx { -SurfaceImpl::SurfaceImpl() +SurfaceImpl::SurfaceImpl(const egl::SurfaceState &state) : mState(state) { } @@ -19,4 +19,10 @@ SurfaceImpl::~SurfaceImpl() { } +egl::Error SurfaceImpl::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) +{ + UNREACHABLE(); + return egl::EglBadSurface() << "swapWithDamage implementation missing."; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h index 32125d542c..eaa27de281 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h @@ -9,35 +9,51 @@ #ifndef LIBANGLE_RENDERER_SURFACEIMPL_H_ #define LIBANGLE_RENDERER_SURFACEIMPL_H_ +#include +#include + #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" + +namespace gl +{ +class FramebufferState; +} namespace egl { class Display; struct Config; +struct SurfaceState; +class Thread; } namespace rx { - class FramebufferImpl; class SurfaceImpl : public FramebufferAttachmentObjectImpl { public: - SurfaceImpl(); - virtual ~SurfaceImpl(); + SurfaceImpl(const egl::SurfaceState &surfaceState); + ~SurfaceImpl() override; + virtual void destroy(const egl::Display *display) {} - 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 initialize(const egl::Display *display) = 0; + virtual FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) = 0; + virtual egl::Error swap(const gl::Context *context) = 0; + virtual egl::Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects); + virtual egl::Error postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) = 0; virtual egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) = 0; virtual egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) = 0; virtual egl::Error releaseTexImage(EGLint buffer) = 0; + virtual egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) = 0; virtual void setSwapInterval(EGLint interval) = 0; // width and height can change with client window resizing @@ -46,6 +62,9 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl virtual EGLint isPostSubBufferSupported() const = 0; virtual EGLint getSwapBehavior() const = 0; + + protected: + const egl::SurfaceState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h new file mode 100644 index 0000000000..22c92c3729 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SyncImpl.h @@ -0,0 +1,34 @@ +// +// 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. +// + +// SyncImpl.h: Defines the rx::SyncImpl class. + +#ifndef LIBANGLE_RENDERER_FENCESYNCIMPL_H_ +#define LIBANGLE_RENDERER_FENCESYNCIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ + +class SyncImpl : angle::NonCopyable +{ + public: + SyncImpl(){}; + virtual ~SyncImpl(){}; + + 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; +}; +} + +#endif // LIBANGLE_RENDERER_FENCESYNCIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp new file mode 100644 index 0000000000..830d30e6d1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2016 The ANGLE Project 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.cpp: Defines the abstract rx::TextureImpl classes. + +#include "libANGLE/renderer/TextureImpl.h" + +namespace rx +{ + +TextureImpl::TextureImpl(const gl::TextureState &state) : mState(state) +{ +} + +TextureImpl::~TextureImpl() +{ +} + +gl::Error TextureImpl::onDestroy(const gl::Context *context) +{ + return gl::NoError(); +} + +gl::Error TextureImpl::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_texture exposed but not implemented."; +} + +gl::Error TextureImpl::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_texture exposed but not implemented."; +} + +gl::Error TextureImpl::copyCompressedTexture(const gl::Context *context, const gl::Texture *source) +{ + UNREACHABLE(); + return gl::InternalError() << "CHROMIUM_copy_compressed_texture exposed but not implemented."; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h index ad4ec8d830..3b4f28f5f7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h @@ -14,8 +14,10 @@ #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/Error.h" -#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/ImageIndex.h" +#include "libANGLE/Stream.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h" namespace egl { @@ -36,38 +38,120 @@ struct TextureState; namespace rx { +class ContextImpl; class TextureImpl : public FramebufferAttachmentObjectImpl { public: - TextureImpl() {} - virtual ~TextureImpl() {} - - virtual void setUsage(GLenum usage) = 0; - - virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; - virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - 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, 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, size_t imageSize, const uint8_t *pixels) = 0; - - virtual gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + TextureImpl(const gl::TextureState &state); + ~TextureImpl() override; + + virtual gl::Error onDestroy(const gl::Context *context); + + virtual gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) = 0; + virtual gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) = 0; + + virtual gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) = 0; + virtual gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) = 0; + + virtual gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) = 0; - virtual gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + virtual gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; - virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 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; + virtual gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source); + virtual gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source); + + virtual gl::Error copyCompressedTexture(const gl::Context *context, const gl::Texture *source); + + virtual gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) = 0; + + virtual gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalformat, + const gl::Extents &size, + bool fixedSampleLocations) = 0; + + virtual gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) = 0; + + virtual gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) = 0; + + virtual gl::Error generateMipmap(const gl::Context *context) = 0; + + virtual gl::Error setBaseLevel(const gl::Context *context, GLuint baseLevel) = 0; + + virtual gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) = 0; + virtual gl::Error releaseTexImage(const gl::Context *context) = 0; + + virtual void syncState(const gl::Texture::DirtyBits &dirtyBits) = 0; + + protected: + const gl::TextureState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h index 3eb43f0033..e7fa441781 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl_mock.h @@ -19,23 +19,111 @@ namespace rx class MockTextureImpl : public TextureImpl { public: + MockTextureImpl() : TextureImpl(mMockState), mMockState(GL_TEXTURE_2D) {} 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_METHOD9(setImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + const gl::Extents &, + GLenum, + GLenum, + const gl::PixelUnpackState &, + const uint8_t *)); + MOCK_METHOD8(setSubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Box &, + GLenum, + GLenum, + const gl::PixelUnpackState &, + const uint8_t *)); + MOCK_METHOD8(setCompressedImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + const gl::Extents &, + const gl::PixelUnpackState &, + size_t, + const uint8_t *)); + MOCK_METHOD8(setCompressedSubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Box &, + GLenum, + const gl::PixelUnpackState &, + size_t, + const uint8_t *)); + MOCK_METHOD6(copyImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Rectangle &, + GLenum, + const gl::Framebuffer *)); + MOCK_METHOD6(copySubImage, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Offset &, + const gl::Rectangle &, + const gl::Framebuffer *)); + MOCK_METHOD10(copyTexture, + gl::Error(const gl::Context *, + GLenum, + size_t, + GLenum, + GLenum, + size_t, + bool, + bool, + bool, + const gl::Texture *)); + MOCK_METHOD10(copySubTexture, + gl::Error(const gl::Context *, + GLenum, + size_t, + const gl::Offset &, + size_t, + const gl::Rectangle &, + bool, + bool, + bool, + const gl::Texture *)); + MOCK_METHOD2(copyCompressedTexture, gl::Error(const gl::Context *, const gl::Texture *source)); + MOCK_METHOD5(setStorage, + gl::Error(const gl::Context *, GLenum, size_t, GLenum, const gl::Extents &)); + MOCK_METHOD4(setImageExternal, + gl::Error(const gl::Context *, + GLenum, + egl::Stream *, + const egl::Stream::GLTextureDescription &)); + MOCK_METHOD3(setEGLImageTarget, gl::Error(const gl::Context *, GLenum, egl::Image *)); + MOCK_METHOD1(generateMipmap, gl::Error(const gl::Context *)); + MOCK_METHOD2(bindTexImage, gl::Error(const gl::Context *, egl::Surface *)); + MOCK_METHOD1(releaseTexImage, gl::Error(const gl::Context *)); + + MOCK_METHOD4(getAttachmentRenderTarget, + gl::Error(const gl::Context *, + GLenum, + const gl::ImageIndex &, + FramebufferAttachmentRenderTarget **)); + + MOCK_METHOD6(setStorageMultisample, + gl::Error(const gl::Context *, GLenum, GLsizei, GLint, const gl::Extents &, bool)); + + MOCK_METHOD2(setBaseLevel, gl::Error(const gl::Context *, GLuint)); + + MOCK_METHOD1(syncState, void(const gl::Texture::DirtyBits &)); MOCK_METHOD0(destructor, void()); + + protected: + gl::TextureState mMockState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h index 5df7cad87b..ad371e9b36 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h @@ -18,6 +18,7 @@ namespace rx class TransformFeedbackImpl : angle::NonCopyable { public: + TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {} virtual ~TransformFeedbackImpl() { } virtual void begin(GLenum primitiveMode) = 0; @@ -25,8 +26,12 @@ class TransformFeedbackImpl : angle::NonCopyable 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; + virtual void bindGenericBuffer(const gl::BindingPointer &binding) = 0; + virtual void bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) = 0; + + protected: + const gl::TransformFeedbackState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h index c7d2fc620d..2de3ad79a9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl_mock.h @@ -19,6 +19,10 @@ namespace rx class MockTransformFeedbackImpl : public TransformFeedbackImpl { public: + MockTransformFeedbackImpl(const gl::TransformFeedbackState &state) + : TransformFeedbackImpl(state) + { + } ~MockTransformFeedbackImpl() { destructor(); } MOCK_METHOD1(begin, void(GLenum primitiveMode)); @@ -26,8 +30,8 @@ class MockTransformFeedbackImpl : public TransformFeedbackImpl MOCK_METHOD0(pause, void()); MOCK_METHOD0(resume, void()); - MOCK_METHOD1(bindGenericBuffer, void(const BindingPointer &)); - MOCK_METHOD2(bindIndexedBuffer, void(size_t, const OffsetBindingPointer &)); + MOCK_METHOD1(bindGenericBuffer, void(const gl::BindingPointer &)); + MOCK_METHOD2(bindIndexedBuffer, void(size_t, const gl::OffsetBindingPointer &)); MOCK_METHOD0(destructor, void()); }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h index 13617c7ecb..e48cc53d6c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h @@ -15,15 +15,21 @@ namespace rx { +class ContextImpl; class VertexArrayImpl : angle::NonCopyable { public: - VertexArrayImpl(const gl::VertexArray::Data &data) : mData(data) { } - virtual ~VertexArrayImpl() { } - virtual void syncState(const gl::VertexArray::DirtyBits &dirtyBits) {} + VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {} + virtual void syncState(const gl::Context *context, const gl::VertexArray::DirtyBits &dirtyBits) + { + } + + virtual void destroy(const gl::Context *context) {} + virtual ~VertexArrayImpl() {} + protected: - const gl::VertexArray::Data &mData; + const gl::VertexArrayState &mState; }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h deleted file mode 100644 index b73f4a5472..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// angletypes.h: Workarounds for driver bugs and other issues. - -#ifndef LIBANGLE_RENDERER_WORKAROUNDS_H_ -#define LIBANGLE_RENDERER_WORKAROUNDS_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 : angle::NonCopyable -{ - D3DCompilerWorkarounds() - : skipOptimization(false), - useMaxOptimization(false), - enableIEEEStrictness(false) - {} - - void reset() - { - skipOptimization = false; - useMaxOptimization = false; - enableIEEEStrictness = false; - } - - bool skipOptimization; - bool useMaxOptimization; - - // IEEE strictness needs to be enabled for NANs to work. - bool enableIEEEStrictness; -}; - -struct Workarounds -{ - Workarounds() - : 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_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json new file mode 100644 index 0000000000..5b3a226e2e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_data.json @@ -0,0 +1,24 @@ +{ + "B5G6R5_UNORM": { + "fboImplementationInternalFormat": "GL_RGB565" + }, + "B5G5R5A1_UNORM": { + "fboImplementationInternalFormat": "GL_RGB5_A1", + "channelStruct": "A1R5G5B5" + }, + "B8G8R8X8_UNORM": { + "glInternalFormat": "GL_BGRA8_EXT", + "channelStruct": "B8G8R8X8" + }, + "R9G9B9E5_SHAREDEXP": { + "componentType": "float", + "channelStruct": "R9G9B9E5" + }, + "B4G4R4A4_UNORM": { + "fboImplementationInternalFormat": "GL_RGBA4", + "channelStruct": "A4R4G4B4" + }, + "R8G8B8A8_UNORM_SRGB": { + "channelStruct": "R8G8B8A8SRGB" + } +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json new file mode 100644 index 0000000000..5a4e487cbd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/angle_format_map.json @@ -0,0 +1,132 @@ +[ + [ "GL_ALPHA16F_EXT", "A16_FLOAT" ], + [ "GL_ALPHA32F_EXT", "A32_FLOAT" ], + [ "GL_ALPHA8_EXT", "A8_UNORM" ], + [ "GL_BGR565_ANGLEX", "B5G6R5_UNORM" ], + [ "GL_BGR5_A1_ANGLEX", "B5G5R5A1_UNORM" ], + [ "GL_BGRA4_ANGLEX", "B4G4R4A4_UNORM" ], + [ "GL_BGRA8_EXT", "B8G8R8A8_UNORM" ], + [ "GL_BGRA8_SRGB_ANGLEX", "B8G8R8A8_UNORM_SRGB"], + [ "GL_BGRX8_ANGLEX", "B8G8R8X8_UNORM" ], + [ "GL_COMPRESSED_R11_EAC", "EAC_R11_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RG11_EAC", "EAC_R11G11_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB8_ETC2", "ETC2_R8G8B8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", "ETC2_R8G8B8A1_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA8_ETC2_EAC", "ETC2_R8G8B8A8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", "BC1_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE", "BC2_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE", "BC3_RGBA_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_4x4_KHR", "ASTC_4x4_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_5x4_KHR", "ASTC_5x4_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_5x5_KHR", "ASTC_5x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_6x5_KHR", "ASTC_6x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_6x6_KHR", "ASTC_6x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x5_KHR", "ASTC_8x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x6_KHR", "ASTC_8x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_8x8_KHR", "ASTC_8x8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x5_KHR", "ASTC_10x5_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x6_KHR", "ASTC_10x6_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", "ASTC_10x8_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", "ASTC_10x10_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", "ASTC_12x10_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGBA_ASTC_12x12_KHR", "ASTC_12x12_UNORM_BLOCK" ], + [ "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", "BC1_RGB_UNORM_BLOCK" ], + [ "GL_COMPRESSED_SIGNED_R11_EAC", "EAC_R11_SNORM_BLOCK" ], + [ "GL_COMPRESSED_SIGNED_RG11_EAC", "EAC_R11G11_SNORM_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", "ASTC_4x4_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", "ASTC_5x4_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", "ASTC_5x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", "ASTC_6x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", "ASTC_6x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", "ASTC_8x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", "ASTC_8x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", "ASTC_8x8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", "ASTC_10x5_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", "ASTC_10x6_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", "ASTC_10x8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", "ASTC_10x10_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", "ASTC_12x10_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", "ASTC_12x12_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", "ETC2_R8G8B8A8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_ETC2", "ETC2_R8G8B8_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", "ETC2_R8G8B8A1_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", "BC1_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", "BC2_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", "BC3_RGBA_UNORM_SRGB_BLOCK" ], + [ "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT", "BC1_RGB_UNORM_SRGB_BLOCK" ], + [ "GL_DEPTH24_STENCIL8", "D24_UNORM_S8_UINT" ], + [ "GL_DEPTH32F_STENCIL8", "D32_FLOAT_S8X24_UINT" ], + [ "GL_DEPTH_COMPONENT16", "D16_UNORM" ], + [ "GL_DEPTH_COMPONENT24", "D24_UNORM" ], + [ "GL_DEPTH_COMPONENT32F", "D32_FLOAT" ], + [ "GL_DEPTH_COMPONENT32_OES", "D32_UNORM" ], + [ "GL_ETC1_RGB8_OES", "ETC1_R8G8B8_UNORM_BLOCK" ], + [ "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE", "ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK" ], + [ "GL_LUMINANCE16F_EXT", "L16_FLOAT" ], + [ "GL_LUMINANCE32F_EXT", "L32_FLOAT" ], + [ "GL_LUMINANCE8_ALPHA8_EXT", "L8A8_UNORM" ], + [ "GL_LUMINANCE8_EXT", "L8_UNORM" ], + [ "GL_LUMINANCE_ALPHA16F_EXT", "L16A16_FLOAT" ], + [ "GL_LUMINANCE_ALPHA32F_EXT", "L32A32_FLOAT" ], + [ "GL_NONE", "NONE" ], + [ "GL_R11F_G11F_B10F", "R11G11B10_FLOAT" ], + [ "GL_R16F", "R16_FLOAT" ], + [ "GL_R16I", "R16_SINT" ], + [ "GL_R16UI", "R16_UINT" ], + [ "GL_R32F", "R32_FLOAT" ], + [ "GL_R32I", "R32_SINT" ], + [ "GL_R32UI", "R32_UINT" ], + [ "GL_R8", "R8_UNORM" ], + [ "GL_R8I", "R8_SINT" ], + [ "GL_R8UI", "R8_UINT" ], + [ "GL_R8_SNORM", "R8_SNORM" ], + [ "GL_RG16F", "R16G16_FLOAT" ], + [ "GL_RG16I", "R16G16_SINT" ], + [ "GL_RG16UI", "R16G16_UINT" ], + [ "GL_RG32F", "R32G32_FLOAT" ], + [ "GL_RG32I", "R32G32_SINT" ], + [ "GL_RG32UI", "R32G32_UINT" ], + [ "GL_RG8", "R8G8_UNORM" ], + [ "GL_RG8I", "R8G8_SINT" ], + [ "GL_RG8UI", "R8G8_UINT" ], + [ "GL_RG8_SNORM", "R8G8_SNORM" ], + [ "GL_RGB", "R8G8B8_UNORM" ], + [ "GL_RGB10_A2", "R10G10B10A2_UNORM" ], + [ "GL_RGB10_A2UI", "R10G10B10A2_UINT" ], + [ "GL_RGB16F", "R16G16B16_FLOAT" ], + [ "GL_RGB16I", "R16G16B16_SINT" ], + [ "GL_RGB16UI", "R16G16B16_UINT" ], + [ "GL_RGB32F", "R32G32B32_FLOAT" ], + [ "GL_RGB32I", "R32G32B32_SINT" ], + [ "GL_RGB32UI", "R32G32B32_UINT" ], + [ "GL_RGB565", "R5G6B5_UNORM" ], + [ "GL_RGB5_A1", "R5G5B5A1_UNORM" ], + [ "GL_RGB8", "R8G8B8_UNORM" ], + [ "GL_RGB8I", "R8G8B8_SINT" ], + [ "GL_RGB8UI", "R8G8B8_UINT" ], + [ "GL_RGB8_SNORM", "R8G8B8_SNORM" ], + [ "GL_RGB9_E5", "R9G9B9E5_SHAREDEXP" ], + [ "GL_RGBA", "R8G8B8A8_UNORM" ], + [ "GL_RGBA16F", "R16G16B16A16_FLOAT" ], + [ "GL_RGBA16I", "R16G16B16A16_SINT" ], + [ "GL_RGBA16UI", "R16G16B16A16_UINT" ], + [ "GL_RGBA32F", "R32G32B32A32_FLOAT" ], + [ "GL_RGBA32I", "R32G32B32A32_SINT" ], + [ "GL_RGBA32UI", "R32G32B32A32_UINT" ], + [ "GL_RGBA4", "R4G4B4A4_UNORM" ], + [ "GL_RGBA8", "R8G8B8A8_UNORM" ], + [ "GL_RGBA8I", "R8G8B8A8_SINT" ], + [ "GL_RGBA8UI", "R8G8B8A8_UINT" ], + [ "GL_RGBA8_SNORM", "R8G8B8A8_SNORM" ], + [ "GL_SRGB8", "R8G8B8_UNORM_SRGB" ], + [ "GL_SRGB8_ALPHA8", "R8G8B8A8_UNORM_SRGB" ], + [ "GL_STENCIL_INDEX8", "S8_UINT" ], + [ "GL_R16_EXT", "R16_UNORM" ], + [ "GL_RG16_EXT", "R16G16_UNORM" ], + [ "GL_RGB16_EXT", "R16G16B16_UNORM" ], + [ "GL_RGBA16_EXT", "R16G16B16A16_UNORM" ], + [ "GL_R16_SNORM_EXT", "R16_SNORM" ], + [ "GL_RG16_SNORM_EXT", "R16G16_SNORM" ], + [ "GL_RGB16_SNORM_EXT", "R16G16B16_SNORM" ], + [ "GL_RGBA16_SNORM_EXT", "R16G16B16A16_SNORM" ] +] diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp index ffca99c3ac..7769ab2b75 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp @@ -12,42 +12,33 @@ #include "common/utilities.h" #include "libANGLE/renderer/d3d/IndexBuffer.h" #include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" namespace rx { unsigned int BufferD3D::mNextSerial = 1; -BufferD3D::BufferD3D(BufferFactoryD3D *factory) - : BufferImpl(), +BufferD3D::BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory) + : BufferImpl(state), mFactory(factory), - mStaticVertexBuffer(nullptr), mStaticIndexBuffer(nullptr), - mStaticBufferCache(nullptr), mStaticBufferCacheTotalSize(0), mStaticVertexBufferOutOfDate(false), mUnmodifiedDataUse(0), - mUsage(D3D_BUFFER_USAGE_STATIC) + mUsage(D3DBufferUsage::STATIC) { updateSerial(); } BufferD3D::~BufferD3D() { - SafeDelete(mStaticVertexBuffer); SafeDelete(mStaticIndexBuffer); - - emptyStaticBufferCache(); } void BufferD3D::emptyStaticBufferCache() { - if (mStaticBufferCache != nullptr) - { - SafeDeleteContainer(*mStaticBufferCache); - SafeDelete(mStaticBufferCache); - } - + mStaticVertexBuffers.clear(); mStaticBufferCacheTotalSize = 0; } @@ -56,35 +47,37 @@ void BufferD3D::updateSerial() mSerial = mNextSerial++; } -void BufferD3D::updateD3DBufferUsage(GLenum usage) +void BufferD3D::updateD3DBufferUsage(const gl::Context *context, gl::BufferUsage usage) { switch (usage) { - case GL_STATIC_DRAW: - case GL_STATIC_READ: - case GL_STATIC_COPY: - mUsage = D3D_BUFFER_USAGE_STATIC; - initializeStaticData(); + case gl::BufferUsage::StaticCopy: + case gl::BufferUsage::StaticDraw: + case gl::BufferUsage::StaticRead: + mUsage = D3DBufferUsage::STATIC; + initializeStaticData(context); 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; + case gl::BufferUsage::DynamicCopy: + case gl::BufferUsage::DynamicDraw: + case gl::BufferUsage::DynamicRead: + case gl::BufferUsage::StreamCopy: + case gl::BufferUsage::StreamDraw: + case gl::BufferUsage::StreamRead: + mUsage = D3DBufferUsage::DYNAMIC; break; default: UNREACHABLE(); } } -void BufferD3D::initializeStaticData() +void BufferD3D::initializeStaticData(const gl::Context *context) { - if (!mStaticVertexBuffer) + if (mStaticVertexBuffers.empty()) { - mStaticVertexBuffer = new StaticVertexBufferInterface(mFactory); + StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); + mStaticVertexBuffers.push_back( + std::unique_ptr(newStaticBuffer)); } if (!mStaticIndexBuffer) { @@ -97,168 +90,101 @@ StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer() return mStaticIndexBuffer; } -StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer( - const gl::VertexAttribute &attribute, - D3DStaticBufferCreationType creationType) +StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding) { - if (!mStaticVertexBuffer) + if (mStaticVertexBuffers.empty()) { // 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. + if (mStaticVertexBuffers.size() == 1 && mStaticVertexBuffers[0]->empty()) { - // Early out, the attribute can be added to mStaticVertexBuffer or is already in there - return mStaticVertexBuffer; + return mStaticVertexBuffers[0].get(); } - // At this point, see if any of the existing static buffers contains the attribute data + // Cache size limiting: track the total allocated buffer sizes. + size_t currentTotalSize = 0; - // If the default static vertex buffer contains the attribute, then return it - if (mStaticVertexBuffer->lookupAttribute(attribute, nullptr)) - { - return mStaticVertexBuffer; - } - - if (mStaticBufferCache != nullptr) + // At this point, see if any of the existing static buffers contains the attribute data + // If there is a cached static buffer that already contains the attribute, then return it + for (const auto &staticBuffer : mStaticVertexBuffers) { - // If there is a cached static buffer that already contains the attribute, then return it - for (StaticVertexBufferInterface *staticBuffer : *mStaticBufferCache) + if (staticBuffer->matchesAttribute(attribute, binding)) { - if (staticBuffer->lookupAttribute(attribute, nullptr)) - { - return staticBuffer; - } + return staticBuffer.get(); } - } - 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; + currentTotalSize += staticBuffer->getBufferSize(); } - // At this point, we must create a new static buffer for the attribute data - if (creationType != D3D_BUFFER_CREATE_IF_NECESSARY) - { - return nullptr; - } + // Cache size limiting: Clean-up threshold is four times the base buffer size, with a minimum. + ASSERT(getSize() < std::numeric_limits::max() / 4u); + size_t sizeThreshold = std::max(getSize() * 4u, static_cast(0x1000u)); - ASSERT(mStaticVertexBuffer); - ASSERT(mStaticVertexBuffer->isCommitted()); - unsigned int staticVertexBufferSize = mStaticVertexBuffer->getBufferSize(); - if (IsUnsignedAdditionSafe(staticVertexBufferSize, mStaticBufferCacheTotalSize)) + // If we're past the threshold, clear the buffer cache. Note that this will release buffers + // that are currenly bound, and in an edge case can even translate the same attribute twice + // in the same draw call. It will not delete currently bound buffers, however, because they + // are ref counted. + if (currentTotalSize > sizeThreshold) { - // 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; - } + emptyStaticBufferCache(); } - // 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; + // At this point, we must create a new static buffer for the attribute data. + StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); + newStaticBuffer->setAttribute(attribute, binding); + mStaticVertexBuffers.push_back(std::unique_ptr(newStaticBuffer)); + return newStaticBuffer; } -void BufferD3D::reinitOutOfDateStaticData() +void BufferD3D::invalidateStaticData(const gl::Context *context) { - 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; - } -} + emptyStaticBufferCache(); -void BufferD3D::invalidateStaticData(D3DBufferInvalidationType invalidationType) -{ - if (invalidationType == D3D_BUFFER_INVALIDATE_WHOLE_CACHE && mStaticBufferCache != nullptr) + if (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0) { - emptyStaticBufferCache(); + SafeDelete(mStaticIndexBuffer); } - if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) + // 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 == D3DBufferUsage::STATIC) { - SafeDelete(mStaticVertexBuffer); - SafeDelete(mStaticIndexBuffer); - - // 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(); - } + initializeStaticData(context); } mUnmodifiedDataUse = 0; } // Creates static buffers if sufficient used data has been left unmodified -void BufferD3D::promoteStaticUsage(int dataSize) +void BufferD3D::promoteStaticUsage(const gl::Context *context, int dataSize) { - if (!mStaticVertexBuffer && !mStaticIndexBuffer) + if (mUsage == D3DBufferUsage::DYNAMIC) { - // 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()) { - initializeStaticData(); + updateD3DBufferUsage(context, gl::BufferUsage::StaticDraw); } } } -gl::Error BufferD3D::getIndexRange(GLenum type, +gl::Error BufferD3D::getIndexRange(const gl::Context *context, + 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; - } + ANGLE_TRY(getData(context, &data)); *outRange = gl::ComputeIndexRange(type, data + offset, count, primitiveRestartEnabled); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h index a27ca9857a..60153748e6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h @@ -15,71 +15,69 @@ #include #include +namespace gl +{ +struct VertexAttribute; +class VertexBinding; +} + namespace rx { class BufferFactoryD3D; class StaticIndexBufferInterface; class StaticVertexBufferInterface; -enum D3DBufferUsage -{ - D3D_BUFFER_USAGE_STATIC, - D3D_BUFFER_USAGE_DYNAMIC, -}; - -enum D3DBufferInvalidationType +enum class D3DBufferUsage { - D3D_BUFFER_INVALIDATE_WHOLE_CACHE, - D3D_BUFFER_INVALIDATE_DEFAULT_BUFFER_ONLY, -}; - -enum D3DStaticBufferCreationType -{ - D3D_BUFFER_CREATE_IF_NECESSARY, - D3D_BUFFER_DO_NOT_CREATE, + STATIC, + DYNAMIC, }; class BufferD3D : public BufferImpl { public: - BufferD3D(BufferFactoryD3D *factory); - virtual ~BufferD3D(); + BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory); + ~BufferD3D() override; unsigned int getSerial() const { return mSerial; } virtual size_t getSize() const = 0; virtual bool supportsDirectBinding() const = 0; - virtual void markTransformFeedbackUsage() = 0; - virtual gl::Error getData(const uint8_t **outData) = 0; + virtual gl::Error markTransformFeedbackUsage(const gl::Context *context) = 0; + virtual gl::Error getData(const gl::Context *context, const uint8_t **outData) = 0; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. StaticVertexBufferInterface *getStaticVertexBuffer(const gl::VertexAttribute &attribute, - D3DStaticBufferCreationType creationType); + const gl::VertexBinding &binding); StaticIndexBufferInterface *getStaticIndexBuffer(); - void initializeStaticData(); - void invalidateStaticData(D3DBufferInvalidationType invalidationType); - void reinitOutOfDateStaticData(); + virtual void initializeStaticData(const gl::Context *context); + virtual void invalidateStaticData(const gl::Context *context); - void promoteStaticUsage(int dataSize); + void promoteStaticUsage(const gl::Context *context, int dataSize); - gl::Error getIndexRange(GLenum type, + gl::Error getIndexRange(const gl::Context *context, + GLenum type, size_t offset, size_t count, bool primitiveRestartEnabled, gl::IndexRange *outRange) override; + BufferFactoryD3D *getFactory() const { return mFactory; } + D3DBufferUsage getUsage() const { return mUsage; } + protected: void updateSerial(); - void updateD3DBufferUsage(GLenum usage); + void updateD3DBufferUsage(const gl::Context *context, gl::BufferUsage usage); void emptyStaticBufferCache(); BufferFactoryD3D *mFactory; unsigned int mSerial; static unsigned int mNextSerial; - StaticVertexBufferInterface *mStaticVertexBuffer; + std::vector> mStaticVertexBuffers; StaticIndexBufferInterface *mStaticIndexBuffer; - std::vector *mStaticBufferCache; unsigned int mStaticBufferCacheTotalSize; unsigned int mStaticVertexBufferOutOfDate; unsigned int mUnmodifiedDataUse; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp index 6f8d1717cd..8ceeec3c39 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp @@ -17,4 +17,14 @@ CompilerD3D::CompilerD3D(ShShaderOutput translatorOutputType) { } +gl::Error CompilerD3D::release() +{ + return gl::NoError(); +} + +ShShaderOutput CompilerD3D::getTranslatorOutputType() const +{ + return mTranslatorOutputType; +} + } // 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 8f4334963d..bcfe810d04 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h @@ -21,8 +21,8 @@ class CompilerD3D : public CompilerImpl CompilerD3D(ShShaderOutput translatorOutputType); ~CompilerD3D() override {} - gl::Error release() override { return gl::Error(GL_NO_ERROR); } - ShShaderOutput getTranslatorOutputType() const override { return mTranslatorOutputType; } + gl::Error release() override; + ShShaderOutput getTranslatorOutputType() const override; private: ShShaderOutput mTranslatorOutputType; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp index f40e6e6cab..5a06b15279 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.cpp @@ -39,11 +39,11 @@ egl::Error DeviceD3D::getDevice(void **outValue) if (!mIsInitialized) { *outValue = nullptr; - return egl::Error(EGL_BAD_DEVICE_EXT); + return egl::EglBadDevice(); } *outValue = mDevice; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error DeviceD3D::initialize(void *device, @@ -53,15 +53,11 @@ egl::Error DeviceD3D::initialize(void *device, ASSERT(!mIsInitialized); if (mIsInitialized) { - return egl::Error(EGL_BAD_DEVICE_EXT); + return egl::EglBadDevice(); } - mDevice = device; - mDeviceType = deviceType; - mDeviceExternallySourced = !!deviceExternallySourced; - #if defined(ANGLE_ENABLE_D3D11) - if (mDeviceType == EGL_D3D11_DEVICE_ANGLE) + if (deviceType == EGL_D3D11_DEVICE_ANGLE) { // Validate the device IUnknown *iunknown = reinterpret_cast(device); @@ -71,7 +67,7 @@ egl::Error DeviceD3D::initialize(void *device, iunknown->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast(&d3dDevice)); if (FAILED(hr)) { - return egl::Error(EGL_BAD_ATTRIBUTE, "Invalid D3D device passed into EGLDeviceEXT"); + return egl::EglBadAttribute() << "Invalid D3D device passed into EGLDeviceEXT"; } // The QI to ID3D11Device adds a ref to the D3D11 device. @@ -81,12 +77,15 @@ egl::Error DeviceD3D::initialize(void *device, else #endif { - ASSERT(!mDeviceExternallySourced); + ASSERT(deviceExternallySourced == EGL_FALSE); } - mIsInitialized = true; + mDevice = device; + mDeviceType = deviceType; + mDeviceExternallySourced = !!deviceExternallySourced; + mIsInitialized = true; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } EGLint DeviceD3D::getType() @@ -99,4 +98,8 @@ void DeviceD3D::generateExtensions(egl::DeviceExtensions *outExtensions) const outExtensions->deviceD3D = true; } +bool DeviceD3D::deviceExternallySourced() +{ + return mDeviceExternallySourced; +} } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h index 1dd9979708..15eaf9210a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DeviceD3D.h @@ -25,7 +25,7 @@ class DeviceD3D : public DeviceImpl egl::Error getDevice(void **outValue) override; EGLint getType() override; void generateExtensions(egl::DeviceExtensions *outExtensions) const override; - bool deviceExternallySourced() override { return mDeviceExternallySourced; } + bool deviceExternallySourced() override; private: void *mDevice; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp index d4dc702582..0edda9c584 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp @@ -8,18 +8,19 @@ #include "libANGLE/renderer/d3d/DisplayD3D.h" -#include "libANGLE/Context.h" +#include + #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Surface.h" +#include "libANGLE/Thread.h" #include "libANGLE/histogram_macros.h" +#include "libANGLE/renderer/d3d/DeviceD3D.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 "libANGLE/renderer/d3d/DeviceD3D.h" - -#include #if defined (ANGLE_ENABLE_D3D9) # include "libANGLE/renderer/d3d/d3d9/Renderer9.h" @@ -29,10 +30,6 @@ # include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #endif // ANGLE_ENABLE_D3D11 -#if defined (ANGLE_TEST_CONFIG) -# define ANGLE_DEFAULT_D3D11 1 -#endif - #if !defined(ANGLE_DEFAULT_D3D11) // Enables use of the Direct3D 11 API for a default display, when available # define ANGLE_DEFAULT_D3D11 1 @@ -60,8 +57,8 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) 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 = static_cast( + 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 || @@ -117,11 +114,10 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) UNIMPLEMENTED(); } - egl::Error result(EGL_NOT_INITIALIZED, "No available renderers."); for (size_t i = 0; i < rendererCreationFunctions.size(); i++) { RendererD3D *renderer = rendererCreationFunctions[i](display); - result = renderer->initialize(); + egl::Error result = renderer->initialize(); # if defined(ANGLE_ENABLE_D3D11) if (renderer->getRendererClass() == RENDERER_D3D11) @@ -146,70 +142,45 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) if (!result.isError()) { *outRenderer = renderer; - break; - } - else - { - // Failed to create the renderer, try the next - SafeDelete(renderer); + return result; } + + // Failed to create the renderer, try the next + SafeDelete(renderer); } - return result; + return egl::EglNotInitialized() << "No available renderers."; } -DisplayD3D::DisplayD3D() : mRenderer(nullptr) +DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) { } - -SurfaceImpl *DisplayD3D::createWindowSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state, 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) - { - width = -1; - height = -1; - } - - return SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize, - directComposition, width, height, orientation); + return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs); } -SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state, const egl::AttributeMap &attribs) { ASSERT(mRenderer != nullptr); - - EGLint width = attribs.get(EGL_WIDTH, 0); - EGLint height = attribs.get(EGL_HEIGHT, 0); - - return SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, nullptr, width, height); + return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs); } -SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration, - EGLClientBuffer shareHandle, +SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, const egl::AttributeMap &attribs) { ASSERT(mRenderer != nullptr); - - EGLint width = attribs.get(EGL_WIDTH, 0); - EGLint height = attribs.get(EGL_HEIGHT, 0); - - return SurfaceD3D::createOffscreen( - mRenderer, mDisplay, configuration, shareHandle, width, height); + return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs); } -SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::Config *configuration, +SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state, NativePixmapType nativePixmap, const egl::AttributeMap &attribs) { @@ -217,11 +188,11 @@ SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::Config *configuration, return nullptr; } -ImageImpl *DisplayD3D::createImage(EGLenum target, - egl::ImageSibling *buffer, +ImageImpl *DisplayD3D::createImage(const egl::ImageState &state, + EGLenum target, const egl::AttributeMap &attribs) { - return new EGLImageD3D(mRenderer, target, buffer, attribs); + return new EGLImageD3D(state, target, attribs, mRenderer); } egl::Error DisplayD3D::getDevice(DeviceImpl **device) @@ -229,30 +200,31 @@ egl::Error DisplayD3D::getDevice(DeviceImpl **device) return mRenderer->getEGLDevice(device); } -gl::Context *DisplayD3D::createContext(const egl::Config *config, - const gl::Context *shareContext, - const egl::AttributeMap &attribs) +ContextImpl *DisplayD3D::createContext(const gl::ContextState &state) { ASSERT(mRenderer != nullptr); - return new gl::Context(config, shareContext, mRenderer, attribs); + return mRenderer->createContext(state); +} + +StreamProducerImpl *DisplayD3D::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) +{ + ASSERT(mRenderer != nullptr); + return mRenderer->createStreamProducerD3DTextureNV12(consumerType, attribs); } egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error DisplayD3D::initialize(egl::Display *display) { ASSERT(mRenderer == nullptr && display != nullptr); mDisplay = display; - egl::Error error = CreateRendererD3D(display, &mRenderer); - if (error.isError()) - { - return error; - } - - return egl::Error(EGL_SUCCESS); + ANGLE_TRY(CreateRendererD3D(display, &mRenderer)); + return egl::NoError(); } void DisplayD3D::terminate() @@ -260,32 +232,26 @@ void DisplayD3D::terminate() SafeDelete(mRenderer); } -egl::ConfigSet DisplayD3D::generateConfigs() const +egl::ConfigSet DisplayD3D::generateConfigs() { ASSERT(mRenderer != nullptr); return mRenderer->generateConfigs(); } -bool DisplayD3D::isDeviceLost() const -{ - ASSERT(mRenderer != nullptr); - return mRenderer->isDeviceLost(); -} - bool DisplayD3D::testDeviceLost() { ASSERT(mRenderer != nullptr); return mRenderer->testDeviceLost(); } -egl::Error DisplayD3D::restoreLostDevice() +egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display) { // Release surface resources to make the Reset() succeed - for (auto &surface : mSurfaceSet) + for (egl::Surface *surface : mState.surfaceSet) { if (surface->getBoundTexture()) { - surface->releaseTexImage(EGL_BACK_BUFFER); + ANGLE_TRY(surface->releaseTexImage(display->getProxyContext(), EGL_BACK_BUFFER)); } SurfaceD3D *surfaceD3D = GetImplAs(surface); surfaceD3D->releaseSwapChain(); @@ -293,27 +259,43 @@ egl::Error DisplayD3D::restoreLostDevice() if (!mRenderer->resetDevice()) { - return egl::Error(EGL_BAD_ALLOC); + return egl::EglBadAlloc(); } // Restore any surfaces that may have been lost - for (const auto &surface : mSurfaceSet) + for (const egl::Surface *surface : mState.surfaceSet) { SurfaceD3D *surfaceD3D = GetImplAs(surface); - egl::Error error = surfaceD3D->resetSwapChain(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(surfaceD3D->resetSwapChain(display)); } - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const { - return NativeWindow::isValidNativeWindow(window); + return mRenderer->isValidNativeWindow(window); +} + +egl::Error DisplayD3D::validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + return mRenderer->validateShareHandle(configuration, static_cast(clientBuffer), + attribs); + + case EGL_D3D_TEXTURE_ANGLE: + return mRenderer->getD3DTextureInfo( + configuration, static_cast(clientBuffer), nullptr, nullptr, nullptr); + + default: + return DisplayImpl::validateClientBuffer(configuration, buftype, clientBuffer, attribs); + } } void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const @@ -337,20 +319,43 @@ void DisplayD3D::generateCaps(egl::Caps *outCaps) const // Display must be initialized to generate caps ASSERT(mRenderer != nullptr); - outCaps->textureNPOT = mRenderer->getRendererExtensions().textureNPOT; + outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOT; } -egl::Error DisplayD3D::waitClient() const +egl::Error DisplayD3D::waitClient(const gl::Context *context) const { - // Unimplemented as it is a noop on D3D - return egl::Error(EGL_SUCCESS); + for (egl::Surface *surface : mState.surfaceSet) + { + SurfaceD3D *surfaceD3D = GetImplAs(surface); + ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(context)); + } + + return egl::NoError(); } -egl::Error DisplayD3D::waitNative(EGLint engine, - egl::Surface *drawSurface, - egl::Surface *readSurface) const +egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine) const { - // Unimplemented as it is a noop on D3D - return egl::Error(EGL_SUCCESS); + egl::Surface *drawSurface = context->getCurrentDrawSurface(); + egl::Surface *readSurface = context->getCurrentReadSurface(); + + if (drawSurface != nullptr) + { + SurfaceD3D *drawSurfaceD3D = GetImplAs(drawSurface); + ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(context)); + } + + if (readSurface != nullptr) + { + SurfaceD3D *readSurfaceD3D = GetImplAs(readSurface); + ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(context)); + } + + return egl::NoError(); } + +gl::Version DisplayD3D::getMaxSupportedESVersion() const +{ + return mRenderer->getMaxSupportedESVersion(); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h index 0ce196dea2..7090522312 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h @@ -19,50 +19,55 @@ class RendererD3D; class DisplayD3D : public DisplayImpl { public: - DisplayD3D(); + DisplayD3D(const egl::DisplayState &state); egl::Error initialize(egl::Display *display) override; - virtual void terminate() override; + void terminate() override; // Surface creation - SurfaceImpl *createWindowSurface(const egl::Config *configuration, + SurfaceImpl *createWindowSurface(const egl::SurfaceState &state, EGLNativeWindowType window, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPbufferSurface(const egl::Config *configuration, + SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPbufferFromClientBuffer(const egl::Config *configuration, - EGLClientBuffer shareHandle, + SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state, + EGLenum buftype, + EGLClientBuffer clientBuffer, const egl::AttributeMap &attribs) override; - SurfaceImpl *createPixmapSurface(const egl::Config *configuration, + SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state, NativePixmapType nativePixmap, const egl::AttributeMap &attribs) override; - ImageImpl *createImage(EGLenum target, - egl::ImageSibling *buffer, + ImageImpl *createImage(const egl::ImageState &state, + EGLenum target, const egl::AttributeMap &attribs) override; - gl::Context *createContext(const egl::Config *config, - const gl::Context *shareContext, - const egl::AttributeMap &attribs) override; + ContextImpl *createContext(const gl::ContextState &state) override; + + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; - bool isDeviceLost() const override; bool testDeviceLost() override; - egl::Error restoreLostDevice() override; + egl::Error restoreLostDevice(const egl::Display *display) override; bool isValidNativeWindow(EGLNativeWindowType window) const override; + egl::Error validateClientBuffer(const egl::Config *configuration, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) 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; + egl::Error waitClient(const gl::Context *context) const override; + egl::Error waitNative(const gl::Context *context, EGLint engine) const override; + gl::Version getMaxSupportedESVersion() const override; private: void generateExtensions(egl::DisplayExtensions *outExtensions) 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 42a534f573..b4143a3f5f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp @@ -8,15 +8,17 @@ #include "libANGLE/renderer/d3d/DynamicHLSL.h" +#include "common/string_utils.h" #include "common/utilities.h" #include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" #include "libANGLE/Shader.h" +#include "libANGLE/VaryingPacking.h" #include "libANGLE/formatutils.h" #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; @@ -26,7 +28,28 @@ namespace rx namespace { -std::string HLSLComponentTypeString(GLenum componentType) +// This class needs to match OutputHLSL::decorate +class DecorateVariable final : angle::NonCopyable +{ + public: + explicit DecorateVariable(const std::string &str) : mName(str) {} + const std::string &getName() const { return mName; } + + private: + const std::string &mName; +}; + +std::ostream &operator<<(std::ostream &o, const DecorateVariable &dv) +{ + if (dv.getName().compare(0, 3, "gl_") != 0) + { + o << "_"; + } + o << dv.getName(); + return o; +} + +const char *HLSLComponentTypeString(GLenum componentType) { switch (componentType) { @@ -44,12 +67,16 @@ std::string HLSLComponentTypeString(GLenum componentType) } } -std::string HLSLComponentTypeString(GLenum componentType, int componentCount) +void HLSLComponentTypeString(std::ostringstream &ostream, GLenum componentType, int componentCount) { - return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); + ostream << HLSLComponentTypeString(componentType); + if (componentCount > 1) + { + ostream << componentCount; + } } -std::string HLSLMatrixTypeString(GLenum type) +const char *HLSLMatrixTypeString(GLenum type) { switch (type) { @@ -77,15 +104,16 @@ std::string HLSLMatrixTypeString(GLenum type) } } -std::string HLSLTypeString(GLenum type) +void HLSLTypeString(std::ostringstream &ostream, GLenum type) { if (gl::IsMatrixType(type)) { - return HLSLMatrixTypeString(type); + ostream << HLSLMatrixTypeString(type); + return; } - return HLSLComponentTypeString(gl::VariableComponentType(type), - gl::VariableComponentCount(type)); + HLSLComponentTypeString(ostream, gl::VariableComponentType(type), + gl::VariableComponentCount(type)); } const PixelShaderOutputVariable *FindOutputAtLocation( @@ -103,7 +131,7 @@ const PixelShaderOutputVariable *FindOutputAtLocation( return nullptr; } -void WriteArrayString(std::stringstream &strstr, unsigned int i) +void WriteArrayString(std::ostringstream &strstr, unsigned int i) { static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int."); @@ -117,16 +145,14 @@ void WriteArrayString(std::stringstream &strstr, unsigned int i) strstr << "]"; } -const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; -const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; +constexpr const char *VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; +constexpr const char *PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; } // anonymous namespace -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"); -} +// BuiltinInfo implementation + +BuiltinInfo::BuiltinInfo() = default; +BuiltinInfo::~BuiltinInfo() = default; // DynamicHLSL implementation @@ -134,55 +160,13 @@ DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer) { } -void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking, - std::stringstream &hlslStream) const -{ - std::string varyingSemantic = - GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize()); - - for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) - { - const auto &varying = *registerInfo.packedVarying->varying; - ASSERT(!varying.isStruct()); - - // 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 (registerInfo.packedVarying->interpolation) - { - case sh::INTERPOLATION_SMOOTH: - hlslStream << " "; - break; - case sh::INTERPOLATION_FLAT: - hlslStream << " nointerpolation "; - break; - case sh::INTERPOLATION_CENTROID: - hlslStream << " centroid "; - break; - default: - UNREACHABLE(); - } - - 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"; - } -} - std::string DynamicHLSL::generateVertexShaderForInputLayout( const std::string &sourceShader, const InputLayout &inputLayout, const std::vector &shaderAttributes) const { - std::stringstream structStream; - std::stringstream initStream; + std::ostringstream structStream; + std::ostringstream initStream; structStream << "struct VS_INPUT\n" << "{\n"; @@ -231,26 +215,31 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( { GLenum componentType = mRenderer->getVertexComponentType(vertexFormatType); - if (shaderAttribute.name == "gl_InstanceID") + if (shaderAttribute.name == "gl_InstanceID" || + shaderAttribute.name == "gl_VertexID") { - // The input type of the instance ID in HLSL (uint) differs from the one in ESSL - // (int). + // The input types of the instance ID and vertex ID in HLSL (uint) differs from + // the ones in ESSL (int). structStream << " uint"; } else { - structStream << " " << HLSLComponentTypeString( - componentType, - VariableComponentCount(shaderAttribute.type)); + structStream << " "; + HLSLComponentTypeString(structStream, componentType, + VariableComponentCount(shaderAttribute.type)); } } - structStream << " " << decorateVariable(shaderAttribute.name) << " : "; + structStream << " " << DecorateVariable(shaderAttribute.name) << " : "; if (shaderAttribute.name == "gl_InstanceID") { structStream << "SV_InstanceID"; } + else if (shaderAttribute.name == "gl_VertexID") + { + structStream << "SV_VertexID"; + } else { structStream << "TEXCOORD" << semanticIndex; @@ -260,7 +249,7 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( structStream << ";\n"; // HLSL code for initialization - initStream << " " << 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) @@ -268,11 +257,11 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( if (IsMatrixType(shaderAttribute.type) || (mRenderer->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_GPU) != 0) { - initStream << generateAttributeConversionHLSL(vertexFormatType, shaderAttribute); + GenerateAttributeConversionHLSL(vertexFormatType, shaderAttribute, initStream); } else { - initStream << "input." << decorateVariable(shaderAttribute.name); + initStream << "input." << DecorateVariable(shaderAttribute.name); } initStream << ";\n"; @@ -289,8 +278,9 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( std::string vertexHLSL(sourceShader); - size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); - vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), structStream.str()); + bool success = + angle::ReplaceSubstring(&vertexHLSL, VERTEX_ATTRIBUTE_STUB_STRING, structStream.str()); + ASSERT(success); return vertexHLSL; } @@ -305,22 +295,32 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; - std::stringstream declarationStream; - std::stringstream copyStream; + std::ostringstream declarationStream; + std::ostringstream copyStream; declarationStream << "struct PS_OUTPUT\n" "{\n"; - for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex) + size_t numOutputs = outputLayout.size(); + + // Workaround for HLSL 3.x: We can't do a depth/stencil only render, the runtime will complain. + if (numOutputs == 0 && (shaderModel == 3 || !mRenderer->getShaderModelSuffix().empty())) + { + numOutputs = 1u; + } + const PixelShaderOutputVariable defaultOutput(GL_FLOAT_VEC4, "dummy", "float4(0, 0, 0, 1)", 0); + + for (size_t layoutIndex = 0; layoutIndex < numOutputs; ++layoutIndex) { - GLenum binding = outputLayout[layoutIndex]; + GLenum binding = outputLayout.empty() ? GL_COLOR_ATTACHMENT0 : outputLayout[layoutIndex]; if (binding != GL_NONE) { unsigned int location = (binding - GL_COLOR_ATTACHMENT0); const PixelShaderOutputVariable *outputVariable = - FindOutputAtLocation(outputVariables, location); + outputLayout.empty() ? &defaultOutput + : FindOutputAtLocation(outputVariables, location); // OpenGL ES 3.0 spec $4.2.1 // If [...] not all user-defined output variables are written, the values of fragment @@ -328,8 +328,9 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( // corresponding to unwritten variables are similarly undefined. if (outputVariable) { - declarationStream << " " + HLSLTypeString(outputVariable->type) << " " - << outputVariable->name << " : " << targetSemantic + declarationStream << " "; + HLSLTypeString(declarationStream, outputVariable->type); + declarationStream << " " << outputVariable->name << " : " << targetSemantic << static_cast(layoutIndex) << ";\n"; copyStream << " output." << outputVariable->name << " = " @@ -354,61 +355,113 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( std::string pixelHLSL(sourceShader); - size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); - pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), - declarationStream.str()); + bool success = + angle::ReplaceSubstring(&pixelHLSL, PIXEL_OUTPUT_STUB_STRING, declarationStream.str()); + ASSERT(success); return pixelHLSL; } -void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType, - const VaryingPacking &varyingPacking, - std::stringstream &linkStream) const +void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking, + const BuiltinInfo &builtins, + bool programUsesPointSize, + std::ostringstream &hlslStream) const { - const auto &builtins = varyingPacking.builtins(shaderType); ASSERT(builtins.dxPosition.enabled); - linkStream << "{\n" + hlslStream << "{\n" << " float4 dx_Position : " << builtins.dxPosition.str() << ";\n"; if (builtins.glPosition.enabled) { - linkStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n"; + hlslStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n"; } if (builtins.glFragCoord.enabled) { - linkStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n"; + hlslStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n"; } if (builtins.glPointCoord.enabled) { - linkStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n"; + hlslStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n"; } if (builtins.glPointSize.enabled) { - linkStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n"; + hlslStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n"; + } + + if (builtins.glViewIDOVR.enabled) + { + hlslStream << " nointerpolation uint gl_ViewID_OVR : " << builtins.glViewIDOVR.str() + << ";\n"; + } + + if (builtins.glViewportIndex.enabled) + { + hlslStream << " nointerpolation uint gl_ViewportIndex : " + << builtins.glViewportIndex.str() << ";\n"; + } + + if (builtins.glLayer.enabled) + { + hlslStream << " nointerpolation uint gl_Layer : " << builtins.glLayer.str() << ";\n"; } - // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the - // same register. - generateVaryingHLSL(varyingPacking, linkStream); + std::string varyingSemantic = + GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize); - linkStream << "};\n"; + for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) + { + const auto &varying = *registerInfo.packedVarying->varying; + ASSERT(!varying.isStruct()); + + // 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 (registerInfo.packedVarying->interpolation) + { + case sh::INTERPOLATION_SMOOTH: + hlslStream << " "; + break; + case sh::INTERPOLATION_FLAT: + hlslStream << " nointerpolation "; + break; + case sh::INTERPOLATION_CENTROID: + hlslStream << " centroid "; + break; + default: + UNREACHABLE(); + } + + GLenum transposedType = gl::TransposeMatrixType(varying.type); + GLenum componentType = gl::VariableComponentType(transposedType); + int columnCount = gl::VariableColumnCount(transposedType); + HLSLComponentTypeString(hlslStream, componentType, columnCount); + unsigned int semanticIndex = registerInfo.semanticIndex; + hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n"; + } + + hlslStream << "};\n"; } -bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, - const gl::Program::Data &programData, +void DynamicHLSL::generateShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData, const ProgramD3DMetadata &programMetadata, const VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, std::string *pixelHLSL, std::string *vertexHLSL) const { ASSERT(pixelHLSL->empty() && vertexHLSL->empty()); - const gl::Shader *vertexShaderGL = programData.getAttachedVertexShader(); - const ShaderD3D *vertexShader = GetImplAs(vertexShaderGL); - const gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader(); + const auto &data = context->getContextState(); + gl::Shader *vertexShaderGL = programData.getAttachedVertexShader(); + gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader(); const ShaderD3D *fragmentShader = GetImplAs(fragmentShaderGL); const int shaderModel = mRenderer->getMajorShaderModel(); @@ -422,48 +475,59 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, // Validation done in the compiler ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData()); - std::stringstream vertexStream; - vertexStream << vertexShaderGL->getTranslatedSource(); + std::ostringstream vertexStream; + vertexStream << vertexShaderGL->getTranslatedSource(context); // Instanced PointSprite emulation requires additional entries originally generated in the // GeometryShader HLSL. These include pointsize clamp values. if (useInstancedPointSpriteEmulation) { vertexStream << "static float minPointSize = " - << static_cast(data.caps->minAliasedPointSize) << ".0f;\n" + << static_cast(data.getCaps().minAliasedPointSize) << ".0f;\n" << "static float maxPointSize = " - << static_cast(data.caps->maxAliasedPointSize) << ".0f;\n"; + << static_cast(data.getCaps().maxAliasedPointSize) << ".0f;\n"; } // Add stub string to be replaced when shader is dynamically defined by its layout - vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n"; + vertexStream << "\n" << std::string(VERTEX_ATTRIBUTE_STUB_STRING) << "\n"; + + const auto &vertexBuiltins = builtinsD3D[gl::SHADER_VERTEX]; // Write the HLSL input/output declarations vertexStream << "struct VS_OUTPUT\n"; - generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream); + generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(), + vertexStream); vertexStream << "\n" << "VS_OUTPUT main(VS_INPUT input)\n" << "{\n" << " initAttributes(input);\n"; - if (vertexShader->usesDeferredInit()) - { - vertexStream << "\n" - << " initializeDeferredGlobals();\n"; - } - vertexStream << "\n" << " gl_main();\n" << "\n" << " VS_OUTPUT output;\n"; - const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX); - if (vertexBuiltins.glPosition.enabled) { vertexStream << " output.gl_Position = gl_Position;\n"; } + if (vertexBuiltins.glViewIDOVR.enabled) + { + vertexStream << " output.gl_ViewID_OVR = _ViewID_OVR;\n"; + } + if (programMetadata.hasANGLEMultiviewEnabled() && programMetadata.canSelectViewInVertexShader()) + { + ASSERT(vertexBuiltins.glViewportIndex.enabled && vertexBuiltins.glLayer.enabled); + vertexStream << " if (multiviewSelectViewportIndex)\n" + << " {\n" + << " output.gl_ViewportIndex = _ViewID_OVR;\n" + << " } else {\n" + << " output.gl_ViewportIndex = 0;\n" + << " output.gl_Layer = _ViewID_OVR;\n" + << " }\n"; + } + // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") { @@ -528,10 +592,10 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, if (packedVarying.isStructField()) { - vertexStream << decorateVariable(packedVarying.parentStructName) << "."; + vertexStream << DecorateVariable(packedVarying.parentStructName) << "."; } - vertexStream << decorateVariable(varying.name); + vertexStream << DecorateVariable(varying.name); if (varying.isArray()) { @@ -593,13 +657,16 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, << " return output;\n" << "}\n"; - std::stringstream pixelStream; - pixelStream << fragmentShaderGL->getTranslatedSource(); + const auto &pixelBuiltins = builtinsD3D[gl::SHADER_FRAGMENT]; + + std::ostringstream pixelStream; + pixelStream << fragmentShaderGL->getTranslatedSource(context); pixelStream << "struct PS_INPUT\n"; - generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream); + generateVaryingLinkHLSL(varyingPacking, pixelBuiltins, builtinsD3D.usesPointSize(), + pixelStream); pixelStream << "\n"; - pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n"; + pixelStream << std::string(PIXEL_OUTPUT_STUB_STRING) << "\n"; if (fragmentShader->usesFrontFacing()) { @@ -620,7 +687,11 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, << "{\n"; } - const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL); + if (fragmentShader->usesViewID()) + { + ASSERT(pixelBuiltins.glViewIDOVR.enabled); + pixelStream << " _ViewID_OVR = input.gl_ViewID_OVR;\n"; + } if (pixelBuiltins.glFragCoord.enabled) { @@ -721,18 +792,19 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, 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) + // Don't reference VS-only transform feedback varyings in the PS. Note that we're relying on + // that the staticUse flag is set according to usage in the fragment shader. + if (packedVarying.vertexOnly || !varying.staticUse) continue; pixelStream << " "; if (packedVarying.isStructField()) { - pixelStream << decorateVariable(packedVarying.parentStructName) << "."; + pixelStream << DecorateVariable(packedVarying.parentStructName) << "."; } - pixelStream << decorateVariable(varying.name); + pixelStream << DecorateVariable(varying.name); if (varying.isArray()) { @@ -766,12 +838,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, pixelStream << ";\n"; } - if (fragmentShader->usesDeferredInit()) - { - pixelStream << "\n" - << " initializeDeferredGlobals();\n"; - } - pixelStream << "\n" << " gl_main();\n" << "\n" @@ -780,34 +846,126 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, *vertexHLSL = vertexStream.str(); *pixelHLSL = pixelStream.str(); +} + +std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData) const +{ + gl::Shader *computeShaderGL = programData.getAttachedComputeShader(); + std::stringstream computeStream; + std::string translatedSource = computeShaderGL->getTranslatedSource(context); + computeStream << translatedSource; + + bool usesWorkGroupID = translatedSource.find("GL_USES_WORK_GROUP_ID") != std::string::npos; + bool usesLocalInvocationID = + translatedSource.find("GL_USES_LOCAL_INVOCATION_ID") != std::string::npos; + bool usesGlobalInvocationID = + translatedSource.find("GL_USES_GLOBAL_INVOCATION_ID") != std::string::npos; + bool usesLocalInvocationIndex = + translatedSource.find("GL_USES_LOCAL_INVOCATION_INDEX") != std::string::npos; + + computeStream << "\nstruct CS_INPUT\n{\n"; + if (usesWorkGroupID) + { + computeStream << " uint3 dx_WorkGroupID : " + << "SV_GroupID;\n"; + } - return true; + if (usesLocalInvocationID) + { + computeStream << " uint3 dx_LocalInvocationID : " + << "SV_GroupThreadID;\n"; + } + + if (usesGlobalInvocationID) + { + computeStream << " uint3 dx_GlobalInvocationID : " + << "SV_DispatchThreadID;\n"; + } + + if (usesLocalInvocationIndex) + { + computeStream << " uint dx_LocalInvocationIndex : " + << "SV_GroupIndex;\n"; + } + + computeStream << "};\n\n"; + + const sh::WorkGroupSize &localSize = computeShaderGL->getWorkGroupSize(context); + computeStream << "[numthreads(" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] + << ")]\n"; + + computeStream << "void main(CS_INPUT input)\n" + << "{\n"; + + if (usesWorkGroupID) + { + computeStream << " gl_WorkGroupID = input.dx_WorkGroupID;\n"; + } + if (usesLocalInvocationID) + { + computeStream << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n"; + } + if (usesGlobalInvocationID) + { + computeStream << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n"; + } + if (usesLocalInvocationIndex) + { + computeStream << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n"; + } + + computeStream << "\n" + << " gl_main();\n" + << "}\n"; + + return computeStream.str(); } -std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const +std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS) const { ASSERT(mRenderer->getMajorShaderModel() >= 4); - std::stringstream preambleStream; + std::ostringstream preambleStream; - const auto &builtins = varyingPacking.builtins(SHADER_VERTEX); + const auto &vertexBuiltins = builtinsD3D[gl::SHADER_VERTEX]; preambleStream << "struct GS_INPUT\n"; - generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream); + generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(), + preambleStream); preambleStream << "\n" << "struct GS_OUTPUT\n"; - generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream); + generateVaryingLinkHLSL(varyingPacking, builtinsD3D[gl::SHADER_GEOMETRY], + builtinsD3D.usesPointSize(), 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) + if (vertexBuiltins.glPointSize.enabled) { preambleStream << " output.gl_PointSize = input.gl_PointSize;\n"; } + if (hasANGLEMultiviewEnabled) + { + preambleStream << " output.gl_ViewID_OVR = input.gl_ViewID_OVR;\n"; + if (selectViewInVS) + { + ASSERT(builtinsD3D[gl::SHADER_GEOMETRY].glViewportIndex.enabled && + builtinsD3D[gl::SHADER_GEOMETRY].glLayer.enabled); + + // If the view is already selected in the VS, then we just pass the gl_ViewportIndex and + // gl_Layer to the output. + preambleStream << " output.gl_ViewportIndex = input.gl_ViewportIndex;\n" + << " output.gl_Layer = input.gl_Layer;\n"; + } + } + for (const PackedVaryingRegister &varyingRegister : varyingPacking.getRegisterList()) { preambleStream << " output.v" << varyingRegister.semanticIndex << " = "; @@ -818,7 +976,7 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n"; } - if (builtins.glFragCoord.enabled) + if (vertexBuiltins.glFragCoord.enabled) { preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n"; } @@ -829,20 +987,46 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va << "#endif // ANGLE_POINT_SPRITE_SHADER\n" << "}\n"; + if (hasANGLEMultiviewEnabled && !selectViewInVS) + { + ASSERT(builtinsD3D[gl::SHADER_GEOMETRY].glViewportIndex.enabled && + builtinsD3D[gl::SHADER_GEOMETRY].glLayer.enabled); + + // According to the HLSL reference, using SV_RenderTargetArrayIndex is only valid if the + // render target is an array resource. Because of this we do not write to gl_Layer if we are + // taking the side-by-side code path. We still select the viewport index in the layered code + // path as that is always valid. See: + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx + preambleStream << "\n" + << "void selectView(inout GS_OUTPUT output, GS_INPUT input)\n" + << "{\n" + << " if (multiviewSelectViewportIndex)\n" + << " {\n" + << " output.gl_ViewportIndex = input.gl_ViewID_OVR;\n" + << " } else {\n" + << " output.gl_ViewportIndex = 0;\n" + << " output.gl_Layer = input.gl_ViewID_OVR;\n" + << " }\n" + << "}\n"; + } + return preambleStream.str(); } -std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveType, - const gl::Data &data, - const gl::Program::Data &programData, +std::string DynamicHLSL::generateGeometryShaderHLSL(const gl::Context *context, + gl::PrimitiveType primitiveType, + const gl::ProgramState &programData, const bool useViewScale, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS, + const bool pointSpriteEmulation, const std::string &preambleString) const { ASSERT(mRenderer->getMajorShaderModel() >= 4); std::stringstream shaderStream; - const bool pointSprites = (primitiveType == PRIMITIVE_POINTS); + const bool pointSprites = (primitiveType == PRIMITIVE_POINTS) && pointSpriteEmulation; const bool usesPointCoord = preambleString.find("gl_PointCoord") != std::string::npos; const char *inputPT = nullptr; @@ -854,9 +1038,19 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT { case PRIMITIVE_POINTS: inputPT = "point"; - outputPT = "Triangle"; inputSize = 1; - maxVertexOutput = 4; + + if (pointSprites) + { + outputPT = "Triangle"; + maxVertexOutput = 4; + } + else + { + outputPT = "Point"; + maxVertexOutput = 1; + } + break; case PRIMITIVE_LINES: @@ -882,18 +1076,34 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT break; } - if (pointSprites) + if (pointSprites || hasANGLEMultiviewEnabled) { - shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n" - "\n" - "uniform float4 dx_ViewCoords : register(c1);\n"; + shaderStream << "cbuffer DriverConstants : register(b0)\n" + "{\n"; + + if (pointSprites) + { + shaderStream << " float4 dx_ViewCoords : packoffset(c1);\n"; + if (useViewScale) + { + shaderStream << " float2 dx_ViewScale : packoffset(c3);\n"; + } + } - if (useViewScale) + if (hasANGLEMultiviewEnabled) { - shaderStream << "uniform float2 dx_ViewScale : register(c3);\n"; + // We have to add a value which we can use to keep track of which multi-view code path + // is to be selected in the GS. + shaderStream << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; } - shaderStream << "\n" + shaderStream << "};\n\n"; + } + + if (pointSprites) + { + shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n" + "\n" "static float2 pointSpriteCorners[] = \n" "{\n" " float2( 0.5f, -0.5f),\n" @@ -911,10 +1121,10 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT "};\n" "\n" "static float minPointSize = " - << static_cast(data.caps->minAliasedPointSize) + << static_cast(context->getCaps().minAliasedPointSize) << ".0f;\n" "static float maxPointSize = " - << static_cast(data.caps->maxAliasedPointSize) << ".0f;\n" + << static_cast(context->getCaps().maxAliasedPointSize) << ".0f;\n" << "\n"; } @@ -944,7 +1154,10 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT { shaderStream << " copyVertex(output, input[" << vertexIndex << "], input[lastVertexIndex]);\n"; - + if (hasANGLEMultiviewEnabled && !selectViewInVS) + { + shaderStream << " selectView(output, input[" << vertexIndex << "]);\n"; + } if (!pointSprites) { ASSERT(inputSize == maxVertexOutput); @@ -995,50 +1208,38 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT return shaderStream.str(); } -// This method needs to match OutputHLSL::decorate -std::string DynamicHLSL::decorateVariable(const std::string &name) -{ - if (name.compare(0, 3, "gl_") != 0) - { - return "_" + name; - } - - return name; -} - -std::string DynamicHLSL::generateAttributeConversionHLSL( - gl::VertexFormatType vertexFormatType, - const sh::ShaderVariable &shaderAttrib) const +// static +void DynamicHLSL::GenerateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, + const sh::ShaderVariable &shaderAttrib, + std::ostringstream &outStream) { - const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType); - std::string attribString = "input." + decorateVariable(shaderAttrib.name); - // Matrix if (IsMatrixType(shaderAttrib.type)) { - return "transpose(" + attribString + ")"; + outStream << "transpose(input." << DecorateVariable(shaderAttrib.name) << ")"; + return; } GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); int shaderComponentCount = VariableComponentCount(shaderAttrib.type); + const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType); // Perform integer to float conversion (if necessary) - bool requiresTypeConversion = - (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT); - - if (requiresTypeConversion) + if (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT) { // TODO: normalization for 32-bit integer formats ASSERT(!vertexFormat.normalized && !vertexFormat.pureInteger); - return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; + outStream << "float" << shaderComponentCount << "(input." + << DecorateVariable(shaderAttrib.name) << ")"; + return; } // No conversion necessary - return attribString; + outStream << "input." << DecorateVariable(shaderAttrib.name); } -void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, - const gl::Program::Data &programData, +void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, + const gl::ProgramState &programData, const ProgramD3DMetadata &metadata, std::vector *outPixelShaderKey) { @@ -1047,7 +1248,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, // - 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); + (broadcast || metadata.usesMultipleFragmentOuts() ? data.getCaps().maxDrawBuffers : 1); if (metadata.getMajorShaderVersion() < 300) { @@ -1069,25 +1270,158 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data, const auto &shaderOutputVars = metadata.getFragmentShader()->getData().getActiveOutputVariables(); - for (auto outputPair : programData.getOutputVariables()) + for (size_t outputLocationIndex = 0u; + outputLocationIndex < programData.getOutputLocations().size(); ++outputLocationIndex) { - const VariableLocation &outputLocation = outputPair.second; + const VariableLocation &outputLocation = + programData.getOutputLocations().at(outputLocationIndex); + if (!outputLocation.used()) + { + continue; + } const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; - const std::string &variableName = "out_" + outputLocation.name; + const std::string &variableName = "out_" + outputVariable.name; + + // Fragment outputs can't be arrays of arrays. ESSL 3.10 section 4.3.6. const std::string &elementString = - (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); + (outputVariable.isArray() ? Str(outputLocation.arrayIndex) : ""); ASSERT(outputVariable.staticUse); PixelShaderOutputVariable outputKeyVariable; outputKeyVariable.type = outputVariable.type; outputKeyVariable.name = variableName + elementString; - outputKeyVariable.source = variableName + ArrayString(outputLocation.element); - outputKeyVariable.outputIndex = outputPair.first; + outputKeyVariable.source = + variableName + + (outputVariable.isArray() ? ArrayString(outputLocation.arrayIndex) : ""); + outputKeyVariable.outputIndex = outputLocationIndex; outPixelShaderKey->push_back(outputKeyVariable); } } } +// BuiltinVarying Implementation. +BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false) +{ +} + +std::string BuiltinVarying::str() const +{ + return (systemValue ? semantic : (semantic + Str(index))); +} + +void BuiltinVarying::enableSystem(const std::string &systemValueSemantic) +{ + enabled = true; + semantic = systemValueSemantic; + systemValue = true; +} + +void BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal) +{ + enabled = true; + semantic = semanticVal; + index = indexVal; +} + +// BuiltinVaryingsD3D Implementation. +BuiltinVaryingsD3D::BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata, + const VaryingPacking &packing) +{ + updateBuiltins(gl::SHADER_VERTEX, metadata, packing); + updateBuiltins(gl::SHADER_FRAGMENT, metadata, packing); + if (metadata.getRendererMajorShaderModel() >= 4) + { + updateBuiltins(gl::SHADER_GEOMETRY, metadata, packing); + } +} + +BuiltinVaryingsD3D::~BuiltinVaryingsD3D() = default; + +void BuiltinVaryingsD3D::updateBuiltins(gl::ShaderType shaderType, + const ProgramD3DMetadata &metadata, + const VaryingPacking &packing) +{ + const std::string &userSemantic = GetVaryingSemantic(metadata.getRendererMajorShaderModel(), + metadata.usesSystemValuePointSize()); + + unsigned int reservedSemanticIndex = packing.getMaxSemanticIndex(); + + BuiltinInfo *builtins = &mBuiltinInfo[shaderType]; + + if (metadata.getRendererMajorShaderModel() >= 4) + { + builtins->dxPosition.enableSystem("SV_Position"); + } + else if (shaderType == gl::SHADER_FRAGMENT) + { + builtins->dxPosition.enableSystem("VPOS"); + } + else + { + builtins->dxPosition.enableSystem("POSITION"); + } + + if (metadata.usesTransformFeedbackGLPosition()) + { + builtins->glPosition.enable(userSemantic, reservedSemanticIndex++); + } + + if (metadata.usesFragCoord()) + { + builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++); + } + + if (shaderType == gl::SHADER_VERTEX ? metadata.addsPointCoordToVertexShader() + : metadata.usesPointCoord()) + { + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + if (metadata.getRendererMajorShaderModel() >= 4) + { + builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++); + } + else + { + builtins->glPointCoord.enable("TEXCOORD", 0); + } + } + + if (shaderType == gl::SHADER_VERTEX && metadata.hasANGLEMultiviewEnabled()) + { + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + if (metadata.canSelectViewInVertexShader()) + { + builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex"); + builtins->glLayer.enableSystem("SV_RenderTargetArrayIndex"); + } + } + + if (shaderType == gl::SHADER_FRAGMENT && metadata.hasANGLEMultiviewEnabled()) + { + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + } + + if (shaderType == gl::SHADER_GEOMETRY && metadata.hasANGLEMultiviewEnabled()) + { + // Although it is possible to retrieve gl_ViewID_OVR from the value of + // SV_ViewportArrayIndex or SV_RenderTargetArrayIndex based on the multi-view state in the + // driver constant buffer, it is easier and cleaner to pass it as a varying. + builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++); + + // gl_Layer and gl_ViewportIndex are necessary so that we can write to either based on the + // multiview state in the driver constant buffer. + builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex"); + builtins->glLayer.enableSystem("SV_RenderTargetArrayIndex"); + } + + // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders + if (metadata.usesSystemValuePointSize() && + (shaderType != gl::SHADER_FRAGMENT || metadata.getRendererMajorShaderModel() >= 4)) + { + builtins->glPointSize.enableSystem("PSIZE"); + } +} + } // 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 69d941c06a..fe8d9cb0a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h @@ -16,6 +16,7 @@ #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Program.h" +#include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/RendererD3D.h" @@ -29,23 +30,88 @@ namespace gl { class InfoLog; struct VariableLocation; +class VaryingPacking; struct VertexAttribute; -struct Data; } namespace rx { -struct PackedVarying; class ProgramD3DMetadata; class ShaderD3D; -class VaryingPacking; struct PixelShaderOutputVariable { - GLenum type; + PixelShaderOutputVariable() {} + PixelShaderOutputVariable(GLenum typeIn, + const std::string &nameIn, + const std::string &sourceIn, + size_t outputIndexIn) + : type(typeIn), name(nameIn), source(sourceIn), outputIndex(outputIndexIn) + { + } + + GLenum type = GL_NONE; std::string name; std::string source; - size_t outputIndex; + size_t outputIndex = 0; +}; + +struct BuiltinVarying final : private 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 +{ + BuiltinInfo(); + ~BuiltinInfo(); + + BuiltinVarying dxPosition; + BuiltinVarying glPosition; + BuiltinVarying glFragCoord; + BuiltinVarying glPointCoord; + BuiltinVarying glPointSize; + BuiltinVarying glViewIDOVR; + BuiltinVarying glViewportIndex; + BuiltinVarying glLayer; +}; + +inline 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"); +} + +class BuiltinVaryingsD3D +{ + public: + BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata, const gl::VaryingPacking &packing); + ~BuiltinVaryingsD3D(); + + bool usesPointSize() const { return mBuiltinInfo[gl::SHADER_VERTEX].glPointSize.enabled; } + + const BuiltinInfo &operator[](gl::ShaderType shaderType) const + { + return mBuiltinInfo[shaderType]; + } + BuiltinInfo &operator[](gl::ShaderType shaderType) { return mBuiltinInfo[shaderType]; } + + private: + void updateBuiltins(gl::ShaderType shaderType, + const ProgramD3DMetadata &metadata, + const gl::VaryingPacking &packing); + + std::array mBuiltinInfo; }; class DynamicHLSL : angle::NonCopyable @@ -62,43 +128,48 @@ class DynamicHLSL : angle::NonCopyable const std::vector &outputVariables, bool usesFragDepth, const std::vector &outputLayout) const; - bool generateShaderLinkHLSL(const gl::Data &data, - const gl::Program::Data &programData, + void generateShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData, const ProgramD3DMetadata &programMetadata, - const VaryingPacking &varyingPacking, + const gl::VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, std::string *pixelHLSL, std::string *vertexHLSL) const; + std::string generateComputeShaderLinkHLSL(const gl::Context *context, + const gl::ProgramState &programData) const; - std::string generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const; + std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking, + const BuiltinVaryingsD3D &builtinsD3D, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS) const; - std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType, - const gl::Data &data, - const gl::Program::Data &programData, + std::string generateGeometryShaderHLSL(const gl::Context *context, + gl::PrimitiveType primitiveType, + const gl::ProgramState &programData, const bool useViewScale, + const bool hasANGLEMultiviewEnabled, + const bool selectViewInVS, + const bool pointSpriteEmulation, const std::string &preambleString) const; - void getPixelShaderOutputKey(const gl::Data &data, - const gl::Program::Data &programData, + void getPixelShaderOutputKey(const gl::ContextState &data, + const gl::ProgramState &programData, const ProgramD3DMetadata &metadata, std::vector *outPixelShaderKey); private: RendererD3D *const mRenderer; - 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); + void generateVaryingLinkHLSL(const gl::VaryingPacking &varyingPacking, + const BuiltinInfo &builtins, + bool programUsesPointSize, + std::ostringstream &hlslStream) const; - std::string generateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, - const sh::ShaderVariable &shaderAttrib) const; + static void GenerateAttributeConversionHLSL(gl::VertexFormatType vertexFormatType, + const sh::ShaderVariable &shaderAttrib, + std::ostringstream &outStream); }; -std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize); -} +} // namespace rx #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 index ca4b16987f..fcc2456bd6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.cpp @@ -22,46 +22,14 @@ 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, +EGLImageD3D::EGLImageD3D(const egl::ImageState &state, EGLenum target, - egl::ImageSibling *buffer, - const egl::AttributeMap &attribs) - : mRenderer(renderer), mBuffer(buffer), mAttachmentBuffer(nullptr), mRenderTarget(nullptr) + const egl::AttributeMap &attribs, + RendererD3D *renderer) + : ImageImpl(state), mRenderer(renderer), 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() @@ -71,62 +39,49 @@ EGLImageD3D::~EGLImageD3D() egl::Error EGLImageD3D::initialize() { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -gl::Error EGLImageD3D::orphan(egl::ImageSibling *sibling) +gl::Error EGLImageD3D::orphan(const gl::Context *context, egl::ImageSibling *sibling) { - if (sibling == mBuffer) + if (sibling == mState.source.get()) { - gl::Error error = copyToLocalRendertarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(copyToLocalRendertarget(context)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error EGLImageD3D::getRenderTarget(RenderTargetD3D **outRT) const +gl::Error EGLImageD3D::getRenderTarget(const gl::Context *context, RenderTargetD3D **outRT) const { - if (mAttachmentBuffer) + if (mState.source.get()) { + ASSERT(!mRenderTarget); FramebufferAttachmentRenderTarget *rt = nullptr; - gl::Error error = mAttachmentBuffer->getAttachmentRenderTarget(mAttachmentTarget, &rt); - if (error.isError()) - { - return error; - } - + ANGLE_TRY( + mState.source->getAttachmentRenderTarget(context, GL_NONE, mState.imageIndex, &rt)); *outRT = static_cast(rt); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { ASSERT(mRenderTarget); *outRT = mRenderTarget; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error EGLImageD3D::copyToLocalRendertarget() +gl::Error EGLImageD3D::copyToLocalRendertarget(const gl::Context *context) { - ASSERT(mBuffer != nullptr); - ASSERT(mAttachmentBuffer != nullptr); + ASSERT(mState.source.get() != nullptr); ASSERT(mRenderTarget == nullptr); RenderTargetD3D *curRenderTarget = nullptr; - gl::Error error = getRenderTarget(&curRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getRenderTarget(context, &curRenderTarget)); - // Clear the source image buffers - mBuffer = nullptr; - mAttachmentBuffer = nullptr; + // This only currently applies do D3D11, where it invalidates FBOs with this Image attached. + curRenderTarget->signalDirty(context); return mRenderer->createRenderTargetCopy(curRenderTarget, &mRenderTarget); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h index 6ec33e08f2..1ee7984426 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/EGLImageD3D.h @@ -9,9 +9,13 @@ #ifndef LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_ #define LIBANGLE_RENDERER_D3D_EGLIMAGED3D_H_ -#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/renderer/ImageImpl.h" +namespace gl +{ +class Context; +} + namespace egl { class AttributeMap; @@ -19,6 +23,7 @@ class AttributeMap; namespace rx { +class FramebufferAttachmentObjectImpl; class TextureD3D; class RenderbufferD3D; class RendererD3D; @@ -27,30 +32,24 @@ class RenderTargetD3D; class EGLImageD3D final : public ImageImpl { public: - EGLImageD3D(RendererD3D *renderer, + EGLImageD3D(const egl::ImageState &state, EGLenum target, - egl::ImageSibling *buffer, - const egl::AttributeMap &attribs); + const egl::AttributeMap &attribs, + RendererD3D *renderer); ~EGLImageD3D() override; egl::Error initialize() override; - gl::Error orphan(egl::ImageSibling *sibling) override; + gl::Error orphan(const gl::Context *context, egl::ImageSibling *sibling) override; - gl::Error getRenderTarget(RenderTargetD3D **outRT) const; + gl::Error getRenderTarget(const gl::Context *context, RenderTargetD3D **outRT) const; private: - gl::Error copyToLocalRendertarget(); + gl::Error copyToLocalRendertarget(const gl::Context *context); RendererD3D *mRenderer; - - egl::ImageSibling *mBuffer; - - gl::FramebufferAttachment::Target mAttachmentTarget; - FramebufferAttachmentObjectImpl *mAttachmentBuffer; - RenderTargetD3D *mRenderTarget; }; -} +} // namespace rx #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 82967aced0..3d73b2c840 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp @@ -8,14 +8,16 @@ #include "libANGLE/renderer/d3d/FramebufferD3D.h" -#include "common/BitSetIterator.h" -#include "libANGLE/formatutils.h" +#include "common/bitset_utils.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Surface.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" -#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/SwapChainD3D.h" #include "libANGLE/renderer/d3d/TextureD3D.h" @@ -37,19 +39,19 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) { clearParams.clearColor[i] = false; } - clearParams.colorFClearValue = state.getColorClearValue(); - clearParams.colorClearType = GL_FLOAT; - clearParams.colorMaskRed = blendState.colorMaskRed; - clearParams.colorMaskGreen = blendState.colorMaskGreen; - clearParams.colorMaskBlue = blendState.colorMaskBlue; - clearParams.colorMaskAlpha = blendState.colorMaskAlpha; - clearParams.clearDepth = false; - clearParams.depthClearValue = state.getDepthClearValue(); - clearParams.clearStencil = false; - clearParams.stencilClearValue = state.getStencilClearValue(); + clearParams.colorF = state.getColorClearValue(); + clearParams.colorType = GL_FLOAT; + clearParams.colorMaskRed = blendState.colorMaskRed; + clearParams.colorMaskGreen = blendState.colorMaskGreen; + clearParams.colorMaskBlue = blendState.colorMaskBlue; + clearParams.colorMaskAlpha = blendState.colorMaskAlpha; + clearParams.clearDepth = false; + clearParams.depthValue = state.getDepthClearValue(); + clearParams.clearStencil = false; + clearParams.stencilValue = state.getStencilClearValue(); clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; - clearParams.scissorEnabled = state.isScissorTestEnabled(); - clearParams.scissor = state.getScissor(); + clearParams.scissorEnabled = state.isScissorTestEnabled(); + clearParams.scissor = state.getScissor(); const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer(); if (mask & GL_COLOR_BUFFER_BIT) @@ -65,7 +67,8 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) if (mask & GL_DEPTH_BUFFER_BIT) { - if (state.getDepthStencilState().depthMask && framebufferObject->getDepthbuffer() != NULL) + if (state.getDepthStencilState().depthMask && + framebufferObject->getDepthbuffer() != nullptr) { clearParams.clearDepth = true; } @@ -73,7 +76,7 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) if (mask & GL_STENCIL_BUFFER_BIT) { - if (framebufferObject->getStencilbuffer() != NULL && + if (framebufferObject->getStencilbuffer() != nullptr && framebufferObject->getStencilbuffer()->getStencilSize() > 0) { clearParams.clearStencil = true; @@ -82,10 +85,13 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) return clearParams; } - } -FramebufferD3D::FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer) +ClearParameters::ClearParameters() = default; + +ClearParameters::ClearParameters(const ClearParameters &other) = default; + +FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer) : FramebufferImpl(data), mRenderer(renderer) { } @@ -94,20 +100,19 @@ FramebufferD3D::~FramebufferD3D() { } -gl::Error FramebufferD3D::clear(const gl::Data &data, GLbitfield mask) +gl::Error FramebufferD3D::clear(const gl::Context *context, GLbitfield mask) { - const gl::State &state = *data.state; - ClearParameters clearParams = GetClearParameters(state, mask); - return clear(data, clearParams); + ClearParameters clearParams = GetClearParameters(context->getGLState(), mask); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferfv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) { // glClearBufferfv can be called to clear the color buffer or depth buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); if (buffer == GL_COLOR) { @@ -115,43 +120,43 @@ gl::Error FramebufferD3D::clearBufferfv(const gl::Data &data, { clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } - clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_FLOAT; + clearParams.colorF = gl::ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_FLOAT; } if (buffer == GL_DEPTH) { clearParams.clearDepth = true; - clearParams.depthClearValue = values[0]; + clearParams.depthValue = values[0]; } - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferuiv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) { // glClearBufferuiv can only be called to clear a color buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) { clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } - clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_UNSIGNED_INT; + clearParams.colorUI = gl::ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_UNSIGNED_INT; - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferiv(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) { // glClearBufferiv can be called to clear the color buffer or stencil buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); if (buffer == GL_COLOR) { @@ -159,167 +164,154 @@ gl::Error FramebufferD3D::clearBufferiv(const gl::Data &data, { clearParams.clearColor[i] = (drawbuffer == static_cast(i)); } - clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_INT; + clearParams.colorI = gl::ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorType = GL_INT; } if (buffer == GL_STENCIL) { clearParams.clearStencil = true; - clearParams.stencilClearValue = values[1]; + clearParams.stencilValue = values[0]; } - return clear(data, clearParams); + return clearImpl(context, clearParams); } -gl::Error FramebufferD3D::clearBufferfi(const gl::Data &data, +gl::Error FramebufferD3D::clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { // glClearBufferfi can only be called to clear a depth stencil buffer - ClearParameters clearParams = GetClearParameters(*data.state, 0); - clearParams.clearDepth = true; - clearParams.depthClearValue = depth; - clearParams.clearStencil = true; - clearParams.stencilClearValue = stencil; + ClearParameters clearParams = GetClearParameters(context->getGLState(), 0); + clearParams.clearDepth = true; + clearParams.depthValue = depth; + clearParams.clearStencil = true; + clearParams.stencilValue = stencil; - return clear(data, clearParams); + return clearImpl(context, clearParams); } -GLenum FramebufferD3D::getImplementationColorReadFormat() const +GLenum FramebufferD3D::getImplementationColorReadFormat(const gl::Context *context) const { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); if (readAttachment == nullptr) { return GL_NONE; } - RenderTargetD3D *attachmentRenderTarget = NULL; - gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget); + RenderTargetD3D *attachmentRenderTarget = nullptr; + gl::Error error = readAttachment->getRenderTarget(context, &attachmentRenderTarget); if (error.isError()) { return GL_NONE; } GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); - const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + const gl::InternalFormat &implementationFormatInfo = + gl::GetSizedInternalFormatInfo(implementationFormat); - return implementationFormatInfo.format; + return implementationFormatInfo.getReadPixelsFormat(); } -GLenum FramebufferD3D::getImplementationColorReadType() const +GLenum FramebufferD3D::getImplementationColorReadType(const gl::Context *context) const { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); if (readAttachment == nullptr) { return GL_NONE; } - RenderTargetD3D *attachmentRenderTarget = NULL; - gl::Error error = readAttachment->getRenderTarget(&attachmentRenderTarget); + RenderTargetD3D *attachmentRenderTarget = nullptr; + gl::Error error = readAttachment->getRenderTarget(context, &attachmentRenderTarget); if (error.isError()) { return GL_NONE; } GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); - const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + const gl::InternalFormat &implementationFormatInfo = + gl::GetSizedInternalFormatInfo(implementationFormat); - return implementationFormatInfo.type; + return implementationFormatInfo.getReadPixelsType(context->getClientVersion()); } -gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +gl::Error FramebufferD3D::readPixels(const gl::Context *context, + const gl::Rectangle &origArea, + GLenum format, + GLenum type, + void *pixels) { - const gl::PixelPackState &packState = state.getPackState(); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); - const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLuint outputPitch = - sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, packState.rowLength); - GLsizei outputSkipBytes = sizedFormatInfo.computeSkipPixels( - outputPitch, 0, 0, packState.skipRows, packState.skipPixels); - - 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, - GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) -{ - bool blitRenderTarget = false; - if ((mask & GL_COLOR_BUFFER_BIT) && - sourceFramebuffer->getReadColorbuffer() != nullptr && - mData.getFirstColorAttachment() != nullptr) + // Clip read area to framebuffer. + const gl::Extents fbSize = getState().getReadAttachment()->getSize(); + const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); + gl::Rectangle area; + if (!ClipRectangle(origArea, fbRect, &area)) { - blitRenderTarget = true; + // nothing to read + return gl::NoError(); } - bool blitStencil = false; - if ((mask & GL_STENCIL_BUFFER_BIT) && - sourceFramebuffer->getStencilbuffer() != nullptr && - mData.getStencilAttachment() != nullptr) - { - blitStencil = true; - } + const gl::PixelPackState &packState = context->getGLState().getPackState(); - bool blitDepth = false; - if ((mask & GL_DEPTH_BUFFER_BIT) && - sourceFramebuffer->getDepthbuffer() != nullptr && - mData.getDepthAttachment() != nullptr) - { - blitDepth = true; - } + const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type); - if (blitRenderTarget || blitDepth || blitStencil) - { - const gl::Rectangle *scissor = state.isScissorTestEnabled() ? &state.getScissor() : NULL; - gl::Error error = blit(sourceArea, destArea, scissor, blitRenderTarget, blitDepth, blitStencil, - filter, sourceFramebuffer); - if (error.isError()) - { - return error; - } - } + GLuint outputPitch = 0; + ANGLE_TRY_RESULT(sizedFormatInfo.computeRowPitch(type, origArea.width, packState.alignment, + packState.rowLength), + outputPitch); + GLuint outputSkipBytes = 0; + ANGLE_TRY_RESULT(sizedFormatInfo.computeSkipBytes(outputPitch, 0, packState, false), + outputSkipBytes); + outputSkipBytes += + (area.x - origArea.x) * sizedFormatInfo.pixelBytes + (area.y - origArea.y) * outputPitch; + + return readPixelsImpl(context, area, format, type, outputPitch, packState, + reinterpret_cast(pixels) + outputSkipBytes); +} - return gl::Error(GL_NO_ERROR); +gl::Error FramebufferD3D::blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) +{ + const auto &glState = context->getGLState(); + const gl::Framebuffer *sourceFramebuffer = glState.getReadFramebuffer(); + const gl::Rectangle *scissor = glState.isScissorTestEnabled() ? &glState.getScissor() : nullptr; + ANGLE_TRY(blitImpl(context, sourceArea, destArea, scissor, (mask & GL_COLOR_BUFFER_BIT) != 0, + (mask & GL_DEPTH_BUFFER_BIT) != 0, (mask & GL_STENCIL_BUFFER_BIT) != 0, + filter, sourceFramebuffer)); + + return gl::NoError(); } -bool FramebufferD3D::checkStatus() const +bool FramebufferD3D::checkStatus(const gl::Context *context) 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) + if (mState.getDepthAttachment() != nullptr && mState.getStencilAttachment() != nullptr && + mState.getDepthStencilAttachment() == nullptr) { return false; } - // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness - const auto &colorAttachments = mData.getColorAttachments(); - for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) + // D3D11 does not allow for overlapping RenderTargetViews. + // If WebGL compatibility is enabled, this has already been checked at a higher level. + ASSERT(!context->getExtensions().webglCompatibility || mState.colorAttachmentsAreUniqueImages()); + if (!context->getExtensions().webglCompatibility) { - const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachment]; - if (attachment.isAttached()) + if (!mState.colorAttachmentsAreUniqueImages()) { - for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++) - { - const gl::FramebufferAttachment &prevAttachment = colorAttachments[prevColorAttachment]; - if (prevAttachment.isAttached() && - (attachment.id() == prevAttachment.id() && - attachment.type() == prevAttachment.type())) - { - return false; - } - } + return false; } } // D3D requires all render targets to have the same dimensions. - if (!mData.attachmentsHaveSameDimensions()) + if (!mState.attachmentsHaveSameDimensions()) { return false; } @@ -327,45 +319,52 @@ bool FramebufferD3D::checkStatus() const return true; } -void FramebufferD3D::syncState(const gl::Framebuffer::DirtyBits &dirtyBits) +void FramebufferD3D::syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) { - bool invalidateColorAttachmentCache = false; - if (!mColorAttachmentsForRender.valid()) { - invalidateColorAttachmentCache = true; + return; } - for (auto dirtyBit : angle::IterateBitSet(dirtyBits)) + for (auto dirtyBit : dirtyBits) { if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 && dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) || dirtyBit == gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS) { - invalidateColorAttachmentCache = true; + mColorAttachmentsForRender.reset(); } } +} - if (!invalidateColorAttachmentCache) +const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context) +{ + gl::DrawBufferMask activeProgramOutputs = + context->getContextState().getState().getProgram()->getActiveOutputVariables(); + + if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs) { - return; + return mColorAttachmentsForRender.value(); } // Does not actually free memory gl::AttachmentList colorAttachmentsForRender; - const auto &colorAttachments = mData.getColorAttachments(); - const auto &drawBufferStates = mData.getDrawBufferStates(); + const auto &colorAttachments = mState.getColorAttachments(); + const auto &drawBufferStates = mState.getDrawBufferStates(); const auto &workarounds = mRenderer->getWorkarounds(); for (size_t attachmentIndex = 0; attachmentIndex < colorAttachments.size(); ++attachmentIndex) { - GLenum drawBufferState = drawBufferStates[attachmentIndex]; + GLenum drawBufferState = drawBufferStates[attachmentIndex]; const gl::FramebufferAttachment &colorAttachment = colorAttachments[attachmentIndex]; - if (colorAttachment.isAttached() && drawBufferState != GL_NONE) + if (colorAttachment.isAttached() && drawBufferState != GL_NONE && + activeProgramOutputs[attachmentIndex]) { - ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); + ASSERT(drawBufferState == GL_BACK || + drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); colorAttachmentsForRender.push_back(&colorAttachment); } else if (!workarounds.mrtPerfWorkaround) @@ -374,12 +373,32 @@ void FramebufferD3D::syncState(const gl::Framebuffer::DirtyBits &dirtyBits) } } + // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel + // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel + // shader. We add a dummy texture as render target in such case. + if (mRenderer->getWorkarounds().addDummyTextureNoRenderTarget && + colorAttachmentsForRender.empty()) + { + static_assert(static_cast(activeProgramOutputs.size()) <= 32, + "Size of active program outputs should less or equal than 32."); + GLenum i = static_cast( + gl::ScanForward(static_cast(activeProgramOutputs.bits()))); + + gl::Texture *dummyTex = nullptr; + // TODO(Jamie): Handle error if dummy texture can't be created. + ANGLE_SWALLOW_ERR(mRenderer->getIncompleteTexture(context, GL_TEXTURE_2D, &dummyTex)); + if (dummyTex) + { + gl::ImageIndex index = gl::ImageIndex::Make2D(0); + gl::FramebufferAttachment *dummyAttach = new gl::FramebufferAttachment( + context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + i, index, dummyTex); + colorAttachmentsForRender.push_back(dummyAttach); + } + } + mColorAttachmentsForRender = std::move(colorAttachmentsForRender); -} + mCurrentActiveProgramOutputs = activeProgramOutputs; -const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender() const -{ - ASSERT(mColorAttachmentsForRender.valid()); return mColorAttachmentsForRender.value(); } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h index eb839c4364..a7312fdef4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h @@ -9,9 +9,10 @@ #ifndef LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ #define LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ -#include #include +#include +#include "common/Color.h" #include "common/Optional.h" #include "libANGLE/angletypes.h" #include "libANGLE/renderer/FramebufferImpl.h" @@ -22,32 +23,33 @@ class FramebufferAttachment; struct PixelPackState; typedef std::vector AttachmentList; - } namespace rx { class RendererD3D; class RenderTargetD3D; -struct WorkaroundsD3D; struct ClearParameters { + ClearParameters(); + ClearParameters(const ClearParameters &other); + bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - gl::ColorF colorFClearValue; - gl::ColorI colorIClearValue; - gl::ColorUI colorUIClearValue; - GLenum colorClearType; + gl::ColorF colorF; + gl::ColorI colorI; + gl::ColorUI colorUI; + GLenum colorType; bool colorMaskRed; bool colorMaskGreen; bool colorMaskBlue; bool colorMaskAlpha; bool clearDepth; - float depthClearValue; + float depthValue; bool clearStencil; - GLint stencilClearValue; + GLint stencilValue; GLuint stencilWriteMask; bool scissorEnabled; @@ -57,61 +59,76 @@ struct ClearParameters class FramebufferD3D : public FramebufferImpl { public: - FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer); - virtual ~FramebufferD3D(); + FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer); + ~FramebufferD3D() override; - gl::Error clear(const gl::Data &data, GLbitfield mask) override; - gl::Error clearBufferfv(const gl::Data &data, + gl::Error clear(const gl::Context *context, GLbitfield mask) override; + gl::Error clearBufferfv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values) override; - gl::Error clearBufferuiv(const gl::Data &data, + gl::Error clearBufferuiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values) override; - gl::Error clearBufferiv(const gl::Data &data, + gl::Error clearBufferiv(const gl::Context *context, GLenum buffer, GLint drawbuffer, const GLint *values) override; - gl::Error clearBufferfi(const gl::Data &data, + gl::Error clearBufferfi(const gl::Context *context, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override; - GLenum getImplementationColorReadFormat() const override; - GLenum getImplementationColorReadType() const override; - gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const override; + GLenum getImplementationColorReadFormat(const gl::Context *context) const override; + GLenum getImplementationColorReadType(const gl::Context *context) const override; + gl::Error readPixels(const gl::Context *context, + const gl::Rectangle &area, + GLenum format, + GLenum type, + void *pixels) override; - gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, - GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) override; + gl::Error blit(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + GLbitfield mask, + GLenum filter) override; - bool checkStatus() const override; + bool checkStatus(const gl::Context *context) const override; - void syncState(const gl::Framebuffer::DirtyBits &dirtyBits) override; + void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) override; - const gl::AttachmentList &getColorAttachmentsForRender() const; + const gl::AttachmentList &getColorAttachmentsForRender(const gl::Context *context); private: - virtual gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) = 0; + virtual gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) = 0; - virtual gl::Error readPixelsImpl(const gl::Rectangle &area, + virtual gl::Error readPixelsImpl(const gl::Context *context, + 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; + uint8_t *pixels) = 0; + + virtual gl::Error blitImpl(const gl::Context *context, + 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; RendererD3D *mRenderer; Optional mColorAttachmentsForRender; + gl::DrawBufferMask mCurrentActiveProgramOutputs; }; - } -#endif // LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ +#endif // LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp index df0257e370..b38765070b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp @@ -6,16 +6,14 @@ #include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include + #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 - #if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED namespace { @@ -25,15 +23,6 @@ namespace #define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } -#if defined(ANGLE_MINGW32_COMPAT) -#ifndef D3DCOMPILE_RESERVED16 -#define D3DCOMPILE_RESERVED16 0x10000 -#endif -#ifndef D3DCOMPILE_RESERVED17 -#define D3DCOMPILE_RESERVED17 0x20000 -#endif -#endif - struct CompilerFlagInfo { UINT mFlag; @@ -119,11 +108,11 @@ HLSLCompiler::~HLSLCompiler() release(); } -gl::Error HLSLCompiler::initialize() +gl::Error HLSLCompiler::ensureInitialized() { if (mInitialized) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } TRACE_EVENT0("gpu.angle", "HLSLCompiler::initialize"); @@ -141,28 +130,6 @@ gl::Error HLSLCompiler::initialize() } #endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES - // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL - const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); - if (!defaultCompiler) - defaultCompiler = QT_D3DCOMPILER_DLL; - - const wchar_t *compilerDlls[] = { - defaultCompiler, - L"d3dcompiler_47.dll", - L"d3dcompiler_46.dll", - L"d3dcompiler_43.dll", - 0 - }; - - // Load the first available known compiler DLL - for (int i = 0; compilerDlls[i]; ++i) - { - mD3DCompilerModule = LoadLibrary(compilerDlls[i]); - if (mD3DCompilerModule) - break; - } - - if (!mD3DCompilerModule) { // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. @@ -171,7 +138,8 @@ gl::Error HLSLCompiler::initialize() if (!mD3DCompilerModule) { - return gl::Error(GL_INVALID_OPERATION, "No D3D compiler module found - aborting!\n"); + ERR() << "D3D compiler module not found."; + return gl::OutOfMemory() << "D3D compiler module not found."; } mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); @@ -190,11 +158,11 @@ gl::Error HLSLCompiler::initialize() if (mD3DCompileFunc == nullptr) { - return gl::Error(GL_INVALID_OPERATION, "Error finding D3DCompile entry point"); + return gl::OutOfMemory() << "Error finding D3DCompile entry point."; } mInitialized = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void HLSLCompiler::release() @@ -213,11 +181,7 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, ID3DBlob **outCompiledBlob, std::string *outDebugInfo) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ASSERT(mInitialized); #if !defined(ANGLE_ENABLE_WINDOWS_STORE) ASSERT(mD3DCompilerModule); @@ -228,7 +192,9 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string if (gl::DebugAnnotationsActive()) { std::string sourcePath = getTempPath(); - std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); + std::ostringstream stream; + stream << "#line 2 \"" << sourcePath << "\"\n\n" << hlsl; + std::string sourceText = stream.str(); writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); } #endif @@ -255,8 +221,11 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string SafeRelease(errorMessage); infoLog.appendSanitized(message.c_str()); - TRACE("\n%s", hlsl.c_str()); - TRACE("\n%s", message.c_str()); + + // This produces unbelievable amounts of spam in about:gpu. + // WARN() << std::endl << hlsl; + + WARN() << std::endl << message; 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", @@ -304,20 +273,17 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string } std::string disassembly; - error = disassembleBinary(binary, &disassembly); - if (error.isError()) - { - return error; - } + ANGLE_TRY(disassembleBinary(binary, &disassembly)); (*outDebugInfo) += "\n" + disassembly + "\n// ASSEMBLY END\n"; #endif // ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (result == E_OUTOFMEMORY) { *outCompiledBlob = nullptr; - return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); + return gl::OutOfMemory() + << "HLSL compiler had an unexpected failure, " << gl::FmtHR(result); } infoLog << "Warning: D3D shader compilation failed with " << configs[i].name << " flags. (" @@ -331,16 +297,12 @@ gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string // None of the configurations succeeded in compiling this shader but the compiler is still intact *outCompiledBlob = nullptr; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureInitialized()); // Retrieve disassembly UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; @@ -361,7 +323,7 @@ gl::Error HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary, std::string *d SafeRelease(disassembly); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } // 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 3c0d2adcac..c8f9eac290 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h @@ -1,3 +1,11 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// HLSLCompiler: Wrapper for the D3DCompiler DLL. +// + #ifndef LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ #define LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ @@ -41,9 +49,9 @@ class HLSLCompiler : angle::NonCopyable ID3DBlob **outCompiledBlob, std::string *outDebugInfo); gl::Error disassembleBinary(ID3DBlob *shaderBinary, std::string *disassemblyOut); + gl::Error ensureInitialized(); private: - gl::Error initialize(); bool mInitialized; HMODULE mD3DCompilerModule; @@ -53,4 +61,4 @@ class HLSLCompiler : angle::NonCopyable } -#endif // LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ +#endif // LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp index ead5db6453..dbbcbbed2a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp @@ -29,4 +29,34 @@ ImageD3D::ImageD3D() { } +gl::Error ImageD3D::setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurface3D(const gl::Context *context, + TextureStorage *storage, + int level) +{ + return gl::NoError(); +} + +gl::Error ImageD3D::setManagedSurface2DArray(const gl::Context *context, + TextureStorage *storage, + int layer, + int level) +{ + return gl::NoError(); +} + } // 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 2afe1cfabf..1b7235fbaa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h @@ -17,6 +17,7 @@ namespace gl { +class Context; class Framebuffer; struct ImageIndex; struct Box; @@ -51,18 +52,40 @@ class ImageD3D : angle::NonCopyable virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; - virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) = 0; - virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; - - virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; - 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 copyFromTexStorage(const gl::ImageIndex &imageIndex, + virtual gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) = 0; + virtual gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) = 0; + + virtual gl::Error setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level); + virtual gl::Error setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level); + virtual gl::Error setManagedSurface3D(const gl::Context *context, + TextureStorage *storage, + int level); + virtual gl::Error setManagedSurface2DArray(const gl::Context *context, + TextureStorage *storage, + int layer, + int level); + virtual gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) = 0; + + virtual gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, TextureStorage *source) = 0; - virtual gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + virtual gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp index 677b8bb240..937512a96a 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp @@ -71,7 +71,8 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem // Protect against integer overflow if (mWritePosition + size < mWritePosition) { - return gl::Error(GL_OUT_OF_MEMORY, "Mapping of internal index buffer would cause an integer overflow."); + return gl::OutOfMemory() + << "Mapping of internal index buffer would cause an integer overflow."; } gl::Error error = mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory); @@ -79,7 +80,7 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem { if (outMappedMemory) { - *outMappedMemory = NULL; + *outMappedMemory = nullptr; } return error; } @@ -90,7 +91,7 @@ gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMem } mWritePosition += size; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBufferInterface::unmapBuffer() @@ -145,24 +146,16 @@ gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, G unsigned int writePos = getWritePosition(); if (size > curBufferSize) { - gl::Error error = setBufferSize(std::max(size, 2 * curBufferSize), indexType); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setBufferSize(std::max(size, 2 * curBufferSize), indexType)); setWritePosition(0); } else if (writePos + size > curBufferSize || writePos + size < writePos) { - gl::Error error = discard(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(discard()); setWritePosition(0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } @@ -184,13 +177,13 @@ gl::Error StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLen } else if (curSize >= size && indexType == getIndexType()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal static index buffers can't be resized"); + return gl::InternalError() << "Internal static index buffers can't be resized"; } } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h index 0b7b28ddf0..969cf6ae63 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h @@ -81,7 +81,7 @@ class StreamingIndexBufferInterface : public IndexBufferInterface { public: explicit StreamingIndexBufferInterface(BufferFactoryD3D *factory); - ~StreamingIndexBufferInterface(); + ~StreamingIndexBufferInterface() override; gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; }; @@ -90,7 +90,7 @@ class StaticIndexBufferInterface : public IndexBufferInterface { public: explicit StaticIndexBufferInterface(BufferFactoryD3D *factory); - ~StaticIndexBufferInterface(); + ~StaticIndexBufferInterface() override; gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp index f1ba3d3db0..e974097b45 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp @@ -10,10 +10,12 @@ #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" +#include "libANGLE/Context.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" namespace rx { @@ -76,11 +78,12 @@ void ConvertIndices(GLenum sourceType, ConvertIndexArray(input, sourceType, output, destinationType, count, usePrimitiveRestartFixedIndex); } - else UNREACHABLE(); + else + UNREACHABLE(); } gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, - const GLvoid *data, + const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -91,50 +94,59 @@ gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, 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); + return gl::OutOfMemory() << "Reserving " << count << " indices of " << dstTypeInfo.bytes + << " bytes each exceeds the maximum buffer size."; } unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift; - gl::Error error = buffer->reserveBufferSpace(bufferSizeRequired, dstType); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->reserveBufferSpace(bufferSizeRequired, dstType)); void *output = nullptr; - error = buffer->mapBuffer(bufferSizeRequired, &output, offset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->mapBuffer(bufferSizeRequired, &output, offset)); ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex); - error = buffer->unmapBuffer(); - if (error.isError()) + ANGLE_TRY(buffer->unmapBuffer()); + return gl::NoError(); +} + +unsigned int ElementTypeSize(GLenum elementType) +{ + switch (elementType) { - return error; + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + default: + UNREACHABLE(); + return 0; } - - return gl::Error(GL_NO_ERROR); } } // anonymous namespace -IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass) - : mFactory(factory), - mRendererClass(rendererClass), - mStreamingBufferShort(nullptr), - mStreamingBufferInt(nullptr) +bool IsOffsetAligned(GLenum elementType, unsigned int offset) +{ + return (offset % ElementTypeSize(elementType) == 0); +} + +// IndexDataManager implementation. +IndexDataManager::IndexDataManager(BufferFactoryD3D *factory) + : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt() { } IndexDataManager::~IndexDataManager() { - SafeDelete(mStreamingBufferShort); - SafeDelete(mStreamingBufferInt); +} + +void IndexDataManager::deinitialize() +{ + mStreamingBufferShort.reset(); + mStreamingBufferInt.reset(); } // This function translates a GL-style indices into DX-style indices, with their description @@ -143,43 +155,31 @@ IndexDataManager::~IndexDataManager() // 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, +// 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(const gl::Context *context, + GLenum srcType, + GLenum dstType, GLsizei count, gl::Buffer *glBuffer, - const GLvoid *indices, - TranslatedIndexData *translated, - bool primitiveRestartFixedIndexEnabled) + const void *indices, + TranslatedIndexData *translated) { - // 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->indexType = dstType; translated->srcIndexData.srcBuffer = buffer; translated->srcIndexData.srcIndices = indices; translated->srcIndexData.srcIndexType = srcType; translated->srcIndexData.srcCount = count; + // Context can be nullptr in perf tests. + bool primitiveRestartFixedIndexEnabled = + context ? context->getGLState().isPrimitiveRestartEnabled() : false; + // Case 1: the indices are passed by pointer, which forces the streaming of index data if (glBuffer == nullptr) { @@ -192,95 +192,69 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, unsigned int offset = static_cast(reinterpret_cast(indices)); ASSERT(srcTypeInfo.bytes * static_cast(count) + offset <= buffer->getSize()); - bool offsetAligned; - switch (srcType) - { - 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; - } + bool offsetAligned = IsOffsetAligned(srcType, offset); // Case 2a: the buffer can be used directly - if (offsetAligned && buffer->supportsDirectBinding() && - dstType == srcType && !primitiveRestartWorkaround) + if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType) { - translated->storage = buffer; + translated->storage = buffer; translated->indexBuffer = nullptr; - translated->serial = buffer->getSerial(); - translated->startIndex = (offset >> srcTypeInfo.bytesShift); + translated->serial = buffer->getSerial(); + translated->startIndex = (offset >> srcTypeInfo.bytesShift); translated->startOffset = offset; - buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift); - return gl::Error(GL_NO_ERROR); - } - else - { - translated->storage = nullptr; + return gl::NoError(); } + translated->storage = nullptr; + // Case 2b: use a static translated copy or fall back to streaming StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer(); bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0; - bool staticBufferUsable = staticBuffer && - offsetAligned && staticBuffer->getIndexType() == dstType; + bool staticBufferUsable = + staticBuffer && offsetAligned && staticBuffer->getIndexType() == dstType; if (staticBufferInitialized && !staticBufferUsable) { - buffer->invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + buffer->invalidateStaticData(context); staticBuffer = nullptr; } if (staticBuffer == nullptr || !offsetAligned) { const uint8_t *bufferData = nullptr; - gl::Error error = buffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); - error = streamIndexData(bufferData + offset, count, srcType, dstType, - primitiveRestartFixedIndexEnabled, translated); - if (error.isError()) - { - return error; - } + ANGLE_TRY(streamIndexData(bufferData + offset, count, srcType, dstType, + primitiveRestartFixedIndexEnabled, translated)); + buffer->promoteStaticUsage(context, count << srcTypeInfo.bytesShift); } else { if (!staticBufferInitialized) { const uint8_t *bufferData = nullptr; - gl::Error error = buffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); unsigned int convertCount = static_cast(buffer->getSize()) >> srcTypeInfo.bytesShift; - error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType, - primitiveRestartFixedIndexEnabled, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType, + primitiveRestartFixedIndexEnabled, nullptr)); } ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType); translated->indexBuffer = staticBuffer->getIndexBuffer(); - translated->serial = staticBuffer->getSerial(); - translated->startIndex = (offset >> srcTypeInfo.bytesShift); + translated->serial = staticBuffer->getSerial(); + translated->startIndex = (offset >> srcTypeInfo.bytesShift); translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error IndexDataManager::streamIndexData(const GLvoid *data, +gl::Error IndexDataManager::streamIndexData(const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -290,65 +264,57 @@ gl::Error IndexDataManager::streamIndexData(const GLvoid *data, const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType); IndexBufferInterface *indexBuffer = nullptr; - gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getStreamingIndexBuffer(dstType, &indexBuffer)); ASSERT(indexBuffer != nullptr); unsigned int offset; - StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, usePrimitiveRestartFixedIndex, - &offset); + ANGLE_TRY(StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, + usePrimitiveRestartFixedIndex, &offset)); translated->indexBuffer = indexBuffer->getIndexBuffer(); - translated->serial = indexBuffer->getSerial(); - translated->startIndex = (offset >> dstTypeInfo.bytesShift); + translated->serial = indexBuffer->getSerial(); + translated->startIndex = (offset >> dstTypeInfo.bytesShift); translated->startOffset = offset; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) { ASSERT(outBuffer); - if (destinationIndexType == GL_UNSIGNED_INT) - { - if (!mStreamingBufferInt) - { - mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory); - gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, - GL_UNSIGNED_INT); - if (error.isError()) - { - SafeDelete(mStreamingBufferInt); - return error; - } - } + ASSERT(destinationIndexType == GL_UNSIGNED_SHORT || destinationIndexType == GL_UNSIGNED_INT); - *outBuffer = mStreamingBufferInt; - return gl::Error(GL_NO_ERROR); - } - else + auto &streamingBuffer = + (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; + + if (!streamingBuffer) { - ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); + StreamingBuffer newBuffer(new StreamingIndexBufferInterface(mFactory)); + ANGLE_TRY(newBuffer->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, destinationIndexType)); + streamingBuffer = std::move(newBuffer); + } - if (!mStreamingBufferShort) + *outBuffer = streamingBuffer.get(); + return gl::NoError(); +} + +GLenum GetIndexTranslationDestType(GLenum srcType, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround) +{ + // Avoid D3D11's primitive restart index value + // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx + if (usePrimitiveRestartWorkaround) + { + const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value(); + if (indexRange.end == gl::GetPrimitiveRestartIndex(srcType)) { - mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory); - gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, - GL_UNSIGNED_SHORT); - if (error.isError()) - { - SafeDelete(mStreamingBufferShort); - return error; - } + return GL_UNSIGNED_INT; } - - *outBuffer = mStreamingBufferShort; - return gl::Error(GL_NO_ERROR); } -} + return (srcType == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h index 44eb68c071..77f05df92d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h @@ -19,7 +19,10 @@ namespace { - enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +enum +{ + INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) +}; } namespace gl @@ -39,7 +42,7 @@ class RendererD3D; struct SourceIndexData { BufferD3D *srcBuffer; - const GLvoid *srcIndices; + const void *srcIndices; unsigned int srcCount; GLenum srcIndexType; bool srcIndicesChanged; @@ -47,9 +50,8 @@ struct SourceIndexData struct TranslatedIndexData { - gl::IndexRange indexRange; unsigned int startIndex; - unsigned int startOffset; // In bytes + unsigned int startOffset; // In bytes IndexBuffer *indexBuffer; BufferD3D *storage; @@ -62,18 +64,21 @@ struct TranslatedIndexData class IndexDataManager : angle::NonCopyable { public: - explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); + explicit IndexDataManager(BufferFactoryD3D *factory); virtual ~IndexDataManager(); - gl::Error prepareIndexData(GLenum srcType, + void deinitialize(); + + gl::Error prepareIndexData(const gl::Context *context, + GLenum srcType, + GLenum dstType, GLsizei count, gl::Buffer *glBuffer, - const GLvoid *indices, - TranslatedIndexData *translated, - bool primitiveRestartFixedIndexEnabled); + const void *indices, + TranslatedIndexData *translated); private: - gl::Error streamIndexData(const GLvoid *data, + gl::Error streamIndexData(const void *data, unsigned int count, GLenum srcType, GLenum dstType, @@ -82,12 +87,19 @@ class IndexDataManager : angle::NonCopyable gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); + using StreamingBuffer = std::unique_ptr; + BufferFactoryD3D *const mFactory; - RendererClass mRendererClass; - StreamingIndexBufferInterface *mStreamingBufferShort; - StreamingIndexBufferInterface *mStreamingBufferInt; + std::unique_ptr mStreamingBufferShort; + std::unique_ptr mStreamingBufferInt; }; -} +GLenum GetIndexTranslationDestType(GLenum srcType, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround); + +bool IsOffsetAligned(GLenum elementType, unsigned int offset); + +} // namespace rx -#endif // LIBANGLE_INDEXDATAMANAGER_H_ +#endif // LIBANGLE_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp new file mode 100644 index 0000000000..113bad647c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindowD3D.cpp: Defines NativeWindowD3D, a class for managing and performing operations on +// an EGLNativeWindowType for the D3D renderers. + +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +NativeWindowD3D::NativeWindowD3D(EGLNativeWindowType window) : mWindow(window) +{ +} + +NativeWindowD3D::~NativeWindowD3D() +{ +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h new file mode 100644 index 0000000000..365448488d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/NativeWindowD3D.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindowD3D.h: Defines NativeWindowD3D, a class for managing and performing operations on an +// EGLNativeWindowType for the D3D renderers. + +#ifndef LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ +#define LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include +#include "libANGLE/Config.h" + +namespace rx +{ +class NativeWindowD3D : angle::NonCopyable +{ + public: + NativeWindowD3D(EGLNativeWindowType window); + virtual ~NativeWindowD3D(); + + virtual bool initialize() = 0; + virtual bool getClientRect(LPRECT rect) const = 0; + virtual bool isIconic() const = 0; + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + + private: + EGLNativeWindowType mWindow; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_NATIVEWINDOWD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp index 72c6f1a1a9..afc318d9fa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -8,31 +8,41 @@ #include "libANGLE/renderer/d3d/ProgramD3D.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" +#include "common/string_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Program.h" +#include "libANGLE/ProgramLinkedResources.h" +#include "libANGLE/Uniform.h" #include "libANGLE/VertexArray.h" #include "libANGLE/features.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/renderer/ContextImpl.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" +using namespace angle; + namespace rx { namespace { -gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader) +void GetDefaultInputLayoutFromShader(const gl::Context *context, + gl::Shader *vertexShader, + gl::InputLayout *inputLayoutOut) { - gl::InputLayout defaultLayout; - for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes()) + inputLayoutOut->clear(); + + for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes(context)) { if (shaderAttr.type != GL_NONE) { @@ -47,301 +57,256 @@ gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader) gl::VertexFormatType defaultType = gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt); - defaultLayout.push_back(defaultType); + inputLayoutOut->push_back(defaultType); } } } - - return defaultLayout; } -std::vector GetDefaultOutputLayoutFromShader( - const std::vector &shaderOutputVars) +void GetDefaultOutputLayoutFromShader( + const std::vector &shaderOutputVars, + std::vector *outputLayoutOut) { - std::vector defaultPixelOutput; + outputLayoutOut->clear(); if (!shaderOutputVars.empty()) { - defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + - static_cast(shaderOutputVars[0].outputIndex)); + outputLayoutOut->push_back(GL_COLOR_ATTACHMENT0 + + static_cast(shaderOutputVars[0].outputIndex)); } - - return defaultPixelOutput; } -bool IsRowMajorLayout(const sh::InterfaceBlockField &var) +template +bool TransposeExpandMatrix(T *target, const GLfloat *value) { - return var.isRowMajorLayout; -} + constexpr int targetWidth = 4; + constexpr int targetHeight = rows; + constexpr int srcWidth = rows; + constexpr int srcHeight = cols; -bool IsRowMajorLayout(const sh::ShaderVariable &var) -{ - return false; -} + constexpr int copyWidth = std::min(targetHeight, srcWidth); + constexpr int copyHeight = std::min(targetWidth, srcHeight); -struct AttributeSorter -{ - AttributeSorter(const ProgramD3D::SemanticIndexArray &semanticIndices) - : originalIndices(&semanticIndices) + T staging[targetWidth * targetHeight] = {0}; + + for (int x = 0; x < copyWidth; x++) { + for (int y = 0; y < copyHeight; y++) + { + staging[x * targetWidth + y] = static_cast(value[y * srcWidth + x]); + } } - bool operator()(int a, int b) + if (memcmp(target, staging, targetWidth * targetHeight * sizeof(T)) == 0) { - int indexA = (*originalIndices)[a]; - int indexB = (*originalIndices)[b]; - - if (indexA == -1) - return false; - if (indexB == -1) - return true; - return (indexA < indexB); + return false; } - 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); + memcpy(target, staging, targetWidth * targetHeight * sizeof(T)); + return true; } -std::vector MergeVaryings(const gl::Shader &vertexShader, - const gl::Shader &fragmentShader, - const std::vector &tfVaryings) +template +bool ExpandMatrix(T *target, const GLfloat *value) { - std::vector packedVaryings; - - for (const sh::Varying &output : vertexShader.getVaryings()) - { - bool packed = false; + constexpr int targetWidth = 4; + constexpr int targetHeight = rows; + constexpr int srcWidth = cols; + constexpr int srcHeight = rows; - // Built-in varyings obey special rules - if (output.isBuiltIn()) - { - continue; - } + constexpr int copyWidth = std::min(targetWidth, srcWidth); + constexpr int copyHeight = std::min(targetHeight, srcHeight); - 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; - } - } + T staging[targetWidth * targetHeight] = {0}; - // Keep Transform FB varyings in the merged list always. - if (!packed) + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; x++) { - 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; - } - } + staging[y * targetWidth + x] = static_cast(value[y * srcWidth + x]); } } - std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying); + if (memcmp(target, staging, targetWidth * targetHeight * sizeof(T)) == 0) + { + return false; + } - return packedVaryings; + memcpy(target, staging, targetWidth * targetHeight * sizeof(T)); + return true; } -template -void GetUniformBlockInfo(const std::vector &fields, - const std::string &prefix, - sh::BlockLayoutEncoder *encoder, - bool inRowMajorLayout, - std::map *blockInfoOut) +gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) { - for (const VarT &field : fields) + switch (drawMode) { - const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + // Uses the point sprite geometry shader. + case GL_POINTS: + return gl::PRIMITIVE_POINTS; - if (field.isStruct()) - { - bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + // All line drawing uses the same geometry shader. + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + return gl::PRIMITIVE_LINES; - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) - { - encoder->enterAggregateType(); + // The triangle fan primitive is emulated with strips in D3D11. + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + return gl::PRIMITIVE_TRIANGLES; - const std::string uniformElementName = - fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); - GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout, - blockInfoOut); + // Special case for triangle strips. + case GL_TRIANGLE_STRIP: + return gl::PRIMITIVE_TRIANGLE_STRIP; - encoder->exitAggregateType(); - } - } - else - { - bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); - (*blockInfoOut)[fieldName] = - encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); - } + default: + UNREACHABLE(); + return gl::PRIMITIVE_TYPE_MAX; } } -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 FindFlatInterpolationVarying(const std::vector &varyings) { - 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++) + // Note: this assumes nested structs can only be packed with one interpolation. + for (const auto &varying : varyings) { - for (int x = copyHeight; x < targetWidth; x++) + if (varying.interpolation == sh::INTERPOLATION_FLAT) { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + return true; } } - // clear unfilled bottom. - for (int y = copyWidth; y < targetHeight; y++) + + return false; +} + +// Helper method to de-tranpose a matrix uniform for an API query. +void GetMatrixUniform(GLint columns, GLint rows, GLfloat *dataOut, const GLfloat *source) +{ + for (GLint col = 0; col < columns; ++col) { - for (int x = 0; x < targetWidth; x++) + for (GLint row = 0; row < rows; ++row) { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + GLfloat *outptr = dataOut + ((col * rows) + row); + const GLfloat *inptr = source + ((row * 4) + col); + *outptr = *inptr; } } +} - return dirty; +template +void GetMatrixUniform(GLint columns, GLint rows, NonFloatT *dataOut, const NonFloatT *source) +{ + UNREACHABLE(); } -template -bool ExpandMatrix(T *target, - const GLfloat *value, - int targetWidth, - int targetHeight, - int srcWidth, - int srcHeight) +class UniformBlockInfo final : angle::NonCopyable { - bool dirty = false; - int copyWidth = std::min(targetWidth, srcWidth); - int copyHeight = std::min(targetHeight, srcHeight); + public: + UniformBlockInfo() {} - for (int y = 0; y < copyHeight; y++) + void getShaderBlockInfo(const gl::Context *context, gl::Shader *shader); + + bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut); + bool getBlockMemberInfo(const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut); + + private: + size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock); + + std::map mBlockSizes; + sh::BlockLayoutMap mBlockLayout; +}; + +void UniformBlockInfo::getShaderBlockInfo(const gl::Context *context, gl::Shader *shader) +{ + for (const sh::InterfaceBlock &interfaceBlock : shader->getUniformBlocks(context)) { - for (int x = 0; x < copyWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), - &dirty); - } + if (!interfaceBlock.staticUse && interfaceBlock.layout == sh::BLOCKLAYOUT_PACKED) + continue; + + if (mBlockSizes.count(interfaceBlock.name) > 0) + continue; + + size_t dataSize = getBlockInfo(interfaceBlock); + mBlockSizes[interfaceBlock.name] = dataSize; } - // clear unfilled right side - for (int y = 0; y < copyHeight; y++) +} + +size_t UniformBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock) +{ + ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED); + + // define member uniforms + sh::Std140BlockEncoder std140Encoder; + sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false); + sh::BlockLayoutEncoder *encoder = nullptr; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140) { - for (int x = copyWidth; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } + encoder = &std140Encoder; } - // clear unfilled bottom. - for (int y = copyHeight; y < targetHeight; y++) + else { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } + encoder = &hlslEncoder; } - return dirty; + sh::GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, + interfaceBlock.isRowMajorLayout, &mBlockLayout); + + return encoder->getBlockSize(); } -gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) +bool UniformBlockInfo::getBlockSize(const std::string &name, + const std::string &mappedName, + size_t *sizeOut) { - switch (drawMode) + size_t nameLengthWithoutArrayIndex; + gl::ParseArrayIndex(name, &nameLengthWithoutArrayIndex); + std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex); + auto sizeIter = mBlockSizes.find(baseName); + if (sizeIter == mBlockSizes.end()) { - // 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; + *sizeOut = 0; + return false; + } - // Special case for triangle strips. - case GL_TRIANGLE_STRIP: - return gl::PRIMITIVE_TRIANGLE_STRIP; + *sizeOut = sizeIter->second; + return true; +}; - default: - UNREACHABLE(); - return gl::PRIMITIVE_TYPE_MAX; +bool UniformBlockInfo::getBlockMemberInfo(const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut) +{ + auto infoIter = mBlockLayout.find(name); + if (infoIter == mBlockLayout.end()) + { + *infoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); + return false; } -} + + *infoOut = infoIter->second; + return true; +}; } // anonymous namespace // D3DUniform Implementation -D3DUniform::D3DUniform(GLenum typeIn, +D3DUniform::D3DUniform(GLenum type, const std::string &nameIn, - unsigned int arraySizeIn, + const std::vector &arraySizesIn, bool defaultBlock) - : type(typeIn), + : typeInfo(gl::GetUniformTypeInfo(type)), name(nameIn), - arraySize(arraySizeIn), - data(nullptr), - dirty(true), + arraySizes(arraySizesIn), + vsData(nullptr), + psData(nullptr), + csData(nullptr), vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX), + csRegisterIndex(GL_INVALID_INDEX), registerCount(0), registerElement(0) { @@ -350,23 +315,36 @@ D3DUniform::D3DUniform(GLenum typeIn, // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) if (defaultBlock) { - size_t bytes = gl::VariableInternalSize(type) * elementCount(); - data = new uint8_t[bytes]; - memset(data, 0, bytes); - - // TODO(jmadill): is this correct with non-square matrices? - registerCount = gl::VariableRowCount(type) * elementCount(); + // Use the row count as register count, will work for non-square matrices. + registerCount = typeInfo.rowCount * getArraySizeProduct(); } } D3DUniform::~D3DUniform() { - SafeDeleteArray(data); +} + +unsigned int D3DUniform::getArraySizeProduct() const +{ + return gl::ArraySizeProduct(arraySizes); +} + +const uint8_t *D3DUniform::getDataPtrToElement(size_t elementIndex) const +{ + ASSERT((!isArray() && elementIndex == 0) || + (isArray() && elementIndex < getArraySizeProduct())); + + if (isSampler()) + { + return reinterpret_cast(&mSamplerData[elementIndex]); + } + + return firstNonNullData() + (elementIndex > 0 ? (typeInfo.internalSize * elementIndex) : 0u); } bool D3DUniform::isSampler() const { - return gl::IsSamplerType(type); + return typeInfo.isSampler; } bool D3DUniform::isReferencedByVertexShader() const @@ -379,6 +357,23 @@ bool D3DUniform::isReferencedByFragmentShader() const return psRegisterIndex != GL_INVALID_INDEX; } +bool D3DUniform::isReferencedByComputeShader() const +{ + return csRegisterIndex != GL_INVALID_INDEX; +} + +const uint8_t *D3DUniform::firstNonNullData() const +{ + ASSERT(vsData || psData || csData || !mSamplerData.empty()); + + if (!mSamplerData.empty()) + { + return reinterpret_cast(mSamplerData.data()); + } + + return vsData ? vsData : (psData ? psData : csData); +} + // D3DVarying Implementation D3DVarying::D3DVarying() : semanticIndex(0), componentCount(0), outputSlot(0) @@ -398,16 +393,17 @@ D3DVarying::D3DVarying(const std::string &semanticNameIn, // ProgramD3DMetadata Implementation -ProgramD3DMetadata::ProgramD3DMetadata(int rendererMajorShaderModel, - const std::string &shaderModelSuffix, - bool usesInstancedPointSpriteEmulation, - bool usesViewScale, +ProgramD3DMetadata::ProgramD3DMetadata(RendererD3D *renderer, const ShaderD3D *vertexShader, const ShaderD3D *fragmentShader) - : mRendererMajorShaderModel(rendererMajorShaderModel), - mShaderModelSuffix(shaderModelSuffix), - mUsesInstancedPointSpriteEmulation(usesInstancedPointSpriteEmulation), - mUsesViewScale(usesViewScale), + : mRendererMajorShaderModel(renderer->getMajorShaderModel()), + mShaderModelSuffix(renderer->getShaderModelSuffix()), + mUsesInstancedPointSpriteEmulation( + renderer->getWorkarounds().useInstancedPointSpriteEmulation), + mUsesViewScale(renderer->presentPathFastEnabled()), + mHasANGLEMultiviewEnabled(vertexShader->hasANGLEMultiviewEnabled()), + mUsesViewID(fragmentShader->usesViewID()), + mCanSelectViewInVertexShader(renderer->canSelectViewInVertexShader()), mVertexShader(vertexShader), mFragmentShader(fragmentShader) { @@ -418,12 +414,13 @@ int ProgramD3DMetadata::getRendererMajorShaderModel() const return mRendererMajorShaderModel; } -bool ProgramD3DMetadata::usesBroadcast(const gl::Data &data) const +bool ProgramD3DMetadata::usesBroadcast(const gl::ContextState &data) const { - return (mFragmentShader->usesFragColor() && data.clientVersion < 3); + return (mFragmentShader->usesFragColor() && mFragmentShader->usesMultipleRenderTargets() && + data.getClientMajorVersion() < 3); } -bool ProgramD3DMetadata::usesFragDepth(const gl::Program::Data &programData) const +bool ProgramD3DMetadata::usesFragDepth() const { return mFragmentShader->usesFragDepth(); } @@ -445,7 +442,8 @@ bool ProgramD3DMetadata::usesPointSize() const bool ProgramD3DMetadata::usesInsertedPointCoordValue() const { - return !usesPointSize() && usesPointCoord() && mRendererMajorShaderModel >= 4; + return (!usesPointSize() || !mUsesInstancedPointSpriteEmulation) && usesPointCoord() && + mRendererMajorShaderModel >= 4; } bool ProgramD3DMetadata::usesViewScale() const @@ -453,15 +451,29 @@ bool ProgramD3DMetadata::usesViewScale() const return mUsesViewScale; } +bool ProgramD3DMetadata::hasANGLEMultiviewEnabled() const +{ + return mHasANGLEMultiviewEnabled; +} + +bool ProgramD3DMetadata::usesViewID() const +{ + return mUsesViewID; +} + +bool ProgramD3DMetadata::canSelectViewInVertexShader() const +{ + return mCanSelectViewInVertexShader; +} + bool ProgramD3DMetadata::addsPointCoordToVertexShader() const { - // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader + // PointSprite emulation requiress 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. + // Even with a geometry shader, the app can render triangles or lines and reference + // gl_PointCoord in the fragment shader, requiring us to provide a dummy value. For + // simplicity, we always add this to the vertex shader when the fragment shader + // references gl_PointCoord, even if we could skip it in the geometry shader. return (mUsesInstancedPointSpriteEmulation && usesPointCoord()) || usesInsertedPointCoordValue(); } @@ -508,25 +520,45 @@ ProgramD3D::VertexExecutable::~VertexExecutable() SafeDelete(mShaderExecutable); } +// static +ProgramD3D::VertexExecutable::HLSLAttribType ProgramD3D::VertexExecutable::GetAttribType( + GLenum type) +{ + switch (type) + { + case GL_INT: + return HLSLAttribType::SIGNED_INT; + case GL_UNSIGNED_INT: + return HLSLAttribType::UNSIGNED_INT; + case GL_SIGNED_NORMALIZED: + case GL_UNSIGNED_NORMALIZED: + case GL_FLOAT: + return HLSLAttribType::FLOAT; + default: + UNREACHABLE(); + return HLSLAttribType::FLOAT; + } +} + // static void ProgramD3D::VertexExecutable::getSignature(RendererD3D *renderer, const gl::InputLayout &inputLayout, Signature *signatureOut) { - signatureOut->resize(inputLayout.size()); + signatureOut->assign(inputLayout.size(), HLSLAttribType::FLOAT); for (size_t index = 0; index < inputLayout.size(); ++index) { gl::VertexFormatType vertexFormatType = inputLayout[index]; - bool converted = false; - if (vertexFormatType != gl::VERTEX_FORMAT_INVALID) - { - VertexConversionType conversionType = - renderer->getVertexConversionType(vertexFormatType); - converted = ((conversionType & VERTEX_CONVERT_GPU) != 0); - } + if (vertexFormatType == gl::VERTEX_FORMAT_INVALID) + continue; + + VertexConversionType conversionType = renderer->getVertexConversionType(vertexFormatType); + if ((conversionType & VERTEX_CONVERT_GPU) == 0) + continue; - (*signatureOut)[index] = converted; + GLenum componentType = renderer->getVertexComponentType(vertexFormatType); + (*signatureOut)[index] = GetAttribType(componentType); } } @@ -535,9 +567,9 @@ bool ProgramD3D::VertexExecutable::matchesSignature(const Signature &signature) 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; + // treat undefined indexes as FLOAT + auto a = index < signature.size() ? signature[index] : HLSLAttribType::FLOAT; + auto b = index < mSignature.size() ? mSignature[index] : HLSLAttribType::FLOAT; if (a != b) return false; } @@ -562,19 +594,25 @@ ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureTy unsigned int ProgramD3D::mCurrentSerial = 1; -ProgramD3D::ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer) - : ProgramImpl(data), +ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer) + : ProgramImpl(state), mRenderer(renderer), - mDynamicHLSL(NULL), - mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX, nullptr), + mDynamicHLSL(nullptr), + mGeometryExecutables(gl::PRIMITIVE_TYPE_MAX), + mComputeExecutable(nullptr), mUsesPointSize(false), mUsesFlatInterpolation(false), - mVertexUniformStorage(NULL), - mFragmentUniformStorage(NULL), + mVertexUniformStorage(nullptr), + mFragmentUniformStorage(nullptr), + mComputeUniformStorage(nullptr), mUsedVertexSamplerRange(0), mUsedPixelSamplerRange(0), + mUsedComputeSamplerRange(0), mDirtySamplerMapping(true), - mSerial(issueSerial()) + mSerial(issueSerial()), + mVertexUniformsDirty(true), + mFragmentUniformsDirty(true), + mComputeUniformsDirty(true) { mDynamicHLSL = new DynamicHLSL(renderer); } @@ -590,14 +628,22 @@ bool ProgramD3D::usesPointSpriteEmulation() const return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; } +bool ProgramD3D::usesGeometryShaderForPointSpriteEmulation() const +{ + return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); +} + bool ProgramD3D::usesGeometryShader(GLenum drawMode) const { + if (mHasANGLEMultiviewEnabled && !mRenderer->canSelectViewInVertexShader()) + { + return true; + } if (drawMode != GL_POINTS) { return mUsesFlatInterpolation; } - - return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); + return usesGeometryShaderForPointSpriteEmulation(); } bool ProgramD3D::usesInstancedPointSpriteEmulation() const @@ -627,6 +673,13 @@ GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; } break; + case gl::SAMPLER_COMPUTE: + ASSERT(samplerIndex < caps.maxComputeTextureImageUnits); + if (samplerIndex < mSamplersCS.size() && mSamplersCS[samplerIndex].active) + { + logicalTextureUnit = mSamplersCS[samplerIndex].logicalTextureUnit; + } + break; default: UNREACHABLE(); } @@ -654,6 +707,10 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp ASSERT(samplerIndex < mSamplersVS.size()); ASSERT(mSamplersVS[samplerIndex].active); return mSamplersVS[samplerIndex].textureType; + case gl::SAMPLER_COMPUTE: + ASSERT(samplerIndex < mSamplersCS.size()); + ASSERT(mSamplersCS[samplerIndex].active); + return mSamplersCS[samplerIndex].textureType; default: UNREACHABLE(); } @@ -661,7 +718,7 @@ GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samp return GL_TEXTURE_2D; } -GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const +GLuint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const { switch (type) { @@ -669,17 +726,19 @@ GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const return mUsedPixelSamplerRange; case gl::SAMPLER_VERTEX: return mUsedVertexSamplerRange; + case gl::SAMPLER_COMPUTE: + return mUsedComputeSamplerRange; default: UNREACHABLE(); - return 0; + return 0u; } } -void ProgramD3D::updateSamplerMapping() +ProgramD3D::SamplerMapping ProgramD3D::updateSamplerMapping() { if (!mDirtySamplerMapping) { - return; + return SamplerMapping::WasClean; } mDirtySamplerMapping = false; @@ -687,14 +746,10 @@ void ProgramD3D::updateSamplerMapping() // Retrieve sampler uniform values for (const D3DUniform *d3dUniform : mD3DUniforms) { - if (!d3dUniform->dirty) - continue; - if (!d3dUniform->isSampler()) continue; - int count = d3dUniform->elementCount(); - const GLint(*v)[4] = reinterpret_cast(d3dUniform->data); + int count = d3dUniform->getArraySizeProduct(); if (d3dUniform->isReferencedByFragmentShader()) { @@ -707,7 +762,7 @@ void ProgramD3D::updateSamplerMapping() if (samplerIndex < mSamplersPS.size()) { ASSERT(mSamplersPS[samplerIndex].active); - mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; + mSamplersPS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; } } } @@ -723,15 +778,37 @@ void ProgramD3D::updateSamplerMapping() if (samplerIndex < mSamplersVS.size()) { ASSERT(mSamplersVS[samplerIndex].active); - mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; + mSamplersVS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; + } + } + } + + if (d3dUniform->isReferencedByComputeShader()) + { + unsigned int firstIndex = d3dUniform->csRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersCS.size()) + { + ASSERT(mSamplersCS[samplerIndex].active); + mSamplersCS[samplerIndex].logicalTextureUnit = d3dUniform->mSamplerData[i]; } } } } + + return SamplerMapping::WasDirty; } -LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +gl::LinkResult ProgramD3D::load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) { + // TODO(jmadill): Use Renderer from contextImpl. + reset(); DeviceIdentifier binaryDeviceIdentifier = {0}; @@ -742,20 +819,19 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0) { infoLog << "Invalid program binary, device configuration has changed."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } int compileFlags = stream->readInt(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { infoLog << "Mismatched compilation flags."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } - // TODO(jmadill): replace MAX_VERTEX_ATTRIBS - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + for (int &index : mAttribLocationToD3DSemantic) { - stream->readInt(&mSemanticIndexes[i]); + stream->readInt(&index); } const unsigned int psSamplerCount = stream->readInt(); @@ -777,27 +853,39 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) mSamplersVS.push_back(sampler); } + const unsigned int csSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < csSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersCS.push_back(sampler); + } + stream->readInt(&mUsedVertexSamplerRange); stream->readInt(&mUsedPixelSamplerRange); + stream->readInt(&mUsedComputeSamplerRange); const unsigned int uniformCount = stream->readInt(); if (stream->error()) { infoLog << "Invalid program binary."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } - const auto &linkedUniforms = mData.getUniforms(); + const auto &linkedUniforms = mState.getUniforms(); ASSERT(mD3DUniforms.empty()); for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex]; D3DUniform *d3dUniform = - new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySize, + new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySizes, linkedUniform.isInDefaultBlock()); stream->readInt(&d3dUniform->psRegisterIndex); stream->readInt(&d3dUniform->vsRegisterIndex); + stream->readInt(&d3dUniform->csRegisterIndex); stream->readInt(&d3dUniform->registerCount); stream->readInt(&d3dUniform->registerElement); @@ -808,7 +896,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) if (stream->error()) { infoLog << "Invalid program binary."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } ASSERT(mD3DUniformBlocks.empty()); @@ -817,6 +905,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) D3DUniformBlock uniformBlock; stream->readInt(&uniformBlock.psRegisterIndex); stream->readInt(&uniformBlock.vsRegisterIndex); + stream->readInt(&uniformBlock.csRegisterIndex); mD3DUniformBlocks.push_back(uniformBlock); } @@ -834,11 +923,13 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->readString(&mVertexHLSL); stream->readBytes(reinterpret_cast(&mVertexWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->readString(&mPixelHLSL); stream->readBytes(reinterpret_cast(&mPixelWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->readBool(&mUsesFragDepth); + stream->readBool(&mHasANGLEMultiviewEnabled); + stream->readBool(&mUsesViewID); stream->readBool(&mUsesPointSize); stream->readBool(&mUsesFlatInterpolation); @@ -857,6 +948,8 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) const unsigned char *binary = reinterpret_cast(stream->data()); + bool separateAttribs = (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS); + const unsigned int vertexShaderCount = stream->readInt(); for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) @@ -874,18 +967,14 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) 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); - } + ANGLE_TRY(mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + gl::SHADER_VERTEX, mStreamOutVaryings, separateAttribs, + &shaderExecutable)); if (!shaderExecutable) { infoLog << "Could not create vertex shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } // generated converted input layout @@ -893,8 +982,8 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) VertexExecutable::getSignature(mRenderer, inputLayout, &signature); // add new binary - mVertexExecutables.push_back( - new VertexExecutable(inputLayout, signature, shaderExecutable)); + mVertexExecutables.push_back(std::unique_ptr( + new VertexExecutable(inputLayout, signature, shaderExecutable))); stream->skip(vertexShaderSize); } @@ -913,22 +1002,19 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) const unsigned char *pixelShaderFunction = binary + stream->offset(); 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); - } + ANGLE_TRY(mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, + gl::SHADER_FRAGMENT, mStreamOutVaryings, + separateAttribs, &shaderExecutable)); if (!shaderExecutable) { infoLog << "Could not create pixel shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } // add new binary - mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); + mPixelExecutables.push_back( + std::unique_ptr(new PixelExecutable(outputs, shaderExecutable))); stream->skip(pixelShaderSize); } @@ -939,36 +1025,52 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) unsigned int geometryShaderSize = stream->readInt(); if (geometryShaderSize == 0) { - mGeometryExecutables[geometryExeIndex] = nullptr; continue; } const unsigned char *geometryShaderFunction = binary + stream->offset(); - 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); - } + ShaderExecutableD3D *geometryExecutable = nullptr; + ANGLE_TRY(mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, + gl::SHADER_GEOMETRY, mStreamOutVaryings, + separateAttribs, &geometryExecutable)); - if (!mGeometryExecutables[geometryExeIndex]) + if (!geometryExecutable) { infoLog << "Could not create geometry shader."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + return false; } + + mGeometryExecutables[geometryExeIndex].reset(geometryExecutable); + stream->skip(geometryShaderSize); } + unsigned int computeShaderSize = stream->readInt(); + if (computeShaderSize > 0) + { + const unsigned char *computeShaderFunction = binary + stream->offset(); + + ShaderExecutableD3D *computeExecutable = nullptr; + ANGLE_TRY(mRenderer->loadExecutable(computeShaderFunction, computeShaderSize, + gl::SHADER_COMPUTE, std::vector(), false, + &computeExecutable)); + + if (!computeExecutable) + { + infoLog << "Could not create compute shader."; + return false; + } + + mComputeExecutable.reset(computeExecutable); + } + initializeUniformStorage(); - initAttributesByLayout(); - return LinkResult(true, gl::Error(GL_NO_ERROR)); + return true; } -gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) +void ProgramD3D::save(const gl::Context *context, 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 @@ -979,10 +1081,9 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - // TODO(jmadill): replace MAX_VERTEX_ATTRIBS - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + for (int d3dSemantic : mAttribLocationToD3DSemantic) { - stream->writeInt(mSemanticIndexes[i]); + stream->writeInt(d3dSemantic); } stream->writeInt(mSamplersPS.size()); @@ -1001,15 +1102,25 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(mSamplersVS[i].textureType); } + stream->writeInt(mSamplersCS.size()); + for (unsigned int i = 0; i < mSamplersCS.size(); ++i) + { + stream->writeInt(mSamplersCS[i].active); + stream->writeInt(mSamplersCS[i].logicalTextureUnit); + stream->writeInt(mSamplersCS[i].textureType); + } + stream->writeInt(mUsedVertexSamplerRange); stream->writeInt(mUsedPixelSamplerRange); + stream->writeInt(mUsedComputeSamplerRange); stream->writeInt(mD3DUniforms.size()); for (const D3DUniform *uniform : mD3DUniforms) { // Type, name and arraySize are redundant, so aren't stored in the binary. - stream->writeInt(uniform->psRegisterIndex); - stream->writeInt(uniform->vsRegisterIndex); + stream->writeIntOrNegOne(uniform->psRegisterIndex); + stream->writeIntOrNegOne(uniform->vsRegisterIndex); + stream->writeIntOrNegOne(uniform->csRegisterIndex); stream->writeInt(uniform->registerCount); stream->writeInt(uniform->registerElement); } @@ -1017,8 +1128,9 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeInt(mD3DUniformBlocks.size()); for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks) { - stream->writeInt(uniformBlock.psRegisterIndex); - stream->writeInt(uniformBlock.vsRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.psRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.vsRegisterIndex); + stream->writeIntOrNegOne(uniformBlock.csRegisterIndex); } stream->writeInt(mStreamOutVaryings.size()); @@ -1032,11 +1144,13 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeString(mVertexHLSL); stream->writeBytes(reinterpret_cast(&mVertexWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->writeString(mPixelHLSL); stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), - sizeof(D3DCompilerWorkarounds)); + sizeof(angle::CompilerWorkaroundsD3D)); stream->writeInt(mUsesFragDepth); + stream->writeInt(mHasANGLEMultiviewEnabled); + stream->writeInt(mUsesViewID); stream->writeInt(mUsesPointSize); stream->writeInt(mUsesFlatInterpolation); @@ -1058,14 +1172,14 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) { - VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex].get(); const auto &inputLayout = vertexExecutable->inputs(); stream->writeInt(inputLayout.size()); for (size_t inputIndex = 0; inputIndex < inputLayout.size(); inputIndex++) { - stream->writeInt(inputLayout[inputIndex]); + stream->writeInt(static_cast(inputLayout[inputIndex])); } size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); @@ -1079,7 +1193,7 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) { - PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex].get(); const std::vector outputs = pixelExecutable->outputSignature(); stream->writeInt(outputs.size()); @@ -1095,150 +1209,120 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) stream->writeBytes(pixelBlob, pixelShaderSize); } - for (const ShaderExecutableD3D *geometryExe : mGeometryExecutables) + for (auto const &geometryExecutable : mGeometryExecutables) { - if (geometryExe == nullptr) + if (!geometryExecutable) { stream->writeInt(0); continue; } - size_t geometryShaderSize = geometryExe->getLength(); + size_t geometryShaderSize = geometryExecutable->getLength(); stream->writeInt(geometryShaderSize); - stream->writeBytes(geometryExe->getFunction(), geometryShaderSize); + stream->writeBytes(geometryExecutable->getFunction(), geometryShaderSize); } - return gl::Error(GL_NO_ERROR); + if (mComputeExecutable) + { + size_t computeShaderSize = mComputeExecutable->getLength(); + stream->writeInt(computeShaderSize); + stream->writeBytes(mComputeExecutable->getFunction(), computeShaderSize); + } + else + { + stream->writeInt(0); + } } void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) { } -gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, - ShaderExecutableD3D **outExecutable) +void ProgramD3D::setSeparable(bool /* separable */) { - mPixelShaderOutputFormatCache.clear(); - - const FramebufferD3D *fboD3D = GetImplAs(fbo); - const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(); - - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) - { - mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK - ? GL_COLOR_ATTACHMENT0 - : colorbuffer->getBinding()); - } - else - { - mPixelShaderOutputFormatCache.push_back(GL_NONE); - } - } - - return getPixelExecutableForOutputLayout(mPixelShaderOutputFormatCache, outExecutable, nullptr); } -gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector &outputSignature, - ShaderExecutableD3D **outExectuable, - gl::InfoLog *infoLog) +gl::Error ProgramD3D::getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExecutable, + gl::InfoLog *infoLog) { - for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + if (mCachedPixelExecutableIndex.valid()) { - if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) - { - *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } + *outExecutable = mPixelExecutables[mCachedPixelExecutableIndex.value()]->shaderExecutable(); + return gl::NoError(); } std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature( - mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature); + mPixelHLSL, mPixelShaderKey, mUsesFragDepth, mPixelShaderOutputLayoutCache); // Generate new pixel executable - ShaderExecutableD3D *pixelExecutable = NULL; + ShaderExecutableD3D *pixelExecutable = nullptr; gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable( - *currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds, - &pixelExecutable); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->compileToExecutable( + *currentInfoLog, finalPixelHLSL, gl::SHADER_FRAGMENT, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds, + &pixelExecutable)); if (pixelExecutable) { - mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + mPixelExecutables.push_back(std::unique_ptr( + new PixelExecutable(mPixelShaderOutputLayoutCache, pixelExecutable))); + mCachedPixelExecutableIndex = mPixelExecutables.size() - 1; } else if (!infoLog) { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(static_cast(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + ERR() << "Error compiling dynamic pixel executable:" << std::endl + << tempInfoLog.str() << std::endl; } - *outExectuable = pixelExecutable; - return gl::Error(GL_NO_ERROR); + *outExecutable = pixelExecutable; + return gl::NoError(); } -gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout, - ShaderExecutableD3D **outExectuable, - gl::InfoLog *infoLog) +gl::Error ProgramD3D::getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) { - VertexExecutable::getSignature(mRenderer, inputLayout, &mCachedVertexSignature); - - for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + if (mCachedVertexExecutableIndex.valid()) { - if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) - { - *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } + *outExectuable = + mVertexExecutables[mCachedVertexExecutableIndex.value()]->shaderExecutable(); + return gl::NoError(); } // Generate new dynamic layout with attribute conversions std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout( - mVertexHLSL, inputLayout, mData.getAttributes()); + mVertexHLSL, mCachedInputLayout, mState.getAttributes()); // Generate new vertex executable - ShaderExecutableD3D *vertexExecutable = NULL; + ShaderExecutableD3D *vertexExecutable = nullptr; gl::InfoLog tempInfoLog; gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; - gl::Error error = mRenderer->compileToExecutable( - *currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mStreamOutVaryings, - (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds, - &vertexExecutable); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->compileToExecutable( + *currentInfoLog, finalVertexHLSL, gl::SHADER_VERTEX, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds, + &vertexExecutable)); if (vertexExecutable) { - mVertexExecutables.push_back( - new VertexExecutable(inputLayout, mCachedVertexSignature, vertexExecutable)); + mVertexExecutables.push_back(std::unique_ptr( + new VertexExecutable(mCachedInputLayout, mCachedVertexSignature, vertexExecutable))); + mCachedVertexExecutableIndex = mVertexExecutables.size() - 1; } else if (!infoLog) { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(static_cast(tempInfoLog.getLength()), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + ERR() << "Error compiling dynamic vertex executable:" << std::endl + << tempInfoLog.str() << std::endl; } *outExectuable = vertexExecutable; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data, +gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Context *context, GLenum drawMode, ShaderExecutableD3D **outExecutable, gl::InfoLog *infoLog) @@ -1251,75 +1335,188 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data // Return a null shader if the current rendering doesn't use a geometry shader if (!usesGeometryShader(drawMode)) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); - if (mGeometryExecutables[geometryShaderType] != nullptr) + if (mGeometryExecutables[geometryShaderType]) { if (outExecutable) { - *outExecutable = mGeometryExecutables[geometryShaderType]; + *outExecutable = mGeometryExecutables[geometryShaderType].get(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL( - geometryShaderType, data, mData, mRenderer->presentPathFastEnabled(), - mGeometryShaderPreamble); + context, geometryShaderType, mState, mRenderer->presentPathFastEnabled(), + mHasANGLEMultiviewEnabled, mRenderer->canSelectViewInVertexShader(), + usesGeometryShaderForPointSpriteEmulation(), 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]); + ShaderExecutableD3D *geometryExecutable = nullptr; + gl::Error error = mRenderer->compileToExecutable( + *currentInfoLog, geometryHLSL, gl::SHADER_GEOMETRY, mStreamOutVaryings, + (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), + angle::CompilerWorkaroundsD3D(), &geometryExecutable); 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]); + ERR() << "Error compiling dynamic geometry executable:" << std::endl + << tempInfoLog.str() << std::endl; + } + + if (geometryExecutable != nullptr) + { + mGeometryExecutables[geometryShaderType].reset(geometryExecutable); } if (outExecutable) { - *outExecutable = mGeometryExecutables[geometryShaderType]; + *outExecutable = mGeometryExecutables[geometryShaderType].get(); } return error; } -LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog) +class ProgramD3D::GetExecutableTask : public Closure +{ + public: + GetExecutableTask(ProgramD3D *program) + : mProgram(program), mError(gl::NoError()), mInfoLog(), mResult(nullptr) + { + } + + virtual gl::Error run() = 0; + + void operator()() override { mError = run(); } + + const gl::Error &getError() const { return mError; } + const gl::InfoLog &getInfoLog() const { return mInfoLog; } + ShaderExecutableD3D *getResult() { return mResult; } + + protected: + ProgramD3D *mProgram; + gl::Error mError; + gl::InfoLog mInfoLog; + ShaderExecutableD3D *mResult; +}; + +class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask +{ + public: + GetVertexExecutableTask(ProgramD3D *program, const gl::Context *context) + : GetExecutableTask(program), mContext(context) + { + } + gl::Error run() override + { + mProgram->updateCachedInputLayoutFromShader(mContext); + + ANGLE_TRY(mProgram->getVertexExecutableForCachedInputLayout(&mResult, &mInfoLog)); + + return gl::NoError(); + } + + private: + const gl::Context *mContext; +}; + +void ProgramD3D::updateCachedInputLayoutFromShader(const gl::Context *context) +{ + GetDefaultInputLayoutFromShader(context, mState.getAttachedVertexShader(), &mCachedInputLayout); + VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature); + updateCachedVertexExecutableIndex(); +} + +class ProgramD3D::GetPixelExecutableTask : public ProgramD3D::GetExecutableTask { - const gl::InputLayout &defaultInputLayout = - GetDefaultInputLayoutFromShader(mData.getAttachedVertexShader()); - ShaderExecutableD3D *defaultVertexExecutable = NULL; - gl::Error error = - getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); - if (error.isError()) + public: + GetPixelExecutableTask(ProgramD3D *program) : GetExecutableTask(program) {} + gl::Error run() override { - return LinkResult(false, error); + mProgram->updateCachedOutputLayoutFromShader(); + + ANGLE_TRY(mProgram->getPixelExecutableForCachedOutputLayout(&mResult, &mInfoLog)); + + return gl::NoError(); } +}; + +void ProgramD3D::updateCachedOutputLayoutFromShader() +{ + GetDefaultOutputLayoutFromShader(mPixelShaderKey, &mPixelShaderOutputLayoutCache); + updateCachedPixelExecutableIndex(); +} - std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); - ShaderExecutableD3D *defaultPixelExecutable = NULL; - error = - getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); - if (error.isError()) +class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTask +{ + public: + GetGeometryExecutableTask(ProgramD3D *program, const gl::Context *context) + : GetExecutableTask(program), mContext(context) { - return LinkResult(false, error); } - // Auto-generate the geometry shader here, if we expect to be using point rendering in D3D11. - ShaderExecutableD3D *pointGS = nullptr; - if (usesGeometryShader(GL_POINTS)) + gl::Error run() override { - getGeometryExecutableForPrimitiveType(data, GL_POINTS, &pointGS, &infoLog); + // Auto-generate the geometry shader here, if we expect to be using point rendering in + // D3D11. + if (mProgram->usesGeometryShader(GL_POINTS)) + { + ANGLE_TRY(mProgram->getGeometryExecutableForPrimitiveType(mContext, GL_POINTS, &mResult, + &mInfoLog)); + } + + return gl::NoError(); } - const ShaderD3D *vertexShaderD3D = GetImplAs(mData.getAttachedVertexShader()); + private: + const gl::Context *mContext; +}; + +gl::Error ProgramD3D::getComputeExecutable(ShaderExecutableD3D **outExecutable) +{ + if (outExecutable) + { + *outExecutable = mComputeExecutable.get(); + } + + return gl::NoError(); +} + +gl::LinkResult ProgramD3D::compileProgramExecutables(const gl::Context *context, + gl::InfoLog &infoLog) +{ + // Ensure the compiler is initialized to avoid race conditions. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); + + WorkerThreadPool *workerPool = mRenderer->getWorkerThreadPool(); + + GetVertexExecutableTask vertexTask(this, context); + GetPixelExecutableTask pixelTask(this); + GetGeometryExecutableTask geometryTask(this, context); + + std::array waitEvents = {{workerPool->postWorkerTask(&vertexTask), + workerPool->postWorkerTask(&pixelTask), + workerPool->postWorkerTask(&geometryTask)}}; + + WaitableEvent::WaitMany(&waitEvents); + + infoLog << vertexTask.getInfoLog().str(); + infoLog << pixelTask.getInfoLog().str(); + infoLog << geometryTask.getInfoLog().str(); + + ANGLE_TRY(vertexTask.getError()); + ANGLE_TRY(pixelTask.getError()); + ANGLE_TRY(geometryTask.getError()); + + ShaderExecutableD3D *defaultVertexExecutable = vertexTask.getResult(); + ShaderExecutableD3D *defaultPixelExecutable = pixelTask.getResult(); + ShaderExecutableD3D *pointGS = geometryTask.getResult(); + + const ShaderD3D *vertexShaderD3D = GetImplAs(mState.getAttachedVertexShader()); if (usesGeometryShader(GL_POINTS) && pointGS) { @@ -1339,128 +1536,148 @@ LinkResult ProgramD3D::compileProgramExecutables(const gl::Data &data, gl::InfoL if (defaultPixelExecutable) { const ShaderD3D *fragmentShaderD3D = - GetImplAs(mData.getAttachedFragmentShader()); + GetImplAs(mState.getAttachedFragmentShader()); fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); } - bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && - (!usesGeometryShader(GL_POINTS) || pointGS)); - return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); + return (defaultVertexExecutable && defaultPixelExecutable && + (!usesGeometryShader(GL_POINTS) || pointGS)); } -LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog) +gl::LinkResult ProgramD3D::compileComputeExecutable(const gl::Context *context, + gl::InfoLog &infoLog) { - reset(); + // Ensure the compiler is initialized to avoid race conditions. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); - // TODO(jmadill): structures containing samplers - for (const gl::LinkedUniform &linkedUniform : mData.getUniforms()) + std::string computeShader = mDynamicHLSL->generateComputeShaderLinkHLSL(context, mState); + + ShaderExecutableD3D *computeExecutable = nullptr; + ANGLE_TRY(mRenderer->compileToExecutable(infoLog, computeShader, gl::SHADER_COMPUTE, + std::vector(), false, + angle::CompilerWorkaroundsD3D(), &computeExecutable)); + + if (computeExecutable == nullptr) { - if (linkedUniform.isSampler() && linkedUniform.isField()) - { - infoLog << "Structures containing samplers not currently supported in D3D."; - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + ERR() << "Error compiling dynamic compute executable:" << std::endl + << infoLog.str() << std::endl; + } + else + { + const ShaderD3D *computeShaderD3D = GetImplAs(mState.getAttachedComputeShader()); + computeShaderD3D->appendDebugInfo(computeExecutable->getDebugInfo()); + mComputeExecutable.reset(computeExecutable); } - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - - const ShaderD3D *vertexShaderD3D = GetImplAs(vertexShader); - const ShaderD3D *fragmentShaderD3D = GetImplAs(fragmentShader); + return mComputeExecutable.get() != nullptr; +} - mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); - mSamplersPS.resize(data.caps->maxTextureImageUnits); +gl::LinkResult ProgramD3D::link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + gl::InfoLog &infoLog) +{ + const auto &data = context->getContextState(); - vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); - fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + reset(); - if (mRenderer->getRendererLimitations().noFrontFacingSupport) + gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) { - if (fragmentShaderD3D->usesFrontFacing()) + mSamplersCS.resize(data.getCaps().maxComputeTextureImageUnits); + + defineUniformsAndAssignRegisters(context); + + gl::LinkResult result = compileComputeExecutable(context, infoLog); + if (result.isError()) + { + infoLog << result.getError().getMessage(); + return result; + } + else if (!result.getResult()) { - infoLog << "The current renderer doesn't support gl_FrontFacing"; - return LinkResult(false, gl::Error(GL_NO_ERROR)); + infoLog << "Failed to create D3D compute shader."; + return result; } } + else + { + gl::Shader *vertexShader = mState.getAttachedVertexShader(); + gl::Shader *fragmentShader = mState.getAttachedFragmentShader(); - std::vector packedVaryings = - MergeVaryings(*vertexShader, *fragmentShader, mData.getTransformFeedbackVaryingNames()); + const ShaderD3D *vertexShaderD3D = GetImplAs(vertexShader); + const ShaderD3D *fragmentShaderD3D = GetImplAs(fragmentShader); - // Map the varyings to the register file - VaryingPacking varyingPacking(data.caps->maxVaryingVectors); - if (!varyingPacking.packVaryings(infoLog, packedVaryings, - mData.getTransformFeedbackVaryingNames())) - { - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + mSamplersVS.resize(data.getCaps().maxVertexTextureImageUnits); + mSamplersPS.resize(data.getCaps().maxTextureImageUnits); - ProgramD3DMetadata metadata(mRenderer->getMajorShaderModel(), mRenderer->getShaderModelSuffix(), - usesInstancedPointSpriteEmulation(), - mRenderer->presentPathFastEnabled(), vertexShaderD3D, - fragmentShaderD3D); + vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); + fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); - varyingPacking.enableBuiltins(SHADER_VERTEX, metadata); - varyingPacking.enableBuiltins(SHADER_PIXEL, metadata); + if (mRenderer->getNativeLimitations().noFrontFacingSupport) + { + if (fragmentShaderD3D->usesFrontFacing()) + { + infoLog << "The current renderer doesn't support gl_FrontFacing"; + return false; + } + } - 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)); - } + // 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 && + resources.varyingPacking.getMaxSemanticIndex() > data.getCaps().maxVaryingVectors) + { + infoLog << "Cannot pack these varyings on D3D9."; + return false; + } - // 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)); - } + ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D); + BuiltinVaryingsD3D builtins(metadata, resources.varyingPacking); - if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, varyingPacking, &mPixelHLSL, - &mVertexHLSL)) - { - return LinkResult(false, gl::Error(GL_NO_ERROR)); - } + mDynamicHLSL->generateShaderLinkHLSL(context, mState, metadata, resources.varyingPacking, + builtins, &mPixelHLSL, &mVertexHLSL); - mUsesPointSize = vertexShaderD3D->usesPointSize(); - mDynamicHLSL->getPixelShaderOutputKey(data, mData, metadata, &mPixelShaderKey); - mUsesFragDepth = metadata.usesFragDepth(mData); + mUsesPointSize = vertexShaderD3D->usesPointSize(); + mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey); + mUsesFragDepth = metadata.usesFragDepth(); + mUsesViewID = metadata.usesViewID(); + mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled(); - // Cache if we use flat shading - mUsesFlatInterpolation = false; - for (const auto &varying : packedVaryings) - { - if (varying.interpolation == sh::INTERPOLATION_FLAT) + // Cache if we use flat shading + mUsesFlatInterpolation = + (FindFlatInterpolationVarying(fragmentShader->getInputVaryings(context)) || + FindFlatInterpolationVarying(vertexShader->getOutputVaryings(context))); + + if (mRenderer->getMajorShaderModel() >= 4) { - mUsesFlatInterpolation = true; - break; + mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble( + resources.varyingPacking, builtins, mHasANGLEMultiviewEnabled, + metadata.canSelectViewInVertexShader()); } - } - if (mRenderer->getMajorShaderModel() >= 4) - { - varyingPacking.enableBuiltins(SHADER_GEOMETRY, metadata); - mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking); - } - - initSemanticIndex(); + initAttribLocationsToD3DSemantic(context); - defineUniformsAndAssignRegisters(); + defineUniformsAndAssignRegisters(context); - gatherTransformFeedbackVaryings(varyingPacking); + gatherTransformFeedbackVaryings(resources.varyingPacking, builtins[gl::SHADER_VERTEX]); - LinkResult result = compileProgramExecutables(data, infoLog); - if (result.error.isError() || !result.linkSuccess) - { - infoLog << "Failed to create D3D shaders."; - return result; + gl::LinkResult result = compileProgramExecutables(context, infoLog); + if (result.isError()) + { + infoLog << result.getError().getMessage(); + return result; + } + else if (!result.getResult()) + { + infoLog << "Failed to create D3D shaders."; + return result; + } } - initUniformBlockInfo(); + linkResources(context, resources); - return LinkResult(true, gl::Error(GL_NO_ERROR)); + return true; } GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/) @@ -1469,46 +1686,22 @@ GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLo return GL_TRUE; } -void ProgramD3D::initUniformBlockInfo() +void ProgramD3D::initializeUniformBlocks() { - 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 (mState.getUniformBlocks().empty()) { - 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; + return; } -} -void ProgramD3D::assignUniformBlockRegisters() -{ - mD3DUniformBlocks.clear(); + ASSERT(mD3DUniformBlocks.empty()); // Assign registers and update sizes. - const ShaderD3D *vertexShaderD3D = GetImplAs(mData.getAttachedVertexShader()); - const ShaderD3D *fragmentShaderD3D = GetImplAs(mData.getAttachedFragmentShader()); + const ShaderD3D *vertexShaderD3D = SafeGetImplAs(mState.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = + SafeGetImplAs(mState.getAttachedFragmentShader()); + const ShaderD3D *computeShaderD3D = SafeGetImplAs(mState.getAttachedComputeShader()); - for (const gl::UniformBlock &uniformBlock : mData.getUniformBlocks()) + for (const gl::InterfaceBlock &uniformBlock : mState.getUniformBlocks()) { unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0; @@ -1516,18 +1709,27 @@ void ProgramD3D::assignUniformBlockRegisters() if (uniformBlock.vertexStaticUse) { - unsigned int baseRegister = - vertexShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + ASSERT(vertexShaderD3D != nullptr); + unsigned int baseRegister = vertexShaderD3D->getUniformBlockRegister(uniformBlock.name); d3dUniformBlock.vsRegisterIndex = baseRegister + uniformBlockElement; } if (uniformBlock.fragmentStaticUse) { + ASSERT(fragmentShaderD3D != nullptr); unsigned int baseRegister = - fragmentShaderD3D->getInterfaceBlockRegister(uniformBlock.name); + fragmentShaderD3D->getUniformBlockRegister(uniformBlock.name); d3dUniformBlock.psRegisterIndex = baseRegister + uniformBlockElement; } + if (uniformBlock.computeStaticUse) + { + ASSERT(computeShaderD3D != nullptr); + unsigned int baseRegister = + computeShaderD3D->getUniformBlockRegister(uniformBlock.name); + d3dUniformBlock.csRegisterIndex = baseRegister + uniformBlockElement; + } + mD3DUniformBlocks.push_back(d3dUniformBlock); } } @@ -1537,6 +1739,7 @@ void ProgramD3D::initializeUniformStorage() // Compute total default block size unsigned int vertexRegisters = 0; unsigned int fragmentRegisters = 0; + unsigned int computeRegisters = 0; for (const D3DUniform *d3dUniform : mD3DUniforms) { if (!d3dUniform->isSampler()) @@ -1551,55 +1754,67 @@ void ProgramD3D::initializeUniformStorage() fragmentRegisters = std::max( fragmentRegisters, d3dUniform->psRegisterIndex + d3dUniform->registerCount); } + if (d3dUniform->isReferencedByComputeShader()) + { + computeRegisters = std::max( + computeRegisters, d3dUniform->csRegisterIndex + d3dUniform->registerCount); + } } } - mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); - mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); -} - -gl::Error ProgramD3D::applyUniforms(GLenum drawMode) -{ - ASSERT(!mDirtySamplerMapping); - - gl::Error error = mRenderer->applyUniforms(*this, drawMode, mD3DUniforms); - if (error.isError()) - { - return error; - } + mVertexUniformStorage = + std::unique_ptr(mRenderer->createUniformStorage(vertexRegisters * 16u)); + mFragmentUniformStorage = std::unique_ptr( + mRenderer->createUniformStorage(fragmentRegisters * 16u)); + mComputeUniformStorage = + std::unique_ptr(mRenderer->createUniformStorage(computeRegisters * 16u)); + // Iterate the uniforms again to assign data pointers to default block uniforms. for (D3DUniform *d3dUniform : mD3DUniforms) { - d3dUniform->dirty = false; - } + if (d3dUniform->isSampler()) + { + d3dUniform->mSamplerData.resize(d3dUniform->getArraySizeProduct(), 0); + continue; + } - return gl::Error(GL_NO_ERROR); -} + if (d3dUniform->isReferencedByVertexShader()) + { + d3dUniform->vsData = mVertexUniformStorage->getDataPointer(d3dUniform->vsRegisterIndex, + d3dUniform->registerElement); + } -gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) -{ - if (mData.getUniformBlocks().empty()) - { - return gl::Error(GL_NO_ERROR); + if (d3dUniform->isReferencedByFragmentShader()) + { + d3dUniform->psData = mFragmentUniformStorage->getDataPointer( + d3dUniform->psRegisterIndex, d3dUniform->registerElement); + } + + if (d3dUniform->isReferencedByComputeShader()) + { + d3dUniform->csData = mComputeUniformStorage->getDataPointer( + d3dUniform->csRegisterIndex, d3dUniform->registerElement); + } } +} - // Lazy init. - if (mD3DUniformBlocks.empty()) +void ProgramD3D::updateUniformBufferCache(const gl::Caps &caps, + unsigned int reservedVertex, + unsigned int reservedFragment) +{ + if (mState.getUniformBlocks().empty()) { - assignUniformBlockRegisters(); + return; } mVertexUBOCache.clear(); mFragmentUBOCache.clear(); - const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); - const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size(); uniformBlockIndex++) { const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex]; - GLuint blockBinding = mData.getUniformBlockBinding(uniformBlockIndex); + GLuint blockBinding = mState.getUniformBlockBinding(uniformBlockIndex); // Unnecessary to apply an unreferenced standard or shared UBO if (!uniformBlock.vertexStaticUse() && !uniformBlock.fragmentStaticUse()) @@ -1609,8 +1824,8 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) if (uniformBlock.vertexStaticUse()) { - unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedBuffersInVS; - ASSERT(registerIndex < data.caps->maxVertexUniformBlocks); + unsigned int registerIndex = uniformBlock.vsRegisterIndex - reservedVertex; + ASSERT(registerIndex < caps.maxVertexUniformBlocks); if (mVertexUBOCache.size() <= registerIndex) { @@ -1623,8 +1838,8 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) if (uniformBlock.fragmentStaticUse()) { - unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedBuffersInFS; - ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks); + unsigned int registerIndex = uniformBlock.psRegisterIndex - reservedFragment; + ASSERT(registerIndex < caps.maxFragmentUniformBlocks); if (mFragmentUBOCache.size() <= registerIndex) { @@ -1635,36 +1850,50 @@ gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data) mFragmentUBOCache[registerIndex] = blockBinding; } } +} + +const std::vector &ProgramD3D::getVertexUniformBufferCache() const +{ + return mVertexUBOCache; +} - return mRenderer->setUniformBuffers(data, mVertexUBOCache, mFragmentUBOCache); +const std::vector &ProgramD3D::getFragmentUniformBufferCache() const +{ + return mFragmentUBOCache; } void ProgramD3D::dirtyAllUniforms() { - for (D3DUniform *d3dUniform : mD3DUniforms) - { - d3dUniform->dirty = true; - } + mVertexUniformsDirty = true; + mFragmentUniformsDirty = true; + mComputeUniformsDirty = true; +} + +void ProgramD3D::markUniformsClean() +{ + mVertexUniformsDirty = false; + mFragmentUniformsDirty = false; + mComputeUniformsDirty = false; } void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT); + setUniformInternal(location, count, v, GL_FLOAT); } void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC2); + setUniformInternal(location, count, v, GL_FLOAT_VEC2); } void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC3); + setUniformInternal(location, count, v, GL_FLOAT_VEC3); } void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { - setUniform(location, count, v, GL_FLOAT_VEC4); + setUniformInternal(location, count, v, GL_FLOAT_VEC4); } void ProgramD3D::setUniformMatrix2fv(GLint location, @@ -1672,7 +1901,7 @@ void ProgramD3D::setUniformMatrix2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); + setUniformMatrixfvInternal<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); } void ProgramD3D::setUniformMatrix3fv(GLint location, @@ -1680,7 +1909,7 @@ void ProgramD3D::setUniformMatrix3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); + setUniformMatrixfvInternal<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); } void ProgramD3D::setUniformMatrix4fv(GLint location, @@ -1688,7 +1917,7 @@ void ProgramD3D::setUniformMatrix4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); + setUniformMatrixfvInternal<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); } void ProgramD3D::setUniformMatrix2x3fv(GLint location, @@ -1696,7 +1925,7 @@ void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); + setUniformMatrixfvInternal<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); } void ProgramD3D::setUniformMatrix3x2fv(GLint location, @@ -1704,7 +1933,7 @@ void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); + setUniformMatrixfvInternal<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); } void ProgramD3D::setUniformMatrix2x4fv(GLint location, @@ -1712,7 +1941,7 @@ void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); + setUniformMatrixfvInternal<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); } void ProgramD3D::setUniformMatrix4x2fv(GLint location, @@ -1720,7 +1949,7 @@ void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); + setUniformMatrixfvInternal<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); } void ProgramD3D::setUniformMatrix3x4fv(GLint location, @@ -1728,7 +1957,7 @@ void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); + setUniformMatrixfvInternal<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); } void ProgramD3D::setUniformMatrix4x3fv(GLint location, @@ -1736,47 +1965,47 @@ void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLboolean transpose, const GLfloat *value) { - setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); + setUniformMatrixfvInternal<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); } void ProgramD3D::setUniform1iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT); + setUniformInternal(location, count, v, GL_INT); } void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC2); + setUniformInternal(location, count, v, GL_INT_VEC2); } void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC3); + setUniformInternal(location, count, v, GL_INT_VEC3); } void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - setUniform(location, count, v, GL_INT_VEC4); + setUniformInternal(location, count, v, GL_INT_VEC4); } void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT); + setUniformInternal(location, count, v, GL_UNSIGNED_INT); } void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); + setUniformInternal(location, count, v, GL_UNSIGNED_INT_VEC2); } void ProgramD3D::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); + setUniformInternal(location, count, v, GL_UNSIGNED_INT_VEC3); } void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); + setUniformInternal(location, count, v, GL_UNSIGNED_INT_VEC4); } void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/, @@ -1784,35 +2013,58 @@ void ProgramD3D::setUniformBlockBinding(GLuint /*uniformBlockIndex*/, { } -void ProgramD3D::defineUniformsAndAssignRegisters() +void ProgramD3D::defineUniformsAndAssignRegisters(const gl::Context *context) { D3DUniformMap uniformMap; - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); - for (const sh::Uniform &vertexUniform : vertexShader->getUniforms()) - + gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) { - if (vertexUniform.staticUse) + for (const sh::Uniform &computeUniform : computeShader->getUniforms(context)) { - defineUniformBase(vertexShader, vertexUniform, &uniformMap); + if (computeUniform.staticUse) + { + defineUniformBase(computeShader, computeUniform, &uniformMap); + } } } - - const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); - for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms()) + else { - if (fragmentUniform.staticUse) + gl::Shader *vertexShader = mState.getAttachedVertexShader(); + for (const sh::Uniform &vertexUniform : vertexShader->getUniforms(context)) + { + if (vertexUniform.staticUse) + { + defineUniformBase(vertexShader, vertexUniform, &uniformMap); + } + } + + gl::Shader *fragmentShader = mState.getAttachedFragmentShader(); + for (const sh::Uniform &fragmentUniform : fragmentShader->getUniforms(context)) { - defineUniformBase(fragmentShader, fragmentUniform, &uniformMap); + if (fragmentUniform.staticUse) + { + defineUniformBase(fragmentShader, fragmentUniform, &uniformMap); + } } } // Initialize the D3DUniform list to mirror the indexing of the GL layer. - for (const gl::LinkedUniform &glUniform : mData.getUniforms()) + for (const gl::LinkedUniform &glUniform : mState.getUniforms()) { if (!glUniform.isInDefaultBlock()) continue; - auto mapEntry = uniformMap.find(glUniform.name); + std::string name = glUniform.name; + if (glUniform.isArray()) + { + // In the program state, array uniform names include [0] as in the program resource + // spec. Here we don't include it. + // TODO(oetuaho@nvidia.com): consider using the same uniform naming here as in the GL + // layer. + ASSERT(angle::EndsWith(name, "[0]")); + name.resize(name.length() - 3); + } + auto mapEntry = uniformMap.find(name); ASSERT(mapEntry != uniformMap.end()); mD3DUniforms.push_back(mapEntry->second); } @@ -1825,7 +2077,8 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, const sh::Uniform &uniform, D3DUniformMap *uniformMap) { - if (uniform.isBuiltIn()) + // Samplers get their registers assigned in assignAllSamplerRegisters. + if (uniform.isBuiltIn() || gl::IsSamplerType(uniform.type)) { defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap); return; @@ -1835,7 +2088,7 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name); ShShaderOutput outputType = shaderD3D->getCompilerOutputType(); - sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType), true); encoder.skipRegisters(startRegister); defineUniform(shader->getType(), uniform, uniform.name, &encoder, uniformMap); @@ -1854,6 +2107,84 @@ D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name) return nullptr; } +void ProgramD3D::defineStructUniformFields(GLenum shaderType, + const std::vector &fields, + const std::string &namePrefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + if (encoder) + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const sh::ShaderVariable &field = fields[fieldIndex]; + const std::string &fieldFullName = (namePrefix + "." + field.name); + + // Samplers get their registers assigned in assignAllSamplerRegisters. + // Also they couldn't use the same encoder as the rest of the struct, since they are + // extracted out of the struct by the shader translator. + if (gl::IsSamplerType(field.type)) + { + defineUniform(shaderType, field, fieldFullName, nullptr, uniformMap); + } + else + { + defineUniform(shaderType, field, fieldFullName, encoder, uniformMap); + } + } + + if (encoder) + encoder->exitAggregateType(); +} + +void ProgramD3D::defineArrayOfStructsUniformFields(GLenum shaderType, + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &prefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string &elementString = prefix + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < uniform.arraySizes.size()) + { + defineArrayOfStructsUniformFields(shaderType, uniform, arrayNestingIndex + 1u, + elementString, encoder, uniformMap); + } + else + { + defineStructUniformFields(shaderType, uniform.fields, elementString, encoder, + uniformMap); + } + } +} + +void ProgramD3D::defineArrayUniformElements(GLenum shaderType, + const sh::ShaderVariable &uniform, + const std::string &fullName, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap) +{ + if (encoder) + encoder->enterAggregateType(); + + sh::ShaderVariable uniformElement = uniform; + uniformElement.arraySizes.pop_back(); + for (unsigned int arrayIndex = 0u; arrayIndex < uniform.getOutermostArraySize(); ++arrayIndex) + { + std::string elementFullName = fullName + ArrayString(arrayIndex); + defineUniform(shaderType, uniformElement, elementFullName, encoder, uniformMap); + } + + if (encoder) + encoder->exitAggregateType(); +} + void ProgramD3D::defineUniform(GLenum shaderType, const sh::ShaderVariable &uniform, const std::string &fullName, @@ -1862,26 +2193,22 @@ void ProgramD3D::defineUniform(GLenum shaderType, { if (uniform.isStruct()) { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + if (uniform.isArray()) { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - if (encoder) - encoder->enterAggregateType(); - - 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); - - defineUniform(shaderType, field, fieldFullName, encoder, uniformMap); - } - - if (encoder) - encoder->exitAggregateType(); + defineArrayOfStructsUniformFields(shaderType, uniform, 0u, fullName, encoder, + uniformMap); + } + else + { + defineStructUniformFields(shaderType, uniform.fields, fullName, encoder, uniformMap); } return; } + if (uniform.isArrayOfArrays()) + { + defineArrayUniformElements(shaderType, uniform, fullName, encoder, uniformMap); + return; + } // Not a struct. Arrays are treated as aggregate types. if (uniform.isArray() && encoder) @@ -1891,7 +2218,7 @@ void ProgramD3D::defineUniform(GLenum shaderType, // Advance the uniform offset, to track registers allocation for structs sh::BlockMemberInfo blockInfo = - encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false) + encoder ? encoder->encodeType(uniform.type, uniform.arraySizes, false) : sh::BlockMemberInfo::getDefaultBlockInfo(); auto uniformMapEntry = uniformMap->find(fullName); @@ -1903,7 +2230,7 @@ void ProgramD3D::defineUniform(GLenum shaderType, } else { - d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true); + d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySizes, true); (*uniformMap)[fullName] = d3dUniform; } @@ -1917,11 +2244,15 @@ void ProgramD3D::defineUniform(GLenum shaderType, { d3dUniform->psRegisterIndex = reg; } - else + else if (shaderType == GL_VERTEX_SHADER) { - ASSERT(shaderType == GL_VERTEX_SHADER); d3dUniform->vsRegisterIndex = reg; } + else + { + ASSERT(shaderType == GL_COMPUTE_SHADER); + d3dUniform->csRegisterIndex = reg; + } // Arrays are treated as aggregate types if (uniform.isArray()) @@ -1931,177 +2262,223 @@ void ProgramD3D::defineUniform(GLenum shaderType, } } +// Assume count is already clamped. template -void ProgramD3D::setUniform(GLint location, GLsizei countIn, const T *v, GLenum targetUniformType) +void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo, + GLsizei count, + const T *v, + uint8_t *targetData, + GLenum uniformType) { - const int components = gl::VariableComponentCount(targetUniformType); - const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); - - D3DUniform *targetUniform = getD3DUniformFromLocation(location); - - unsigned int elementCount = targetUniform->elementCount(); - unsigned int arrayElement = mData.getUniformLocations()[location].element; - unsigned int count = std::min(elementCount - arrayElement, static_cast(countIn)); + D3DUniform *targetUniform = mD3DUniforms[locationInfo.index]; + const int components = targetUniform->typeInfo.componentCount; + const unsigned int arrayElementOffset = locationInfo.arrayIndex; - if (targetUniform->type == targetUniformType) + if (targetUniform->typeInfo.type == uniformType) { - T *target = reinterpret_cast(targetUniform->data) + arrayElement * 4; + T *dest = reinterpret_cast(targetData) + arrayElementOffset * 4; + const T *source = v; - for (unsigned int i = 0; i < count; i++) + for (GLint i = 0; i < count; i++, dest += 4, source += components) { - T *dest = target + (i * 4); - const T *source = v + (i * components); - - for (int c = 0; c < components; c++) - { - SetIfDirty(dest + c, source[c], &targetUniform->dirty); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, T(0), &targetUniform->dirty); - } + memcpy(dest, source, components * sizeof(T)); } } - else if (targetUniform->type == targetBoolType) + else { - GLint *boolParams = reinterpret_cast(targetUniform->data) + arrayElement * 4; + ASSERT(targetUniform->typeInfo.type == gl::VariableBoolVectorType(uniformType)); + GLint *boolParams = reinterpret_cast(targetData) + arrayElementOffset * 4; - for (unsigned int i = 0; i < count; i++) + for (GLint i = 0; i < count; i++) { 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); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); + dest[c] = (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE; } } } - else if (targetUniform->isSampler()) - { - ASSERT(targetUniformType == GL_INT); - - GLint *target = reinterpret_cast(targetUniform->data) + arrayElement * 4; - - bool wasDirty = targetUniform->dirty; - - for (unsigned int i = 0; i < count; i++) - { - 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); - SetIfDirty(dest + 2, 0, &targetUniform->dirty); - SetIfDirty(dest + 3, 0, &targetUniform->dirty); - } +template +void ProgramD3D::setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType) +{ + const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; + D3DUniform *targetUniform = mD3DUniforms[locationInfo.index]; - if (!wasDirty && targetUniform->dirty) + if (targetUniform->typeInfo.isSampler) + { + ASSERT(uniformType == GL_INT); + size_t size = count * sizeof(T); + GLint *dest = &targetUniform->mSamplerData[locationInfo.arrayIndex]; + if (memcmp(dest, v, size) != 0) { + memcpy(dest, v, size); mDirtySamplerMapping = true; } + return; + } + + if (targetUniform->vsData) + { + setUniformImpl(locationInfo, count, v, targetUniform->vsData, uniformType); + mVertexUniformsDirty = true; + } + + if (targetUniform->psData) + { + setUniformImpl(locationInfo, count, v, targetUniform->psData, uniformType); + mFragmentUniformsDirty = true; + } + + if (targetUniform->csData) + { + setUniformImpl(locationInfo, count, v, targetUniform->csData, uniformType); + mComputeUniformsDirty = true; } - else - UNREACHABLE(); } template -void ProgramD3D::setUniformMatrixfv(GLint location, - GLsizei countIn, - GLboolean transpose, - const GLfloat *value, - GLenum targetUniformType) +bool ProgramD3D::setUniformMatrixfvImpl(GLint location, + GLsizei countIn, + GLboolean transpose, + const GLfloat *value, + uint8_t *targetData, + GLenum targetUniformType) { D3DUniform *targetUniform = getD3DUniformFromLocation(location); - unsigned int elementCount = targetUniform->elementCount(); - unsigned int arrayElement = mData.getUniformLocations()[location].element; - unsigned int count = std::min(elementCount - arrayElement, static_cast(countIn)); + unsigned int elementCount = targetUniform->getArraySizeProduct(); + unsigned int arrayElementOffset = mState.getUniformLocations()[location].arrayIndex; + unsigned int count = + std::min(elementCount - arrayElementOffset, static_cast(countIn)); const unsigned int targetMatrixStride = (4 * rows); - GLfloat *target = - (GLfloat *)(targetUniform->data + arrayElement * sizeof(GLfloat) * targetMatrixStride); + GLfloat *target = reinterpret_cast( + targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride); + + bool dirty = false; 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; + dirty = TransposeExpandMatrix(target, value) || dirty; } else { - targetUniform->dirty = - ExpandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + dirty = ExpandMatrix(target, value) || dirty; } target += targetMatrixStride; value += cols * rows; } + + return dirty; } -size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock) +template +void ProgramD3D::setUniformMatrixfvInternal(GLint location, + GLsizei countIn, + GLboolean transpose, + const GLfloat *value, + GLenum targetUniformType) { - ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED); - - // define member uniforms - sh::Std140BlockEncoder std140Encoder; - sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); - sh::BlockLayoutEncoder *encoder = nullptr; + D3DUniform *targetUniform = getD3DUniformFromLocation(location); - if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + if (targetUniform->vsData) { - encoder = &std140Encoder; + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->vsData, targetUniformType)) + { + mVertexUniformsDirty = true; + } } - else + + if (targetUniform->psData) { - encoder = &hlslEncoder; + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->psData, targetUniformType)) + { + mFragmentUniformsDirty = true; + } } - GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder, - interfaceBlock.isRowMajorLayout, &mBlockInfo); - - return encoder->getBlockSize(); + if (targetUniform->csData) + { + if (setUniformMatrixfvImpl(location, countIn, transpose, value, + targetUniform->csData, targetUniformType)) + { + mComputeUniformsDirty = true; + } + } } void ProgramD3D::assignAllSamplerRegisters() { - for (const D3DUniform *d3dUniform : mD3DUniforms) + for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex) { - if (d3dUniform->isSampler()) + if (mD3DUniforms[uniformIndex]->isSampler()) { - assignSamplerRegisters(d3dUniform); + assignSamplerRegisters(uniformIndex); } } } -void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform) +void ProgramD3D::assignSamplerRegisters(size_t uniformIndex) { + D3DUniform *d3dUniform = mD3DUniforms[uniformIndex]; ASSERT(d3dUniform->isSampler()); - ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX || - d3dUniform->psRegisterIndex != GL_INVALID_INDEX); - - if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX) - { - AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize, - mSamplersVS, &mUsedVertexSamplerRange); + // If the uniform is an array of arrays, then we have separate entries for each inner array in + // mD3DUniforms. However, the sampler register info is stored in the shader only for the + // outermost array. + std::vector subscripts; + const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts); + unsigned int registerOffset = mState.getUniforms()[uniformIndex].flattenedOffsetInParentArrays * + d3dUniform->getArraySizeProduct(); + + const gl::Shader *computeShader = mState.getAttachedComputeShader(); + if (computeShader) + { + const ShaderD3D *computeShaderD3D = GetImplAs(mState.getAttachedComputeShader()); + ASSERT(computeShaderD3D->hasUniform(baseName)); + d3dUniform->csRegisterIndex = + computeShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->csRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->csRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersCS, &mUsedComputeSamplerRange); } - - if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX) + else { - AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize, - mSamplersPS, &mUsedPixelSamplerRange); + const ShaderD3D *vertexShaderD3D = GetImplAs(mState.getAttachedVertexShader()); + const ShaderD3D *fragmentShaderD3D = + GetImplAs(mState.getAttachedFragmentShader()); + ASSERT(vertexShaderD3D->hasUniform(baseName) || fragmentShaderD3D->hasUniform(baseName)); + if (vertexShaderD3D->hasUniform(baseName)) + { + d3dUniform->vsRegisterIndex = + vertexShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersVS, + &mUsedVertexSamplerRange); + } + if (fragmentShaderD3D->hasUniform(baseName)) + { + d3dUniform->psRegisterIndex = + fragmentShaderD3D->getUniformRegister(baseName) + registerOffset; + ASSERT(d3dUniform->psRegisterIndex != GL_INVALID_INDEX); + AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->typeInfo, + d3dUniform->getArraySizeProduct(), mSamplersPS, &mUsedPixelSamplerRange); + } } } // static void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, + const gl::UniformTypeInfo &typeInfo, unsigned int samplerCount, std::vector &outSamplers, GLuint *outUsedRange) @@ -2113,7 +2490,7 @@ void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, ASSERT(samplerIndex < outSamplers.size()); Sampler *sampler = &outSamplers[samplerIndex]; sampler->active = true; - sampler->textureType = gl::SamplerTypeToTextureType(samplerType); + sampler->textureType = typeInfo.samplerTextureType; sampler->logicalTextureUnit = 0; *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); samplerIndex++; @@ -2122,20 +2499,24 @@ void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex, void ProgramD3D::reset() { - SafeDeleteContainer(mVertexExecutables); - SafeDeleteContainer(mPixelExecutables); + mVertexExecutables.clear(); + mPixelExecutables.clear(); - for (auto &element : mGeometryExecutables) + for (auto &geometryExecutable : mGeometryExecutables) { - SafeDelete(element); + geometryExecutable.reset(nullptr); } + mComputeExecutable.reset(nullptr); + mVertexHLSL.clear(); - mVertexWorkarounds = D3DCompilerWorkarounds(); + mVertexWorkarounds = angle::CompilerWorkaroundsD3D(); mPixelHLSL.clear(); - mPixelWorkarounds = D3DCompilerWorkarounds(); + mPixelWorkarounds = angle::CompilerWorkaroundsD3D(); mUsesFragDepth = false; + mHasANGLEMultiviewEnabled = false; + mUsesViewID = false; mPixelShaderKey.clear(); mUsesPointSize = false; mUsesFlatInterpolation = false; @@ -2143,22 +2524,29 @@ void ProgramD3D::reset() SafeDeleteContainer(mD3DUniforms); mD3DUniformBlocks.clear(); - SafeDelete(mVertexUniformStorage); - SafeDelete(mFragmentUniformStorage); + mVertexUniformStorage.reset(nullptr); + mFragmentUniformStorage.reset(nullptr); + mComputeUniformStorage.reset(nullptr); mSamplersPS.clear(); mSamplersVS.clear(); + mSamplersCS.clear(); mUsedVertexSamplerRange = 0; mUsedPixelSamplerRange = 0; + mUsedComputeSamplerRange = 0; mDirtySamplerMapping = true; - std::fill(mSemanticIndexes, mSemanticIndexes + ArraySize(mSemanticIndexes), -1); - std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1); + mAttribLocationToD3DSemantic.fill(-1); mStreamOutVaryings.clear(); mGeometryShaderPreamble.clear(); + + dirtyAllUniforms(); + + mCachedPixelExecutableIndex.reset(); + mCachedVertexExecutableIndex.reset(); } unsigned int ProgramD3D::getSerial() const @@ -2171,84 +2559,96 @@ unsigned int ProgramD3D::issueSerial() return mCurrentSerial++; } -void ProgramD3D::initSemanticIndex() +void ProgramD3D::initAttribLocationsToD3DSemantic(const gl::Context *context) { - const gl::Shader *vertexShader = mData.getAttachedVertexShader(); + gl::Shader *vertexShader = mState.getAttachedVertexShader(); ASSERT(vertexShader != nullptr); // Init semantic index - for (const sh::Attribute &attribute : mData.getAttributes()) + int semanticIndex = 0; + for (const sh::Attribute &attribute : vertexShader->getActiveAttributes(context)) { - int attributeIndex = attribute.location; - int index = vertexShader->getSemanticIndex(attribute.name); - int regs = gl::VariableRegisterCount(attribute.type); + int regCount = gl::VariableRegisterCount(attribute.type); + GLuint location = mState.getAttributeLocation(attribute.name); + ASSERT(location != std::numeric_limits::max()); - for (int reg = 0; reg < regs; ++reg) + for (int reg = 0; reg < regCount; ++reg) { - mSemanticIndexes[attributeIndex + reg] = index + reg; + mAttribLocationToD3DSemantic[location + reg] = semanticIndex++; } } - - initAttributesByLayout(); } -void ProgramD3D::initAttributesByLayout() +void ProgramD3D::updateCachedInputLayout(Serial associatedSerial, const gl::State &state) { - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + if (mCurrentVertexArrayStateSerial == associatedSerial) { - mAttributesByLayout[i] = i; + return; } - std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], - AttributeSorter(mSemanticIndexes)); -} + mCurrentVertexArrayStateSerial = associatedSerial; + mCachedInputLayout.clear(); -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) + const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + + for (size_t locationIndex : mState.getActiveAttribLocationsMask()) { - int oldIndex = mAttributesByLayout[attribIndex]; - sortedSemanticIndicesOut[attribIndex] = mSemanticIndexes[oldIndex]; - sortedAttributesOut[attribIndex] = &unsortedAttributes[oldIndex]; + int d3dSemantic = mAttribLocationToD3DSemantic[locationIndex]; + + if (d3dSemantic != -1) + { + if (mCachedInputLayout.size() < static_cast(d3dSemantic + 1)) + { + mCachedInputLayout.resize(d3dSemantic + 1, gl::VERTEX_FORMAT_INVALID); + } + mCachedInputLayout[d3dSemantic] = + GetVertexFormatType(vertexAttributes[locationIndex], + state.getVertexAttribCurrentValue(locationIndex).Type); + } } + + VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature); + + updateCachedVertexExecutableIndex(); } -void ProgramD3D::updateCachedInputLayout(const gl::State &state) +void ProgramD3D::updateCachedOutputLayout(const gl::Context *context, + const gl::Framebuffer *framebuffer) { - mCachedInputLayout.clear(); - const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + mPixelShaderOutputLayoutCache.clear(); - for (unsigned int attributeIndex : angle::IterateBitSet(mData.getActiveAttribLocationsMask())) + FramebufferD3D *fboD3D = GetImplAs(framebuffer); + const auto &colorbuffers = fboD3D->getColorAttachmentsForRender(context); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) { - int semanticIndex = mSemanticIndexes[attributeIndex]; + const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - if (semanticIndex != -1) + if (colorbuffer) { - if (mCachedInputLayout.size() < static_cast(semanticIndex + 1)) - { - mCachedInputLayout.resize(semanticIndex + 1, gl::VERTEX_FORMAT_INVALID); - } - mCachedInputLayout[semanticIndex] = - GetVertexFormatType(vertexAttributes[attributeIndex], - state.getVertexAttribCurrentValue(attributeIndex).Type); + auto binding = colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 + : colorbuffer->getBinding(); + mPixelShaderOutputLayoutCache.push_back(binding); + } + else + { + mPixelShaderOutputLayoutCache.push_back(GL_NONE); } } + + updateCachedPixelExecutableIndex(); } -void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking) +void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyingPacking, + const BuiltinInfo &builtins) { - 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(); + const auto &tfVaryingNames = mState.getTransformFeedbackVaryingNames(); for (unsigned int outputSlot = 0; outputSlot < static_cast(tfVaryingNames.size()); ++outputSlot) { @@ -2278,7 +2678,14 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa } else { - for (const PackedVaryingRegister ®isterInfo : varyingPacking.getRegisterList()) + std::vector subscripts; + std::string baseName = gl::ParseResourceName(tfVaryingName, &subscripts); + size_t subscript = GL_INVALID_INDEX; + if (!subscripts.empty()) + { + subscript = subscripts.back(); + } + for (const auto ®isterInfo : varyingPacking.getRegisterList()) { const auto &varying = *registerInfo.packedVarying->varying; GLenum transposedType = gl::TransposeMatrixType(varying.type); @@ -2293,7 +2700,8 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa // 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) + if (baseName == registerInfo.packedVarying->varying->name && + (subscript == GL_INVALID_INDEX || subscript == registerInfo.varyingArrayIndex)) { mStreamOutVaryings.push_back(D3DVarying( varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot)); @@ -2305,36 +2713,155 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) { - return mD3DUniforms[mData.getUniformLocations()[location].index]; + return mD3DUniforms[mState.getUniformLocations()[location].index]; +} + +const D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) const +{ + return mD3DUniforms[mState.getUniformLocations()[location].index]; } -bool ProgramD3D::getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const +void ProgramD3D::setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) { - std::string baseName = blockName; - gl::ParseAndStripArrayIndex(&baseName); + UNREACHABLE(); +} - auto sizeIter = mBlockDataSizes.find(baseName); - if (sizeIter == mBlockDataSizes.end()) +bool ProgramD3D::hasVertexExecutableForCachedInputLayout() +{ + return mCachedVertexExecutableIndex.valid(); +} + +bool ProgramD3D::hasGeometryExecutableForPrimitiveType(GLenum drawMode) +{ + if (!usesGeometryShader(drawMode)) { - *sizeOut = 0; - return false; + // No shader necessary mean we have the required (null) executable. + return true; } - *sizeOut = sizeIter->second; - return true; + gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); + return mGeometryExecutables[geometryShaderType].get() != nullptr; } -bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName, - sh::BlockMemberInfo *memberInfoOut) const +bool ProgramD3D::hasPixelExecutableForCachedOutputLayout() { - auto infoIter = mBlockInfo.find(memberUniformName); - if (infoIter == mBlockInfo.end()) + return mCachedPixelExecutableIndex.valid(); +} + +template +void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const +{ + const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; + const gl::LinkedUniform &uniform = mState.getUniforms()[locationInfo.index]; + + const D3DUniform *targetUniform = getD3DUniformFromLocation(location); + const uint8_t *srcPointer = targetUniform->getDataPtrToElement(locationInfo.arrayIndex); + + if (gl::IsMatrixType(uniform.type)) { - *memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); - return false; + GetMatrixUniform(gl::VariableColumnCount(uniform.type), gl::VariableRowCount(uniform.type), + dataOut, reinterpret_cast(srcPointer)); + } + else + { + memcpy(dataOut, srcPointer, uniform.getElementSize()); } +} - *memberInfoOut = infoIter->second; - return true; +void ProgramD3D::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::getUniformiv(const gl::Context *context, GLint location, GLint *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const +{ + getUniformInternal(location, params); +} + +void ProgramD3D::updateCachedVertexExecutableIndex() +{ + mCachedVertexExecutableIndex.reset(); + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) + { + mCachedVertexExecutableIndex = executableIndex; + break; + } + } +} + +void ProgramD3D::updateCachedPixelExecutableIndex() +{ + mCachedPixelExecutableIndex.reset(); + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(mPixelShaderOutputLayoutCache)) + { + mCachedPixelExecutableIndex = executableIndex; + break; + } + } } + +void ProgramD3D::linkResources(const gl::Context *context, + const gl::ProgramLinkedResources &resources) +{ + UniformBlockInfo uniformBlockInfo; + + if (mState.getAttachedVertexShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedVertexShader()); + } + + if (mState.getAttachedFragmentShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedFragmentShader()); + } + + if (mState.getAttachedComputeShader()) + { + uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedComputeShader()); + } + + // Gather interface block info. + auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name, + const std::string &mappedName, size_t *sizeOut) { + return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut); + }; + + auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name, + const std::string &mappedName, + sh::BlockMemberInfo *infoOut) { + return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut); + }; + + resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo); + initializeUniformBlocks(); + + // TODO(jiajia.qin@intel.com): Determine correct shader storage block info. + auto getShaderStorageBlockSize = [](const std::string &name, const std::string &mappedName, + size_t *sizeOut) { + *sizeOut = 0; + return true; + }; + + auto getShaderStorageBlockMemberInfo = + [](const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut) { + *infoOut = sh::BlockMemberInfo::getDefaultBlockInfo(); + return true; + }; + + resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize, + getShaderStorageBlockMemberInfo); } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h index 3dfe52db1c..829757a73e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -17,7 +17,7 @@ #include "libANGLE/formatutils.h" #include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/d3d/DynamicHLSL.h" -#include "libANGLE/renderer/d3d/WorkaroundsD3D.h" +#include "platform/WorkaroundsD3D.h" namespace rx { @@ -32,52 +32,71 @@ class ShaderExecutableD3D; #endif // Helper struct representing a single shader uniform -struct D3DUniform : angle::NonCopyable +// TODO(jmadill): Make uniform blocks shared between all programs, so we don't need separate +// register indices. +struct D3DUniform : private angle::NonCopyable { - D3DUniform(GLenum typeIn, + D3DUniform(GLenum type, const std::string &nameIn, - unsigned int arraySizeIn, + const std::vector &arraySizesIn, bool defaultBlock); ~D3DUniform(); bool isSampler() const; - unsigned int elementCount() const { return std::max(1u, arraySize); } + + bool isArray() const { return !arraySizes.empty(); } + unsigned int getArraySizeProduct() const; + bool isReferencedByVertexShader() const; bool isReferencedByFragmentShader() const; + bool isReferencedByComputeShader() const; - // Duplicated from the GL layer - GLenum type; - std::string name; - unsigned int arraySize; + const uint8_t *firstNonNullData() const; + const uint8_t *getDataPtrToElement(size_t elementIndex) const; - // Pointer to a system copy of the data. - // TODO(jmadill): remove this in favor of gl::LinkedUniform::data(). - uint8_t *data; + // Duplicated from the GL layer + const gl::UniformTypeInfo &typeInfo; + std::string name; // Names of arrays don't include [0], unlike at the GL layer. + std::vector arraySizes; - // Has the data been updated since the last sync? - bool dirty; + // Pointer to a system copies of the data. Separate pointers for each uniform storage type. + uint8_t *vsData; + uint8_t *psData; + uint8_t *csData; // Register information. unsigned int vsRegisterIndex; unsigned int psRegisterIndex; + unsigned int csRegisterIndex; 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; + + // Special buffer for sampler values. + std::vector mSamplerData; }; struct D3DUniformBlock { - D3DUniformBlock() : vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX) {} + D3DUniformBlock() + : vsRegisterIndex(GL_INVALID_INDEX), + psRegisterIndex(GL_INVALID_INDEX), + csRegisterIndex(GL_INVALID_INDEX) + { + } bool vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; } bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; } + bool computeStaticUse() const { return csRegisterIndex != GL_INVALID_INDEX; } + unsigned int vsRegisterIndex; unsigned int psRegisterIndex; + unsigned int csRegisterIndex; }; struct D3DVarying final @@ -97,24 +116,24 @@ struct D3DVarying final unsigned int outputSlot; }; -class ProgramD3DMetadata : angle::NonCopyable +class ProgramD3DMetadata final : angle::NonCopyable { public: - ProgramD3DMetadata(int rendererMajorShaderModel, - const std::string &shaderModelSuffix, - bool usesInstancedPointSpriteEmulation, - bool usesViewScale, + ProgramD3DMetadata(RendererD3D *renderer, 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 usesBroadcast(const gl::ContextState &data) const; + bool usesFragDepth() const; bool usesPointCoord() const; bool usesFragCoord() const; bool usesPointSize() const; bool usesInsertedPointCoordValue() const; bool usesViewScale() const; + bool hasANGLEMultiviewEnabled() const; + bool usesViewID() const; + bool canSelectViewInVertexShader() const; bool addsPointCoordToVertexShader() const; bool usesTransformFeedbackGLPosition() const; bool usesSystemValuePointSize() const; @@ -127,6 +146,9 @@ class ProgramD3DMetadata : angle::NonCopyable const std::string mShaderModelSuffix; const bool mUsesInstancedPointSpriteEmulation; const bool mUsesViewScale; + const bool mHasANGLEMultiviewEnabled; + const bool mUsesViewID; + const bool mCanSelectViewInVertexShader; const ShaderD3D *mVertexShader; const ShaderD3D *mFragmentShader; }; @@ -134,10 +156,8 @@ class ProgramD3DMetadata : angle::NonCopyable class ProgramD3D : public ProgramImpl { public: - typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS]; - - ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer); - virtual ~ProgramD3D(); + ProgramD3D(const gl::ProgramState &data, RendererD3D *renderer); + ~ProgramD3D() override; const std::vector &getPixelShaderKey() { return mPixelShaderKey; } @@ -145,116 +165,157 @@ class ProgramD3D : public ProgramImpl 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(); + GLuint getUsedSamplerRange(gl::SamplerType type) const; + + enum SamplerMapping + { + WasDirty, + WasClean, + }; + + SamplerMapping updateSamplerMapping(); bool usesPointSize() const { return mUsesPointSize; } bool usesPointSpriteEmulation() const; bool usesGeometryShader(GLenum drawMode) const; + bool usesGeometryShaderForPointSpriteEmulation() const; bool usesInstancedPointSpriteEmulation() const; - LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) override; - gl::Error save(gl::BinaryOutputStream *stream) override; + gl::LinkResult load(const gl::Context *context, + gl::InfoLog &infoLog, + gl::BinaryInputStream *stream) override; + void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; + void setSeparable(bool separable) 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, + gl::Error getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog); + gl::Error getGeometryExecutableForPrimitiveType(const gl::Context *context, GLenum drawMode, ShaderExecutableD3D **outExecutable, gl::InfoLog *infoLog); - - LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override; + gl::Error getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog); + gl::Error getComputeExecutable(ShaderExecutableD3D **outExecutable); + gl::LinkResult link(const gl::Context *context, + const gl::ProgramLinkedResources &resources, + 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 setPathFragmentInputGen(const std::string &inputName, + GLenum genMode, + GLint components, + const GLfloat *coeffs) override; void initializeUniformStorage(); - gl::Error applyUniforms(GLenum drawMode); - gl::Error applyUniformBuffers(const gl::Data &data); + void updateUniformBufferCache(const gl::Caps &caps, + unsigned int reservedVertex, + unsigned int reservedFragment); + const std::vector &getVertexUniformBufferCache() const; + const std::vector &getFragmentUniformBufferCache() const; + void dirtyAllUniforms(); - 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); - void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform1iv(GLint location, GLsizei count, const GLint *v); - void setUniform2iv(GLint location, GLsizei count, const GLint *v); - void setUniform3iv(GLint location, GLsizei count, const GLint *v); - void setUniform4iv(GLint location, GLsizei count, const GLint *v); - void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); - 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 setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override; + void setUniform1iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform2iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform3iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform4iv(GLint location, GLsizei count, const GLint *v) override; + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override; + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override; void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, - const GLfloat *value); + const GLfloat *value) override; + + void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override; + void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override; + void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override; void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override; - const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; } - const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } + UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage.get(); } + UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage.get(); } + UniformStorageD3D &getComputeUniformStorage() const { return *mComputeUniformStorage.get(); } unsigned int getSerial() const; - 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; } + const AttribIndexArray &getAttribLocationToD3DSemantics() const + { + return mAttribLocationToD3DSemantic; + } - void updateCachedInputLayout(const gl::State &state); - const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; } + void updateCachedInputLayout(Serial associatedSerial, const gl::State &state); + void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer); bool isSamplerMappingDirty() { return mDirtySamplerMapping; } + // Checks if we need to recompile certain shaders. + bool hasVertexExecutableForCachedInputLayout(); + bool hasGeometryExecutableForPrimitiveType(GLenum drawMode); + bool hasPixelExecutableForCachedOutputLayout(); + + bool areVertexUniformsDirty() const { return mVertexUniformsDirty; } + bool areFragmentUniformsDirty() const { return mFragmentUniformsDirty; } + bool areComputeUniformsDirty() const { return mComputeUniformsDirty; } + const std::vector &getD3DUniforms() const { return mD3DUniforms; } + void markUniformsClean(); + private: + // These forward-declared tasks are used for multi-thread shader compiles. + class GetExecutableTask; + class GetVertexExecutableTask; + class GetPixelExecutableTask; + class GetGeometryExecutableTask; + class VertexExecutable { public: - typedef std::vector Signature; + enum HLSLAttribType + { + FLOAT, + UNSIGNED_INT, + SIGNED_INT, + }; + + typedef std::vector Signature; VertexExecutable(const gl::InputLayout &inputLayout, const Signature &signature, @@ -271,6 +332,8 @@ class ProgramD3D : public ProgramImpl ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } private: + static HLSLAttribType GetAttribType(GLenum type); + gl::InputLayout mInputs; Signature mSignature; ShaderExecutableD3D *mShaderExecutable; @@ -307,62 +370,105 @@ class ProgramD3D : public ProgramImpl typedef std::map D3DUniformMap; - void defineUniformsAndAssignRegisters(); + void defineUniformsAndAssignRegisters(const gl::Context *context); void defineUniformBase(const gl::Shader *shader, const sh::Uniform &uniform, D3DUniformMap *uniformMap); + void defineStructUniformFields(GLenum shaderType, + const std::vector &fields, + const std::string &namePrefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap); + void defineArrayOfStructsUniformFields(GLenum shaderType, + const sh::ShaderVariable &uniform, + unsigned int arrayNestingIndex, + const std::string &prefix, + sh::HLSLBlockEncoder *encoder, + D3DUniformMap *uniformMap); + void defineArrayUniformElements(GLenum shaderType, + const sh::ShaderVariable &uniform, + const std::string &fullName, + sh::HLSLBlockEncoder *encoder, + 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); + void assignSamplerRegisters(size_t uniformIndex); static void AssignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, + const gl::UniformTypeInfo &typeInfo, unsigned int samplerCount, std::vector &outSamplers, GLuint *outUsedRange); + template + void getUniformInternal(GLint location, DestT *dataOut) const; + + template + void setUniformImpl(const gl::VariableLocation &locationInfo, + GLsizei count, + const T *v, + uint8_t *targetData, + GLenum uniformType); + template - void setUniform(GLint location, GLsizei count, const T *v, GLenum targetUniformType); + void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType); template - void setUniformMatrixfv(GLint location, - GLsizei count, - GLboolean transpose, - const GLfloat *value, - GLenum targetUniformType); + bool setUniformMatrixfvImpl(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value, + uint8_t *targetData, + GLenum targetUniformType); - LinkResult compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog); + template + void setUniformMatrixfvInternal(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value, + GLenum targetUniformType); - void gatherTransformFeedbackVaryings(const VaryingPacking &varyings); + gl::LinkResult compileProgramExecutables(const gl::Context *context, gl::InfoLog &infoLog); + gl::LinkResult compileComputeExecutable(const gl::Context *context, gl::InfoLog &infoLog); + + void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings, + const BuiltinInfo &builtins); D3DUniform *getD3DUniformByName(const std::string &name); D3DUniform *getD3DUniformFromLocation(GLint location); + const D3DUniform *getD3DUniformFromLocation(GLint location) const; - void initSemanticIndex(); - void initAttributesByLayout(); + void initAttribLocationsToD3DSemantic(const gl::Context *context); void reset(); - void assignUniformBlockRegisters(); + void initializeUniformBlocks(); + + void updateCachedInputLayoutFromShader(const gl::Context *context); + void updateCachedOutputLayoutFromShader(); + void updateCachedVertexExecutableIndex(); + void updateCachedPixelExecutableIndex(); - void initUniformBlockInfo(); - size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock); + void linkResources(const gl::Context *context, const gl::ProgramLinkedResources &resources); RendererD3D *mRenderer; DynamicHLSL *mDynamicHLSL; - std::vector mVertexExecutables; - std::vector mPixelExecutables; - std::vector mGeometryExecutables; + std::vector> mVertexExecutables; + std::vector> mPixelExecutables; + std::vector> mGeometryExecutables; + std::unique_ptr mComputeExecutable; std::string mVertexHLSL; - D3DCompilerWorkarounds mVertexWorkarounds; + angle::CompilerWorkaroundsD3D mVertexWorkarounds; std::string mPixelHLSL; - D3DCompilerWorkarounds mPixelWorkarounds; + angle::CompilerWorkaroundsD3D mPixelWorkarounds; bool mUsesFragDepth; + bool mHasANGLEMultiviewEnabled; + bool mUsesViewID; std::vector mPixelShaderKey; // Common code for all dynamic geometry shaders. Consists mainly of the GS input and output @@ -373,20 +479,23 @@ class ProgramD3D : public ProgramImpl bool mUsesPointSize; bool mUsesFlatInterpolation; - UniformStorageD3D *mVertexUniformStorage; - UniformStorageD3D *mFragmentUniformStorage; + std::unique_ptr mVertexUniformStorage; + std::unique_ptr mFragmentUniformStorage; + std::unique_ptr mComputeUniformStorage; std::vector mSamplersPS; std::vector mSamplersVS; + std::vector mSamplersCS; GLuint mUsedVertexSamplerRange; GLuint mUsedPixelSamplerRange; + GLuint mUsedComputeSamplerRange; bool mDirtySamplerMapping; - // Cache for getPixelExecutableForFramebuffer - std::vector mPixelShaderOutputFormatCache; + // Cache for pixel shader output layout to save reallocations. + std::vector mPixelShaderOutputLayoutCache; + Optional mCachedPixelExecutableIndex; - SemanticIndexArray mSemanticIndexes; - SemanticIndexArray mAttributesByLayout; + AttribIndexArray mAttribLocationToD3DSemantic; unsigned int mSerial; @@ -394,17 +503,21 @@ class ProgramD3D : public ProgramImpl std::vector mFragmentUBOCache; VertexExecutable::Signature mCachedVertexSignature; gl::InputLayout mCachedInputLayout; + Optional mCachedVertexExecutableIndex; std::vector mStreamOutVaryings; std::vector mD3DUniforms; std::vector mD3DUniformBlocks; - std::map mBlockInfo; - std::map mBlockDataSizes; + bool mVertexUniformsDirty; + bool mFragmentUniformsDirty; + bool mComputeUniformsDirty; static unsigned int issueSerial(); static unsigned int mCurrentSerial; + + Serial mCurrentVertexArrayStateSerial; }; -} +} // namespace rx #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 b2d895d9c6..fde96133b0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h @@ -21,7 +21,7 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget { public: RenderTargetD3D(); - virtual ~RenderTargetD3D(); + ~RenderTargetD3D() override; virtual GLsizei getWidth() const = 0; virtual GLsizei getHeight() const = 0; @@ -29,10 +29,14 @@ class RenderTargetD3D : public FramebufferAttachmentRenderTarget virtual GLenum getInternalFormat() const = 0; virtual GLsizei getSamples() const = 0; gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } + bool isMultisampled() const { return getSamples() > 0; } virtual unsigned int getSerial() const; static unsigned int issueSerials(unsigned int count); + // Only currently applies to D3D11. + virtual void signalDirty(const gl::Context *context) {} + private: const unsigned int mSerial; static unsigned int mCurrentSerial; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp index 991801a091..d799e0b992 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp @@ -27,12 +27,25 @@ RenderbufferD3D::~RenderbufferD3D() mImage = nullptr; } -gl::Error RenderbufferD3D::setStorage(GLenum internalformat, size_t width, size_t height) +gl::Error RenderbufferD3D::onDestroy(const gl::Context *context) { - return setStorageMultisample(0, internalformat, width, height); + deleteRenderTarget(context); + return gl::NoError(); } -gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +gl::Error RenderbufferD3D::setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) +{ + return setStorageMultisample(context, 0, internalformat, width, height); +} + +gl::Error RenderbufferD3D::setStorageMultisample(const gl::Context *context, + size_t samples, + GLenum internalformat, + size_t width, + size_t height) { // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in @@ -48,54 +61,70 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal // 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); + const gl::TextureCaps &formatCaps = mRenderer->getNativeTextureCaps().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()); + return gl::OutOfMemory() << "Renderbuffer format does not support " << samples + << " samples, " << formatCaps.getMaxSamples() + << " is the maximum."; } - RenderTargetD3D *newRT = NULL; - gl::Error error = - mRenderer->createRenderTarget(static_cast(width), static_cast(height), - creationFormat, static_cast(samples), &newRT); - if (error.isError()) - { - return error; - } + RenderTargetD3D *newRT = nullptr; + ANGLE_TRY(mRenderer->createRenderTarget(static_cast(width), static_cast(height), + creationFormat, static_cast(samples), &newRT)); - SafeDelete(mRenderTarget); + deleteRenderTarget(context); mImage = nullptr; mRenderTarget = newRT; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image) +gl::Error RenderbufferD3D::setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) { mImage = GetImplAs(image); - SafeDelete(mRenderTarget); + deleteRenderTarget(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error RenderbufferD3D::getRenderTarget(RenderTargetD3D **outRenderTarget) +gl::Error RenderbufferD3D::getRenderTarget(const gl::Context *context, + RenderTargetD3D **outRenderTarget) { if (mImage) { - return mImage->getRenderTarget(outRenderTarget); + return mImage->getRenderTarget(context, outRenderTarget); } else { *outRenderTarget = mRenderTarget; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error RenderbufferD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum /*binding*/, + const gl::ImageIndex & /*imageIndex*/, FramebufferAttachmentRenderTarget **rtOut) { - return getRenderTarget(reinterpret_cast(rtOut)); + return getRenderTarget(context, reinterpret_cast(rtOut)); } +void RenderbufferD3D::deleteRenderTarget(const gl::Context *context) +{ + if (mRenderTarget) + { + mRenderTarget->signalDirty(context); + SafeDelete(mRenderTarget); + } } + +gl::Error RenderbufferD3D::initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) +{ + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, &renderTarget)); + return mRenderer->initRenderTarget(renderTarget); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h index 20f6a10b2d..b50eff7db7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h @@ -25,20 +25,33 @@ class RenderbufferD3D : public RenderbufferImpl { public: RenderbufferD3D(RendererD3D *renderer); - virtual ~RenderbufferD3D(); + ~RenderbufferD3D() override; - gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; - gl::Error setStorageMultisample(size_t samples, + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error setStorage(const gl::Context *context, + GLenum internalformat, + size_t width, + size_t height) override; + gl::Error setStorageMultisample(const gl::Context *context, + size_t samples, GLenum internalformat, size_t width, size_t height) override; - gl::Error setStorageEGLImageTarget(egl::Image *image) override; + gl::Error setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) override; - gl::Error getRenderTarget(RenderTargetD3D **outRenderTarget); - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getRenderTarget(const gl::Context *context, RenderTargetD3D **outRenderTarget); + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; + gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) override; + private: + void deleteRenderTarget(const gl::Context *context); + RendererD3D *mRenderer; RenderTargetD3D *mRenderTarget; EGLImageD3D *mImage; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp index 105587f62c..2167200a91 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp @@ -8,43 +8,39 @@ #include "libANGLE/renderer/d3d/RendererD3D.h" -#include "common/debug.h" #include "common/MemoryBuffer.h" +#include "common/debug.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/formatutils.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/TextureImpl.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" +#include "libANGLE/renderer/d3d/TextureD3D.h" namespace rx { -namespace -{ -// If we request a scratch buffer requesting a smaller size this many times, -// 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), - mAnnotator(nullptr), mPresentPathFastEnabled(false), - mScratchMemoryBufferResetCounter(0), + mCapsInitialized(false), mWorkaroundsInitialized(false), - mDisjoint(false) + mDisjoint(false), + mDeviceLost(false), + mWorkerThreadPool(4) { } @@ -55,451 +51,29 @@ RendererD3D::~RendererD3D() void RendererD3D::cleanup() { - mScratchMemoryBuffer.resize(0); - for (auto &incompleteTexture : mIncompleteTextures) - { - incompleteTexture.second.set(NULL); - } - mIncompleteTextures.clear(); - - if (mAnnotator != nullptr) - { - gl::UninitializeDebugAnnotations(); - SafeDelete(mAnnotator); - } -} - -SamplerImpl *RendererD3D::createSampler() -{ - return new SamplerD3D(); -} - -gl::Error RendererD3D::drawArrays(const gl::Data &data, GLenum mode, GLint first, GLsizei count) -{ - 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, - const gl::IndexRange &indexRange) -{ - 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 != nullptr); - ProgramD3D *programD3D = GetImplAs(program); - bool usesPointSize = programD3D->usesPointSize(); - - programD3D->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count, usesPointSize)) - { - return gl::Error(GL_NO_ERROR); - } - - error = updateState(data, mode); - if (error.isError()) - { - return error; - } - - TranslatedIndexData indexInfo; - indexInfo.indexRange = indexRange; - - error = applyIndexBuffer(data, indices, count, mode, type, &indexInfo); - if (error.isError()) - { - return error; - } - - applyTransformFeedbackBuffers(*data.state); - // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation - // layer. - ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); - - 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 = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyShaders(data, mode); - if (error.isError()) - { - return error; - } - - error = programD3D->applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawElementsImpl(data, indexInfo, mode, count, type, indices, instances); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::genericDrawArrays(const gl::Data &data, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances) -{ - gl::Program *program = data.state->getProgram(); - ASSERT(program != nullptr); - ProgramD3D *programD3D = GetImplAs(program); - bool usesPointSize = programD3D->usesPointSize(); - - programD3D->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count, usesPointSize)) - { - return gl::Error(GL_NO_ERROR); - } - - error = updateState(data, mode); - if (error.isError()) - { - return error; - } - - applyTransformFeedbackBuffers(*data.state); - - error = applyVertexBuffer(*data.state, mode, first, count, instances, nullptr); - if (error.isError()) - { - return error; - } - - error = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyShaders(data, mode); - if (error.isError()) - { - return error; - } - - error = programD3D->applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawArraysImpl(data, mode, count, instances); - if (error.isError()) - { - return error; - } - - if (data.state->isTransformFeedbackActiveUnpaused()) - { - markTransformFeedbackUsage(data); - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - unsigned int samplerRange = static_cast(programD3D->getUsedSamplerRange(type)); - - for (unsigned int i = 0; i < samplerRange; i++) - { - 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->getTextureState().swizzleRequired()) - { - gl::Error error = generateSwizzle(texture); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::generateSwizzles(const gl::Data &data) -{ - gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX); - if (error.isError()) - { - return error; - } - - error = generateSwizzles(data, gl::SAMPLER_PIXEL); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -unsigned int RendererD3D::GetBlendSampleMask(const gl::Data &data, int samples) -{ - unsigned int mask = 0; - if (data.state->isSampleCoverageEnabled()) - { - GLclampf coverageValue = data.state->getSampleCoverageValue(); - if (coverageValue != 0) - { - float threshold = 0.5f; - - for (int i = 0; i < samples; ++i) - { - mask <<= 1; - - if ((i + 1) * coverageValue >= threshold) - { - threshold += 1.0f; - mask |= 1; - } - } - } - - bool coverageInvert = data.state->getSampleCoverageInvert(); - if (coverageInvert) - { - mask = ~mask; - } - } - else - { - mask = 0xFFFFFFFF; - } - - return mask; -} - -// Applies the shaders and shader constants to the Direct3D device -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::Error error = applyShadersImpl(data, drawMode); - if (error.isError()) - { - return error; - } - - 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 FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - ASSERT(!programD3D->isSamplerMappingDirty()); - - unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); - for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) - { - 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::Sampler *samplerObject = data.state->getSampler(textureUnit); - - const gl::SamplerState &samplerState = - samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); - - // TODO: std::binary_search may become unavailable using older versions of GCC - if (texture->isSamplerComplete(samplerState, data) && - !std::binary_search(framebufferTextures.begin(), - framebufferTextures.begin() + framebufferTextureCount, texture)) - { - gl::Error error = setSamplerState(shaderType, samplerIndex, texture, samplerState); - if (error.isError()) - { - return error; - } - - error = setTexture(shaderType, samplerIndex, texture); - if (error.isError()) - { - return error; - } - } - else - { - // 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 = setSamplerState(shaderType, samplerIndex, incompleteTexture, - incompleteTexture->getSamplerState()); - if (error.isError()) - { - return error; - } - - error = setTexture(shaderType, samplerIndex, incompleteTexture); - if (error.isError()) - { - return error; - } - } - } - else - { - // No texture bound to this slot even though it is used by the shader, bind a NULL texture - gl::Error error = setTexture(shaderType, samplerIndex, NULL); - if (error.isError()) - { - return error; - } - } - } - - // Set all the remaining textures to NULL - size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits - : data.caps->maxVertexTextureImageUnits; - clearTextures(shaderType, samplerRange, samplerCount); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::applyTextures(const gl::Data &data) -{ - FramebufferTextureArray framebufferTextures; - size_t framebufferSerialCount = getBoundFramebufferTextures(data, &framebufferTextures); - - gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferTextures, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferTextures, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + mIncompleteTextures.onDestroy(mDisplay->getProxyContext()); } -bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) +bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode) { - const gl::State &state = *data.state; - if (drawMode == GL_POINTS) { - bool usesPointSize = GetImplAs(state.getProgram())->usesPointSize(); + bool usesPointSize = GetImplAs(glState.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 (!usesPointSize && !state.isTransformFeedbackActiveUnpaused()) + if (!usesPointSize && !glState.isTransformFeedbackActiveUnpaused()) { - // This is stictly speaking not an error, but developers should be - // notified of risking undefined behavior. - ERR("Point rendering without writing to gl_PointSize."); - + // Notify developers of risking undefined behavior. + WARN() << "Point rendering without writing to gl_PointSize."; return true; } } else if (gl::IsTriangleMode(drawMode)) { - if (state.getRasterizerState().cullFace && - state.getRasterizerState().cullMode == GL_FRONT_AND_BACK) + if (glState.getRasterizerState().cullFace && + glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack) { return true; } @@ -508,196 +82,179 @@ bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) return false; } -void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) +gl::Error RendererD3D::getIncompleteTexture(const gl::Context *context, + GLenum type, + gl::Texture **textureOut) { - const gl::TransformFeedback *transformFeedback = data.state->getCurrentTransformFeedback(); - for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - if (binding.get() != nullptr) - { - BufferD3D *bufferD3D = GetImplAs(binding.get()); - bufferD3D->markTransformFeedbackUsage(); - } - } + return mIncompleteTextures.getIncompleteTexture(context, type, this, textureOut); } -size_t RendererD3D::getBoundFramebufferTextures(const gl::Data &data, FramebufferTextureArray *outTextureArray) +GLenum RendererD3D::getResetStatus() { - size_t textureCount = 0; - - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++) + if (!mDeviceLost) { - const gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); - if (attachment && attachment->type() == GL_TEXTURE) + if (testDeviceLost()) { - (*outTextureArray)[textureCount++] = attachment->getTexture(); + mDeviceLost = true; + notifyDeviceLost(); + return GL_UNKNOWN_CONTEXT_RESET_EXT; } + return GL_NO_ERROR; } - const gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE) + if (testDeviceResettable()) { - (*outTextureArray)[textureCount++] = depthStencilAttachment->getTexture(); + return GL_NO_ERROR; } - std::sort(outTextureArray->begin(), outTextureArray->begin() + textureCount); - - return textureCount; -} - -gl::Texture *RendererD3D::getIncompleteTexture(GLenum type) -{ - if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) - { - const GLubyte color[] = { 0, 0, 0, 255 }; - const gl::Extents colorSize(1, 1, 1); - const gl::PixelUnpackState unpack(1, 0); - const gl::Box area(0, 0, 0, 1, 1, 1); - - // 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->getImplementation()->setSubImage(face, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, - unpack, color); - } - } - else - { - t->getImplementation()->setSubImage(type, 0, area, GL_RGBA8, GL_UNSIGNED_BYTE, unpack, - color); - } - - mIncompleteTextures[type].set(t); - } - - return mIncompleteTextures[type].get(); -} - -bool RendererD3D::isDeviceLost() const -{ - return mDeviceLost; + return GL_UNKNOWN_CONTEXT_RESET_EXT; } void RendererD3D::notifyDeviceLost() { - mDeviceLost = true; mDisplay->notifyDeviceLost(); } std::string RendererD3D::getVendorString() const { - LUID adapterLuid = { 0 }; + LUID adapterLuid = {0}; if (getLUID(&adapterLuid)) { char adapterLuidString[64]; - sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); + sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)", + adapterLuid.HighPart, adapterLuid.LowPart); return std::string(adapterLuidString); } return std::string(""); } -gl::Error RendererD3D::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut) +void RendererD3D::setGPUDisjoint() { - if (mScratchMemoryBuffer.size() == requestedSize) - { - mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; - *bufferOut = &mScratchMemoryBuffer; - return gl::Error(GL_NO_ERROR); - } - - if (mScratchMemoryBuffer.size() > requestedSize) - { - mScratchMemoryBufferResetCounter--; - } + mDisjoint = true; +} - if (mScratchMemoryBufferResetCounter <= 0 || mScratchMemoryBuffer.size() < requestedSize) - { - mScratchMemoryBuffer.resize(0); - if (!mScratchMemoryBuffer.resize(requestedSize)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); - } - mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; - } +GLint RendererD3D::getGPUDisjoint() +{ + bool disjoint = mDisjoint; - ASSERT(mScratchMemoryBuffer.size() >= requestedSize); + // Disjoint flag is cleared when read + mDisjoint = false; - *bufferOut = &mScratchMemoryBuffer; - return gl::Error(GL_NO_ERROR); + return disjoint; } -void RendererD3D::insertEventMarker(GLsizei length, const char *marker) +GLint64 RendererD3D::getTimestamp() { - 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()); - } + // D3D has no way to get an actual timestamp reliably so 0 is returned + return 0; } -void RendererD3D::pushGroupMarker(GLsizei length, const char *marker) +void RendererD3D::ensureCapsInitialized() const { - std::vector wcstring(length + 1); - size_t convertedChars = 0; - errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, marker, _TRUNCATE); - if (err == 0) + if (!mCapsInitialized) { - getAnnotator()->beginEvent(wcstring.data()); + generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations); + mCapsInitialized = true; } } -void RendererD3D::popGroupMarker() +const gl::Caps &RendererD3D::getNativeCaps() const { - getAnnotator()->endEvent(); + ensureCapsInitialized(); + return mNativeCaps; } -void RendererD3D::setGPUDisjoint() +const gl::TextureCapsMap &RendererD3D::getNativeTextureCaps() const { - mDisjoint = true; + ensureCapsInitialized(); + return mNativeTextureCaps; } -GLint RendererD3D::getGPUDisjoint() +const gl::Extensions &RendererD3D::getNativeExtensions() const { - bool disjoint = mDisjoint; + ensureCapsInitialized(); + return mNativeExtensions; +} - // Disjoint flag is cleared when read - mDisjoint = false; +const gl::Limitations &RendererD3D::getNativeLimitations() const +{ + ensureCapsInitialized(); + return mNativeLimitations; +} - return disjoint; +angle::WorkerThreadPool *RendererD3D::getWorkerThreadPool() +{ + return &mWorkerThreadPool; } -GLint64 RendererD3D::getTimestamp() +Serial RendererD3D::generateSerial() { - // D3D has no way to get an actual timestamp reliably so 0 is returned - return 0; + return mSerialFactory.generate(); } -void RendererD3D::onMakeCurrent(const gl::Data &data) +bool InstancedPointSpritesActive(ProgramD3D *programD3D, GLenum mode) { + return programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation() && + mode == GL_POINTS; } -void RendererD3D::initializeDebugAnnotator() +gl::Error RendererD3D::initRenderTarget(RenderTargetD3D *renderTarget) { - createAnnotator(); - ASSERT(mAnnotator); - gl::InitializeDebugAnnotations(mAnnotator); + return clearRenderTarget(renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0); } -gl::DebugAnnotator *RendererD3D::getAnnotator() +gl::Error RendererD3D::initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) { - ASSERT(mAnnotator); - return mAnnotator; + ASSERT(glTexture->getTarget() == GL_TEXTURE_2D_MULTISAMPLE); + TextureD3D *textureD3D = GetImplAs(glTexture); + gl::ImageIndex index = gl::ImageIndex::Make2DMultisample(); + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(textureD3D->getRenderTarget(context, index, &renderTarget)); + return clearRenderTarget(renderTarget, gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0); } + +unsigned int GetBlendSampleMask(const gl::State &glState, int samples) +{ + unsigned int mask = 0; + if (glState.isSampleCoverageEnabled()) + { + GLfloat coverageValue = glState.getSampleCoverageValue(); + if (coverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < samples; ++i) + { + mask <<= 1; + + if ((i + 1) * coverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + bool coverageInvert = glState.getSampleCoverageInvert(); + if (coverageInvert) + { + mask = ~mask; + } + } + else + { + mask = 0xFFFFFFFF; + } + + if (glState.isSampleMaskEnabled()) + { + mask &= glState.getSampleMaskWord(0); + } + + return mask; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h index f956f037e2..dcc98f2ec6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h @@ -9,19 +9,21 @@ #ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ #define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ -#include "common/debug.h" +#include + +#include "common/Color.h" #include "common/MemoryBuffer.h" -#include "libANGLE/Data.h" +#include "common/debug.h" +#include "libANGLE/ContextState.h" #include "libANGLE/Device.h" +#include "libANGLE/Version.h" +#include "libANGLE/WorkerThread.h" +#include "libANGLE/angletypes.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 -#include +#include "libANGLE/renderer/renderer_utils.h" +#include "platform/WorkaroundsD3D.h" namespace egl { @@ -30,7 +32,7 @@ class ConfigSet; namespace gl { -class DebugAnnotator; +class FramebufferState; class InfoLog; class Texture; struct LinkedVarying; @@ -38,28 +40,24 @@ struct LinkedVarying; namespace rx { +class ContextImpl; struct D3DUniform; struct D3DVarying; class DeviceD3D; class EGLImageD3D; +class FramebufferImpl; class ImageD3D; class IndexBuffer; +class NativeWindowD3D; class ProgramD3D; class RenderTargetD3D; class ShaderExecutableD3D; class SwapChainD3D; class TextureStorage; +struct TranslatedIndexData; class UniformStorageD3D; class VertexBuffer; -enum ShaderType -{ - SHADER_VERTEX, - SHADER_PIXEL, - SHADER_GEOMETRY, - SHADER_TYPE_MAX -}; - struct DeviceIdentifier { UINT VendorId; @@ -76,7 +74,7 @@ enum RendererClass }; // Useful for unit testing -class BufferFactoryD3D +class BufferFactoryD3D : angle::NonCopyable { public: BufferFactoryD3D() {} @@ -88,52 +86,32 @@ class BufferFactoryD3D // TODO(jmadill): add VertexFormatCaps virtual VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const = 0; virtual GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const = 0; + + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + virtual gl::ErrorOrResult getVertexSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const = 0; }; -class RendererD3D : public Renderer, public BufferFactoryD3D +using AttribIndexArray = std::array; + +class RendererD3D : public BufferFactoryD3D, public MultisampleTextureInitializer { public: explicit RendererD3D(egl::Display *display); - virtual ~RendererD3D(); + ~RendererD3D() override; virtual egl::Error initialize() = 0; - virtual egl::ConfigSet generateConfigs() const = 0; + virtual egl::ConfigSet generateConfigs() = 0; virtual void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const = 0; - 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, - 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 ContextImpl *createContext(const gl::ContextState &state) = 0; + + std::string getVendorString() const; virtual int getMinorShaderModel() const = 0; virtual std::string getShaderModelSuffix() const = 0; @@ -141,204 +119,241 @@ class RendererD3D : public Renderer, public BufferFactoryD3D // Direct3D Specific methods virtual DeviceIdentifier getAdapterIdentifier() const = 0; - virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + virtual NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const = 0; + + virtual SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) = 0; - - virtual gl::Error updateState(const gl::Data &data, GLenum drawMode) = 0; - - virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 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, - 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 unsigned int getReservedVertexUniformVectors() const = 0; - virtual unsigned int getReservedFragmentUniformVectors() const = 0; - virtual unsigned int getReservedVertexUniformBuffers() const = 0; - virtual unsigned int getReservedFragmentUniformBuffers() const = 0; + EGLint orientation, + EGLint samples) = 0; + virtual egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const = 0; + virtual egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const = 0; virtual int getMajorShaderModel() const = 0; - const WorkaroundsD3D &getWorkarounds() const; + const angle::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; - virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) = 0; - virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; - virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) = 0; + virtual gl::Error copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) = 0; + virtual gl::Error copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) = 0; + virtual gl::Error copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) = 0; + + virtual gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) = 0; + virtual gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) = 0; // 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, + virtual gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - ShaderExecutableD3D **outExecutable) = 0; + ShaderExecutableD3D **outExecutable) = 0; virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) = 0; + virtual gl::Error ensureHLSLCompilerInitialized() = 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 gl::Error generateMipmap(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source) = 0; + virtual gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) = 0; + virtual gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) = 0; virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0; - virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage) = 0; + virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) = 0; + virtual TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) = 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; virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + virtual TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) = 0; // Buffer-to-texture and Texture-to-buffer copies virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; - virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; + virtual gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) = 0; // Device lost - void notifyDeviceLost() override; + GLenum getResetStatus(); + void notifyDeviceLost(); virtual bool resetDevice() = 0; + virtual bool testDeviceLost() = 0; + virtual bool testDeviceResettable() = 0; + virtual RendererClass getRendererClass() const = 0; virtual void *getD3DDevice() = 0; - gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut); - - // 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; + GLint getGPUDisjoint(); + GLint64 getTimestamp(); - // In D3D11, faster than calling setTexture a jillion times - virtual gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) = 0; + virtual gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) = 0; virtual egl::Error getEGLDevice(DeviceImpl **device) = 0; bool presentPathFastEnabled() const { return mPresentPathFastEnabled; } + // Stream creation + virtual StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) = 0; + + const gl::Caps &getNativeCaps() const; + const gl::TextureCapsMap &getNativeTextureCaps() const; + const gl::Extensions &getNativeExtensions() const; + const gl::Limitations &getNativeLimitations() const; + + // Necessary hack for default framebuffers in D3D. + virtual FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) = 0; + + virtual gl::Version getMaxSupportedESVersion() const = 0; + + gl::Error initRenderTarget(RenderTargetD3D *renderTarget); + + angle::WorkerThreadPool *getWorkerThreadPool(); + + gl::Error getIncompleteTexture(const gl::Context *context, + GLenum type, + gl::Texture **textureOut); + + Serial generateSerial(); + + virtual bool canSelectViewInVertexShader() const = 0; + + gl::Error initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) override; + protected: virtual bool getLUID(LUID *adapterLuid) const = 0; - virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0; + virtual void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const = 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. + bool skipDraw(const gl::State &glState, GLenum drawMode); 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 FramebufferTextureArray; - - gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); - gl::Error generateSwizzles(const gl::Data &data); - - gl::Error applyState(const gl::Data &data, GLenum drawMode); - gl::Error applyShaders(const gl::Data &data, GLenum drawMode); - gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, - 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 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; + void ensureCapsInitialized() const; + + virtual angle::WorkaroundsD3D generateWorkarounds() const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mNativeCaps; + mutable gl::TextureCapsMap mNativeTextureCaps; + mutable gl::Extensions mNativeExtensions; + mutable gl::Limitations mNativeLimitations; + + IncompleteTextureSet mIncompleteTextures; mutable bool mWorkaroundsInitialized; - mutable WorkaroundsD3D mWorkarounds; + mutable angle::WorkaroundsD3D mWorkarounds; bool mDisjoint; + bool mDeviceLost; + + angle::WorkerThreadPool mWorkerThreadPool; + + SerialFactory mSerialFactory; }; -} +unsigned int GetBlendSampleMask(const gl::State &glState, int samples); +bool InstancedPointSpritesActive(ProgramD3D *programD3D, GLenum mode); + +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h index 7aabdc8132..3f8f5b9d8d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SamplerD3D.h @@ -17,7 +17,7 @@ namespace rx class SamplerD3D : public SamplerImpl { public: - SamplerD3D() {} + SamplerD3D(const gl::SamplerState &state) : SamplerImpl(state) {} ~SamplerD3D() override {} }; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp index 1ecbfb7410..2a8f1fb11c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp @@ -9,9 +9,11 @@ #include "libANGLE/renderer/d3d/ShaderD3D.h" #include "common/utilities.h" +#include "libANGLE/Caps.h" #include "libANGLE/Compiler.h" #include "libANGLE/Shader.h" #include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" // Definitions local to the translation unit @@ -28,6 +30,9 @@ const char *GetShaderTypeString(GLenum type) case GL_FRAGMENT_SHADER: return "FRAGMENT"; + case GL_COMPUTE_SHADER: + return "COMPUTE"; + default: UNREACHABLE(); return ""; @@ -39,9 +44,39 @@ const char *GetShaderTypeString(GLenum type) namespace rx { -ShaderD3D::ShaderD3D(const gl::Shader::Data &data) : ShaderImpl(data) +ShaderD3D::ShaderD3D(const gl::ShaderState &data, + const angle::WorkaroundsD3D &workarounds, + const gl::Extensions &extensions) + : ShaderImpl(data), mAdditionalOptions(0) { uncompile(); + + if (workarounds.expandIntegerPowExpressions) + { + mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS; + } + + if (workarounds.getDimensionsIgnoresBaseLevel) + { + mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL; + } + + if (workarounds.preAddTexelFetchOffsets) + { + mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH; + } + if (workarounds.rewriteUnaryMinusOperator) + { + mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR; + } + if (workarounds.emulateIsnanFloat) + { + mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION; + } + if (extensions.multiview) + { + mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; + } } ShaderD3D::~ShaderD3D() @@ -50,6 +85,11 @@ ShaderD3D::~ShaderD3D() std::string ShaderD3D::getDebugInfo() const { + if (mDebugInfo.empty()) + { + return ""; + } + return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER END\n"; } @@ -69,15 +109,16 @@ void ShaderD3D::uncompile() mUsesPointCoord = false; mUsesDepthRange = false; mUsesFragDepth = false; + mHasANGLEMultiviewEnabled = false; + mUsesViewID = false; mUsesDiscardRewriting = false; mUsesNestedBreak = false; - mUsesDeferredInit = false; mRequiresIEEEStrictCompiling = false; mDebugInfo.clear(); } -void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const +void ShaderD3D::generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const { if (mUsesDiscardRewriting) { @@ -106,10 +147,10 @@ unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const return mUniformRegisterMap.find(uniformName)->second; } -unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const +unsigned int ShaderD3D::getUniformBlockRegister(const std::string &blockName) const { - ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); - return mInterfaceBlockRegisterMap.find(blockName)->second; + ASSERT(mUniformBlockRegisterMap.count(blockName) > 0); + return mUniformBlockRegisterMap.find(blockName)->second; } ShShaderOutput ShaderD3D::getCompilerOutputType() const @@ -117,12 +158,12 @@ ShShaderOutput ShaderD3D::getCompilerOutputType() const return mCompilerOutputType; } -int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream, - std::string *sourcePath) +ShCompileOptions ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream, + std::string *sourcePath) { uncompile(); - int additionalOptions = 0; + ShCompileOptions additionalOptions = 0; const std::string &source = mData.getSource(); @@ -135,10 +176,24 @@ int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStre } #endif + additionalOptions |= mAdditionalOptions; + *shaderSourceStream << source; return additionalOptions; } +bool ShaderD3D::hasUniform(const std::string &name) const +{ + return mUniformRegisterMap.find(name) != mUniformRegisterMap.end(); +} + +const std::map &GetUniformRegisterMap( + const std::map *uniformRegisterMap) +{ + ASSERT(uniformRegisterMap); + return *uniformRegisterMap; +} + bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) { // TODO(jmadill): We shouldn't need to cache this. @@ -154,41 +209,30 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo 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; + mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mHasANGLEMultiviewEnabled = + translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos; + mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != 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; ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType()); - for (const sh::Uniform &uniform : mData.getUniforms()) - { - if (uniform.staticUse && !uniform.isBuiltIn()) - { - unsigned int index = static_cast(-1); - bool getUniformRegisterResult = - ShGetUniformRegister(compilerHandle, uniform.name, &index); - UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult); - ASSERT(getUniformRegisterResult); - - mUniformRegisterMap[uniform.name] = index; - } - } + mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle)); - for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks()) + for (const sh::InterfaceBlock &interfaceBlock : mData.getUniformBlocks()) { if (interfaceBlock.staticUse) { unsigned int index = static_cast(-1); bool blockRegisterResult = - ShGetInterfaceBlockRegister(compilerHandle, interfaceBlock.name, &index); - UNUSED_ASSERTION_VARIABLE(blockRegisterResult); + sh::GetUniformBlockRegister(compilerHandle, interfaceBlock.name, &index); ASSERT(blockRegisterResult); - mInterfaceBlockRegisterMap[interfaceBlock.name] = index; + mUniformBlockRegisterMap[interfaceBlock.name] = index; } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h index 47a73dc27b..f7b0b20db4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h @@ -13,31 +13,50 @@ #include +namespace angle +{ +struct CompilerWorkaroundsD3D; +struct WorkaroundsD3D; +} + +namespace gl +{ +struct Extensions; +} + namespace rx { class DynamicHLSL; class RendererD3D; -struct D3DCompilerWorkarounds; +struct D3DUniform; class ShaderD3D : public ShaderImpl { public: - ShaderD3D(const gl::Shader::Data &data); - virtual ~ShaderD3D(); + ShaderD3D(const gl::ShaderState &data, + const angle::WorkaroundsD3D &workarounds, + const gl::Extensions &extensions); + ~ShaderD3D() override; // ShaderImpl implementation - int prepareSourceAndReturnOptions(std::stringstream *sourceStream, - std::string *sourcePath) override; + ShCompileOptions 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 void uncompile(); + + bool hasUniform(const std::string &name) const; + + // Query regular uniforms with their name. Query sampler fields of structs with field selection + // using dot (.) operator. unsigned int getUniformRegister(const std::string &uniformName) const; - unsigned int getInterfaceBlockRegister(const std::string &blockName) const; + + unsigned int getUniformBlockRegister(const std::string &blockName) const; void appendDebugInfo(const std::string &info) const { mDebugInfo += info; } - void generateWorkarounds(D3DCompilerWorkarounds *workarounds) const; + void generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const; bool usesMultipleRenderTargets() const { return mUsesMultipleRenderTargets; } bool usesFragColor() const { return mUsesFragColor; } @@ -48,7 +67,8 @@ class ShaderD3D : public ShaderImpl bool usesPointCoord() const { return mUsesPointCoord; } bool usesDepthRange() const { return mUsesDepthRange; } bool usesFragDepth() const { return mUsesFragDepth; } - bool usesDeferredInit() const { return mUsesDeferredInit; } + bool usesViewID() const { return mUsesViewID; } + bool hasANGLEMultiviewEnabled() const { return mHasANGLEMultiviewEnabled; } ShShaderOutput getCompilerOutputType() const; @@ -62,16 +82,18 @@ class ShaderD3D : public ShaderImpl bool mUsesPointCoord; bool mUsesDepthRange; bool mUsesFragDepth; + bool mHasANGLEMultiviewEnabled; + bool mUsesViewID; bool mUsesDiscardRewriting; bool mUsesNestedBreak; - bool mUsesDeferredInit; bool mRequiresIEEEStrictCompiling; ShShaderOutput mCompilerOutputType; mutable std::string mDebugInfo; std::map mUniformRegisterMap; - std::map mInterfaceBlockRegisterMap; + std::map mUniformBlockRegisterMap; + ShCompileOptions mAdditionalOptions; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_SHADERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp index 97ffdf5094..83a66bd1a5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp @@ -44,9 +44,13 @@ void ShaderExecutableD3D::appendDebugInfo(const std::string &info) mDebugInfo += info; } - -UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mSize(initialSize) +UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mUniformData() { + bool result = mUniformData.resize(initialSize); + ASSERT(result); + + // Uniform data is zero-initialized by default. + mUniformData.fill(0); } UniformStorageD3D::~UniformStorageD3D() @@ -55,7 +59,13 @@ UniformStorageD3D::~UniformStorageD3D() size_t UniformStorageD3D::size() const { - return mSize; + return mUniformData.size(); } +uint8_t *UniformStorageD3D::getDataPointer(unsigned int registerIndex, unsigned int registerElement) +{ + size_t offset = ((registerIndex * 4 + registerElement) * sizeof(float)); + return mUniformData.data() + offset; } + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h index 71b83b7954..b8097710e2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h @@ -10,6 +10,7 @@ #ifndef LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ #define LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ +#include "common/MemoryBuffer.h" #include "common/debug.h" #include @@ -45,10 +46,12 @@ class UniformStorageD3D : angle::NonCopyable size_t size() const; + uint8_t *getDataPointer(unsigned int registerIndex, unsigned int registerElement); + private: - size_t mSize; + angle::MemoryBuffer mUniformData; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp index f567f47525..7657aef79e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -8,10 +8,11 @@ #include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Surface.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SwapChainD3D.h" #include @@ -21,60 +22,62 @@ 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, 0, EGL_FALSE, - shareHandle, NULL); -} - -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, orientation, - directComposition, static_cast(0), window); -} - -SurfaceD3D::SurfaceD3D(RendererD3D *renderer, +SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, egl::Display *display, - const egl::Config *config, - EGLint width, - EGLint height, - EGLint fixedSize, - EGLint orientation, - EGLint directComposition, - EGLClientBuffer shareHandle, - EGLNativeWindowType window) - : SurfaceImpl(), + EGLNativeWindowType window, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceImpl(state), mRenderer(renderer), mDisplay(display), - mFixedSize(fixedSize == EGL_TRUE), - mOrientation(orientation), - mRenderTargetFormat(config->renderTargetFormat), - mDepthStencilFormat(config->depthStencilFormat), + mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE), + mOrientation(static_cast(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))), + mRenderTargetFormat(state.config->renderTargetFormat), + mDepthStencilFormat(state.config->depthStencilFormat), mSwapChain(nullptr), mSwapIntervalDirty(true), mWindowSubclassed(false), - mNativeWindow(window, config, directComposition == EGL_TRUE), - mWidth(width), - mHeight(height), + mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)), + mWidth(static_cast(attribs.get(EGL_WIDTH, 0))), + mHeight(static_cast(attribs.get(EGL_HEIGHT, 0))), mSwapInterval(1), - mShareHandle(reinterpret_cast(shareHandle)) + mShareHandle(0), + mD3DTexture(nullptr) { subclassWindow(); + if (window != nullptr && !mFixedSize) + { + mWidth = -1; + mHeight = -1; + } + + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + mShareHandle = static_cast(clientBuffer); + break; + + case EGL_D3D_TEXTURE_ANGLE: + mD3DTexture = static_cast(clientBuffer); + ASSERT(mD3DTexture != nullptr); + mD3DTexture->AddRef(); + ANGLE_SWALLOW_ERR(mRenderer->getD3DTextureInfo(state.config, mD3DTexture, &mWidth, + &mHeight, &mRenderTargetFormat)); + break; + + default: + break; + } } SurfaceD3D::~SurfaceD3D() { unsubclassWindow(); releaseSwapChain(); + SafeDelete(mNativeWindow); + SafeRelease(mD3DTexture); } void SurfaceD3D::releaseSwapChain() @@ -82,41 +85,41 @@ void SurfaceD3D::releaseSwapChain() SafeDelete(mSwapChain); } -egl::Error SurfaceD3D::initialize() +egl::Error SurfaceD3D::initialize(const egl::Display *display) { - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - if (!mNativeWindow.initialize()) + if (!mNativeWindow->initialize()) { - return egl::Error(EGL_BAD_SURFACE); + return egl::EglBadSurface(); } } - egl::Error error = resetSwapChain(); - if (error.isError()) - { - return error; - } - - return egl::Error(EGL_SUCCESS); + ANGLE_TRY(resetSwapChain(display)); + return egl::NoError(); } -FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +FramebufferImpl *SurfaceD3D::createDefaultFramebuffer(const gl::FramebufferState &data) { - return mRenderer->createFramebuffer(data); + return mRenderer->createDefaultFramebuffer(data); } egl::Error SurfaceD3D::bindTexImage(gl::Texture *, EGLint) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } egl::Error SurfaceD3D::releaseTexImage(EGLint) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); +} + +egl::Error SurfaceD3D::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + return mSwapChain->getSyncValues(ust, msc, sbc); } -egl::Error SurfaceD3D::resetSwapChain() +egl::Error SurfaceD3D::resetSwapChain(const egl::Display *display) { ASSERT(!mSwapChain); @@ -126,11 +129,11 @@ egl::Error SurfaceD3D::resetSwapChain() if (!mFixedSize) { RECT windowRect; - if (!mNativeWindow.getClientRect(&windowRect)) + if (!mNativeWindow->getClientRect(&windowRect)) { ASSERT(false); - return egl::Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); + return egl::EglBadSurface() << "Could not retrieve the window dimensions"; } width = windowRect.right - windowRect.left; @@ -143,29 +146,34 @@ egl::Error SurfaceD3D::resetSwapChain() height = mHeight; } - mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, - mDepthStencilFormat, mOrientation); + mSwapChain = + mRenderer->createSwapChain(mNativeWindow, mShareHandle, mD3DTexture, mRenderTargetFormat, + mDepthStencilFormat, mOrientation, mState.config->samples); if (!mSwapChain) { - return egl::Error(EGL_BAD_ALLOC); + return egl::EglBadAlloc(); } - egl::Error error = resetSwapChain(width, height); + // This is a bit risky to pass the proxy context here, but it can happen at almost any time. + egl::Error error = resetSwapChain(display->getProxyContext(), width, height); if (error.isError()) { SafeDelete(mSwapChain); return error; } - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight) +egl::Error SurfaceD3D::resizeSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); - EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); + EGLint status = + mSwapChain->resize(context, std::max(1, backbufferWidth), std::max(1, backbufferHeight)); if (status == EGL_CONTEXT_LOST) { @@ -180,15 +188,18 @@ egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight mWidth = backbufferWidth; mHeight = backbufferHeight; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) +egl::Error SurfaceD3D::resetSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); - EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval); + EGLint status = mSwapChain->reset(context, std::max(1, backbufferWidth), + std::max(1, backbufferHeight), mSwapInterval); if (status == EGL_CONTEXT_LOST) { @@ -204,17 +215,20 @@ egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) mHeight = backbufferHeight; mSwapIntervalDirty = false; - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +egl::Error SurfaceD3D::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: eglPostSubBufferNV comes here if (x + width > mWidth) { width = mWidth - x; @@ -224,11 +238,10 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { height = mHeight - y; } -#endif if (width != 0 && height != 0) { - EGLint status = mSwapChain->swapRect(x, y, width, height); + EGLint status = mSwapChain->swapRect(context, x, y, width, height); if (status == EGL_CONTEXT_LOST) { @@ -241,34 +254,36 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) } } - checkForOutOfDateSwapChain(); + ANGLE_TRY(checkForOutOfDateSwapChain(context)); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } #if !defined(ANGLE_ENABLE_WINDOWS_STORE) #define kSurfaceProperty _TEXT("Egl::SurfaceOwner") #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") +#define kDisplayProperty _TEXT("Egl::Display") 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); + if (message == WM_SIZE) + { + SurfaceD3D* surf = reinterpret_cast(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + egl::Display *display = reinterpret_cast(GetProp(hwnd, kDisplayProperty)); + surf->checkForOutOfDateSwapChain(display->getProxyContext()); + } + } + 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(); + HWND window = mNativeWindow->getNativeWindow(); if (!window) { return; @@ -291,6 +306,7 @@ void SurfaceD3D::subclassWindow() SetProp(window, kSurfaceProperty, reinterpret_cast(this)); SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); + SetProp(window, kDisplayProperty, reinterpret_cast(mDisplay)); mWindowSubclassed = true; #endif } @@ -303,7 +319,7 @@ void SurfaceD3D::unsubclassWindow() } #if !defined(ANGLE_ENABLE_WINDOWS_STORE) - HWND window = mNativeWindow.getNativeWindow(); + HWND window = mNativeWindow->getNativeWindow(); if (!window) { return; @@ -320,30 +336,31 @@ void SurfaceD3D::unsubclassWindow() 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); + RemoveProp(window, kDisplayProperty); #endif mWindowSubclassed = false; } -bool SurfaceD3D::checkForOutOfDateSwapChain() + +egl::Error SurfaceD3D::checkForOutOfDateSwapChain(const gl::Context *context) { RECT client; int clientWidth = getWidth(); int clientHeight = getHeight(); bool sizeDirty = false; - if (!mFixedSize && !mNativeWindow.isIconic()) + if (!mFixedSize && !mNativeWindow->isIconic()) { // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized // because that's not a useful size to render to. - if (!mNativeWindow.getClientRect(&client)) + if (!mNativeWindow->getClientRect(&client)) { - ASSERT(false); - return false; + UNREACHABLE(); + return egl::NoError(); } // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. @@ -352,28 +369,30 @@ bool SurfaceD3D::checkForOutOfDateSwapChain() sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); } - bool wasDirty = (mSwapIntervalDirty || sizeDirty); - if (mSwapIntervalDirty) { - resetSwapChain(clientWidth, clientHeight); + ANGLE_TRY(resetSwapChain(context, clientWidth, clientHeight)); } else if (sizeDirty) { - resizeSwapChain(clientWidth, clientHeight); + ANGLE_TRY(resizeSwapChain(context, clientWidth, clientHeight)); } - return wasDirty; + return egl::NoError(); } -egl::Error SurfaceD3D::swap() +egl::Error SurfaceD3D::swap(const gl::Context *context) { - return swapRect(0, 0, mWidth, mHeight); + return swapRect(context, 0, 0, mWidth, mHeight); } -egl::Error SurfaceD3D::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +egl::Error SurfaceD3D::postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { - return swapRect(x, y, width, height); + return swapRect(context, x, y, width, height); } rx::SwapChainD3D *SurfaceD3D::getSwapChain() const @@ -429,13 +448,15 @@ egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) } else UNREACHABLE(); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } -gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { - if (target.binding() == GL_BACK) + if (binding == GL_BACK) { *rtOut = mSwapChain->getColorRenderTarget(); } @@ -443,7 +464,46 @@ gl::Error SurfaceD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment: { *rtOut = mSwapChain->getDepthStencilRenderTarget(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +WindowSurfaceD3D::WindowSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, + renderer, + display, + window, + 0, + static_cast(0), + attribs) +{ +} + +WindowSurfaceD3D::~WindowSurfaceD3D() +{ } +PbufferSurfaceD3D::PbufferSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) + : SurfaceD3D(state, + renderer, + display, + static_cast(0), + buftype, + clientBuffer, + attribs) +{ } + +PbufferSurfaceD3D::~PbufferSurfaceD3D() +{ +} + +} // namespace rc diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h index 67d408ddd9..01d2573244 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D_SURFACED3D_H_ #include "libANGLE/renderer/SurfaceImpl.h" -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" namespace egl { @@ -25,28 +25,22 @@ class RendererD3D; class SurfaceD3D : public SurfaceImpl { public: - 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 initialize(const egl::Display *display) override; + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; - egl::Error swap() override; - egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error swap(const gl::Context *context) override; + egl::Error postSubBuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override; egl::Error releaseTexImage(EGLint buffer) override; + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; void setSwapInterval(EGLint interval) override; EGLint getWidth() const override; @@ -58,29 +52,35 @@ class SurfaceD3D : public SurfaceImpl // D3D implementations SwapChainD3D *getSwapChain() const; - egl::Error resetSwapChain(); + egl::Error resetSwapChain(const egl::Display *display); - // Returns true if swapchain changed due to resize or interval update - bool checkForOutOfDateSwapChain(); + egl::Error checkForOutOfDateSwapChain(const gl::Context *context); - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; - private: - SurfaceD3D(RendererD3D *renderer, + protected: + SurfaceD3D(const egl::SurfaceState &state, + 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); + EGLNativeWindowType window, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs); + + egl::Error swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height); + egl::Error resetSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); + egl::Error resizeSwapChain(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); void subclassWindow(); void unsubclassWindow(); @@ -96,18 +96,41 @@ class SurfaceD3D : public SurfaceImpl SwapChainD3D *mSwapChain; bool mSwapIntervalDirty; - bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking - NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + NativeWindowD3D *mNativeWindow; // Handler for the Window that the surface is created for. EGLint mWidth; EGLint mHeight; EGLint mSwapInterval; HANDLE mShareHandle; + IUnknown *mD3DTexture; }; +class WindowSurfaceD3D : public SurfaceD3D +{ + public: + WindowSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLNativeWindowType window, + const egl::AttributeMap &attribs); + ~WindowSurfaceD3D() override; +}; -} +class PbufferSurfaceD3D : public SurfaceD3D +{ + public: + PbufferSurfaceD3D(const egl::SurfaceState &state, + RendererD3D *renderer, + egl::Display *display, + EGLenum buftype, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs); + ~PbufferSurfaceD3D() override; +}; + +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_SURFACED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp new file mode 100644 index 0000000000..de8534c3da --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainD3D.cpp: Defines a back-end specific class that hides the details of the +// implementation-specific swapchain. + +#include "libANGLE/renderer/d3d/SwapChainD3D.h" + +namespace rx +{ + +SwapChainD3D::SwapChainD3D(HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat) + : mOffscreenRenderTargetFormat(backBufferFormat), + mDepthBufferFormat(depthBufferFormat), + mShareHandle(shareHandle), + mD3DTexture(d3dTexture) +{ + if (mD3DTexture) + { + mD3DTexture->AddRef(); + } +} + +SwapChainD3D::~SwapChainD3D() +{ + SafeRelease(mD3DTexture); +} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h index 171cab54dd..017737b878 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h @@ -12,17 +12,26 @@ #include #include +#include #include "common/angleutils.h" #include "common/platform.h" - -// TODO: move out of D3D11 -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/Error.h" #if !defined(ANGLE_FORCE_VSYNC_OFF) #define ANGLE_FORCE_VSYNC_OFF 0 #endif +namespace gl +{ +class Context; +} // namespace gl + +namespace egl +{ +class Display; +} // namespace egl + namespace rx { class RenderTargetD3D; @@ -30,35 +39,45 @@ class RenderTargetD3D; class SwapChainD3D : angle::NonCopyable { public: - SwapChainD3D(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mNativeWindow(nativeWindow), mOffscreenRenderTargetFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat), mShareHandle(shareHandle) - { - } - - virtual ~SwapChainD3D() {}; - - virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + SwapChainD3D(HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat); + virtual ~SwapChainD3D(); + + virtual EGLint resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferSize) = 0; + virtual EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) = 0; + virtual EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) = 0; virtual void recreate() = 0; - virtual void *getDevice() { return NULL; } + virtual void *getDevice() { return nullptr; } virtual RenderTargetD3D *getColorRenderTarget() = 0; virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0; - GLenum GetRenderTargetInternalFormat() const { return mOffscreenRenderTargetFormat; } - GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } + GLenum getRenderTargetInternalFormat() const { return mOffscreenRenderTargetFormat; } + GLenum getDepthBufferInternalFormat() const { return mDepthBufferFormat; } HANDLE getShareHandle() { return mShareHandle; } virtual void *getKeyedMutex() = 0; + virtual egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) = 0; + protected: - rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. const GLenum mOffscreenRenderTargetFormat; const GLenum mDepthBufferFormat; HANDLE mShareHandle; + IUnknown *mD3DTexture; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp index 430576b318..bf44cbb5d2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -12,6 +12,7 @@ #include "common/utilities.h" #include "libANGLE/Buffer.h" #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" @@ -21,8 +22,8 @@ #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" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/TextureStorage.h" @@ -32,26 +33,24 @@ namespace rx namespace { -gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, - ptrdiff_t layerOffset, const uint8_t **pointerOut) +gl::Error GetUnpackPointer(const gl::Context *context, + const gl::PixelUnpackState &unpack, + gl::Buffer *unpackBuffer, + const uint8_t *pixels, + ptrdiff_t layerOffset, + const uint8_t **pointerOut) { - if (unpack.pixelBuffer.id() != 0) + if (unpackBuffer) { // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); ptrdiff_t offset = reinterpret_cast(pixels); // TODO: this is the only place outside of renderer that asks for a buffers raw data. // This functionality should be moved into renderer and the getData method of BufferImpl removed. - BufferD3D *bufferD3D = GetImplAs(pixelBuffer); + BufferD3D *bufferD3D = GetImplAs(unpackBuffer); ASSERT(bufferD3D); - const uint8_t *bufferData = NULL; - gl::Error error = bufferD3D->getData(&bufferData); - if (error.isError()) - { - return error; - } - + const uint8_t *bufferData = nullptr; + ANGLE_TRY(bufferD3D->getData(context, &bufferData)); *pointerOut = bufferData + offset; } else @@ -65,7 +64,7 @@ gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pi *pointerOut += layerOffset; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool IsRenderTargetUsage(GLenum usage) @@ -75,41 +74,66 @@ bool IsRenderTargetUsage(GLenum usage) } -TextureD3D::TextureD3D(RendererD3D *renderer) - : mRenderer(renderer), - mUsage(GL_NONE), +TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureImpl(state), + mRenderer(renderer), mDirtyImages(true), mImmutable(false), - mTexStorage(NULL) + mTexStorage(nullptr), + mBaseLevel(0) { } TextureD3D::~TextureD3D() { + ASSERT(!mTexStorage); } -gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) +gl::Error TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage) { // ensure the underlying texture is created - gl::Error error = initializeStorage(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initializeStorage(context, false)); if (mTexStorage) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } ASSERT(outStorage); *outStorage = mTexStorage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error TextureD3D::getImageAndSyncFromStorage(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D **outImage) +{ + ImageD3D *image = getImage(index); + if (mTexStorage && mTexStorage->isRenderTarget()) + { + ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage)); + mDirtyImages = true; + } + *outImage = image; + return gl::NoError(); +} + +GLint TextureD3D::getLevelZeroWidth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelWidth())) > getBaseLevel()); + return getBaseLevelWidth() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroHeight() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelHeight())) > getBaseLevel()); + return getBaseLevelHeight() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroDepth() const +{ + return getBaseLevelDepth(); } GLint TextureD3D::getBaseLevelWidth() const @@ -139,6 +163,27 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } +gl::Error TextureD3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + UNREACHABLE(); + return gl::InternalError(); +} + bool TextureD3D::shouldUseSetData(const ImageD3D *image) const { if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) @@ -146,7 +191,12 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return false; } - gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + if (image->isDirty()) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); // We can only handle full updates for depth-stencil textures, so to avoid complications // disable them entirely. @@ -159,173 +209,166 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return (mTexStorage && !internalFormat.compressed); } -gl::Error TextureD3D::setImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setImageImpl(const gl::Context *context, + const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { ImageD3D *image = getImage(index); + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(image); // No-op if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // 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; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); if (pixelData != nullptr) { if (shouldUseSetData(image)) { - error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + ANGLE_TRY( + mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData)); } else { gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); - error = image->loadData(fullImageArea, unpack, type, pixelData); - } - - if (error.isError()) - { - return error; + ANGLE_TRY( + image->loadData(context, fullImageArea, unpack, type, pixelData, index.is3D())); } mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::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 TextureD3D::subImage(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + ptrdiff_t layerOffset) { // CPU readback & copy where direct GPU copy is not supported - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { ImageD3D *image = getImage(index); ASSERT(image); if (shouldUseSetData(image)) { - return mTexStorage->setData(index, image, &area, type, unpack, pixelData); - } - - error = image->loadData(area, unpack, type, pixelData); - if (error.isError()) - { - return error; - } - - error = commitRegion(index, area); - if (error.isError()) - { - return error; + return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData); } + ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.is3D())); + ANGLE_TRY(commitRegion(context, index, area)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::setCompressedImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setCompressedImageImpl(const gl::Context *context, + const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { - // 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; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) + ImageD3D *image = getImage(index); + ASSERT(image); + + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return error; + return gl::NoError(); } - if (pixelData != NULL) - { - ImageD3D *image = getImage(index); - ASSERT(image); + // 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 = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); + if (pixelData != nullptr) + { gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); - error = image->loadCompressedData(fullImageArea, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, const uint8_t *pixels, +gl::Error TextureD3D::subImageCompressed(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset) { - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { ImageD3D *image = getImage(index); ASSERT(image); - error = image->loadCompressedData(area, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, area, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer, GLenum sizedInternalFormat) { - return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); + return unpackBuffer != nullptr && + mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); } -gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget) +gl::Error TextureD3D::fastUnpackPixels(const gl::Context *context, + 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"); + return gl::InternalError() << "Unimplemented pixel store parameters in fastUnpackPixels"; } // No-op if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // In order to perform the fast copy through the shader, we must have the right format, and be able @@ -334,18 +377,17 @@ gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uintptr_t offset = reinterpret_cast(pixels); - gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, static_cast(offset), destRenderTarget, sizedInternalFormat, type, destArea); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->fastCopyBufferToTexture(context, unpack, static_cast(offset), + destRenderTarget, sizedInternalFormat, type, + destArea)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const { - if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || + mRenderer->getNativeExtensions().textureNPOT) { // Maximum number of levels return gl::log2(std::max(std::max(width, height), depth)) + 1; @@ -357,11 +399,6 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c } } -int TextureD3D::mipLevels() const -{ - return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; -} - TextureStorage *TextureD3D::getStorage() { ASSERT(mTexStorage); @@ -370,72 +407,60 @@ TextureStorage *TextureD3D::getStorage() ImageD3D *TextureD3D::getBaseLevelImage() const { - return getImage(getImageIndex(0, 0)); + if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return nullptr; + } + return getImage(getImageIndex(mBaseLevel, 0)); } -gl::Error TextureD3D::generateMipmaps(const gl::TextureState &textureState) +gl::Error TextureD3D::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - GLint mipCount = mipLevels(); + // Only external images can accept external textures + UNREACHABLE(); + return gl::InternalError(); +} - if (mipCount == 1) - { - return gl::Error(GL_NO_ERROR); // no-op - } +gl::Error TextureD3D::generateMipmap(const gl::Context *context) +{ + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + ASSERT(maxLevel > baseLevel); // Should be checked before calling this. if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround) { // Switch to using the mipmapped texture. - TextureStorage *textureStorage = NULL; - gl::Error error = getNativeTexture(&textureStorage); - if (error.isError()) - { - return error; - } - - error = textureStorage->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + TextureStorage *textureStorage = nullptr; + ANGLE_TRY(getNativeTexture(context, &textureStorage)); + ANGLE_TRY(textureStorage->useLevelZeroWorkaroundTexture(context, false)); } // Set up proper mipmap chain in our Image array. - initMipmapsImages(); + ANGLE_TRY(initMipmapImages(context)); if (mTexStorage && mTexStorage->supportsNativeMipmapFunction()) { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); // Generate the mipmap chain using the ad-hoc DirectX function. - error = mRenderer->generateMipmapsUsingD3D(mTexStorage, textureState); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState)); } else { // Generate the mipmap chain, one level at a time. - gl::Error error = generateMipmapsUsingImages(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(generateMipmapUsingImages(context, maxLevel)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::generateMipmapsUsingImages() +gl::Error TextureD3D::generateMipmapUsingImages(const gl::Context *context, const GLuint maxLevel) { - GLint mipCount = mipLevels(); - // We know that all layers have the same dimension, for the texture to be complete - GLint layerCount = static_cast(getLayerCount(0)); + GLint layerCount = static_cast(getLayerCount(mBaseLevel)); // When making mipmaps with the setData workaround enabled, the texture storage has // the image data already. For non-render-target storage, we have to pull it out into @@ -447,23 +472,15 @@ gl::Error TextureD3D::generateMipmapsUsingImages() // Copy from the storage mip 0 to Image mip 0 for (GLint layer = 0; layer < layerCount; ++layer) { - gl::ImageIndex srcIndex = getImageIndex(0, layer); + gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer); ImageD3D *image = getImage(srcIndex); - gl::Error error = image->copyFromTexStorage(srcIndex, mTexStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage)); } } else { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } } @@ -476,7 +493,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages() for (GLint layer = 0; layer < layerCount; ++layer) { - for (GLint mip = 1; mip < mipCount; ++mip) + for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip) { ASSERT(getLayerCount(mip) == layerCount); @@ -486,30 +503,25 @@ gl::Error TextureD3D::generateMipmapsUsingImages() if (renderableStorage) { // GPU-side mipmapping - gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex)); } else { // CPU-side mipmapping - gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex))); } } } + mDirtyImages = true; + if (mTexStorage) { - updateStorage(); + ANGLE_TRY(updateStorage(context)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::isBaseImageZeroSize() const @@ -531,7 +543,7 @@ bool TextureD3D::isBaseImageZeroSize() const return true; } - if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(getBaseLevel()) <= 0) { return true; } @@ -539,12 +551,16 @@ bool TextureD3D::isBaseImageZeroSize() const return false; } -gl::Error TextureD3D::ensureRenderTarget() +gl::Error TextureD3D::ensureRenderTarget(const gl::Context *context) { - gl::Error error = initializeStorage(true); - if (error.isError()) + ANGLE_TRY(initializeStorage(context, true)); + + // initializeStorage can fail with NoError if the texture is not complete. This is not + // an error for incomplete sampling, but it is a big problem for rendering. + if (!mTexStorage) { - return error; + UNREACHABLE(); + return gl::InternalError() << "Cannot render to incomplete texture."; } if (!isBaseImageZeroSize()) @@ -552,94 +568,210 @@ gl::Error TextureD3D::ensureRenderTarget() ASSERT(mTexStorage); if (!mTexStorage->isRenderTarget()) { - TextureStorage *newRenderTargetStorage = NULL; - error = createCompleteStorage(true, &newRenderTargetStorage); - if (error.isError()) - { - return error; - } - - error = mTexStorage->copyToStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } + TexStoragePointer newRenderTargetStorage(context); + ANGLE_TRY(createCompleteStorage(true, &newRenderTargetStorage)); - error = setCompleteTexStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } + ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get())); + ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get())); + newRenderTargetStorage.release(); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const { + if (index.type == GL_TEXTURE_2D_MULTISAMPLE) + return true; + ImageD3D *image = getImage(index); + ASSERT(image); bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); return (image->isRenderableFormat() && levelsComplete); } -gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error TextureD3D::commitRegion(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box ®ion) { if (mTexStorage) { ASSERT(isValidIndex(index)); ImageD3D *image = getImage(index); - gl::Error error = image->copyToStorage(mTexStorage, index, region); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region)); image->markClean(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error TextureD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum /*binding*/, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { RenderTargetD3D *rtD3D = nullptr; - gl::Error error = getRenderTarget(target.textureIndex(), &rtD3D); + gl::Error error = getRenderTarget(context, imageIndex, &rtD3D); *rtOut = static_cast(rtD3D); return error; } -TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) - : TextureD3D(renderer) +gl::Error TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel) +{ + const int oldStorageWidth = std::max(1, getLevelZeroWidth()); + const int oldStorageHeight = std::max(1, getLevelZeroHeight()); + const int oldStorageDepth = std::max(1, getLevelZeroDepth()); + const int oldStorageFormat = getBaseLevelInternalFormat(); + mBaseLevel = baseLevel; + + // When the base level changes, the texture storage might not be valid anymore, since it could + // have been created based on the dimensions of the previous specified level range. + const int newStorageWidth = std::max(1, getLevelZeroWidth()); + const int newStorageHeight = std::max(1, getLevelZeroHeight()); + const int newStorageDepth = std::max(1, getLevelZeroDepth()); + const int newStorageFormat = getBaseLevelInternalFormat(); + if (mTexStorage && + (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight || + newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat)) + { + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); + } + + return gl::NoError(); +} + +void TextureD3D::syncState(const gl::Texture::DirtyBits &dirtyBits) +{ + // TODO(geofflang): Use dirty bits +} + +gl::Error TextureD3D::releaseTexStorage(const gl::Context *context) +{ + if (!mTexStorage) + { + return gl::NoError(); + } + auto err = mTexStorage->onDestroy(context); + SafeDelete(mTexStorage); + return err; +} + +gl::Error TextureD3D::onDestroy(const gl::Context *context) +{ + return releaseTexStorage(context); +} + +gl::Error TextureD3D::initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndexIn) +{ + gl::ImageIndex imageIndex = imageIndexIn; + + // Special case for D3D11 3D textures. We can't create render targets for individual layers of a + // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we + // would lose existing data. + if (imageIndex.type == GL_TEXTURE_3D) + { + imageIndex.layerIndex = gl::ImageIndex::ENTIRE_LEVEL; + } + else if (imageIndex.type == GL_TEXTURE_2D_ARRAY && + imageIndex.layerIndex == gl::ImageIndex::ENTIRE_LEVEL) + { + GLsizei layerCount = getLayerCount(imageIndex.mipIndex); + for (imageIndex.layerIndex = 0; imageIndex.layerIndex < layerCount; ++imageIndex.layerIndex) + { + ANGLE_TRY(initializeContents(context, imageIndex)); + } + return gl::NoError(); + } + + // Force image clean. + ImageD3D *image = getImage(imageIndex); + if (image) + { + image->markClean(); + } + + // Fast path: can use a render target clear. + if (canCreateRenderTargetForImage(imageIndex)) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(mTexStorage); + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(mTexStorage->getRenderTarget(context, imageIndex, &renderTarget)); + ANGLE_TRY(mRenderer->initRenderTarget(renderTarget)); + return gl::NoError(); + } + + // Slow path: non-renderable texture or the texture levels aren't set up. + const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); + + size_t imageBytes = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(formatInfo.type, image->getWidth(), 1, 0), + imageBytes); + imageBytes *= image->getHeight() * image->getDepth(); + + gl::PixelUnpackState defaultUnpackState; + + angle::MemoryBuffer *zeroBuffer = nullptr; + ANGLE_TRY(context->getZeroFilledBuffer(imageBytes, &zeroBuffer)); + if (shouldUseSetData(image)) + { + ANGLE_TRY(mTexStorage->setData(context, imageIndex, image, nullptr, formatInfo.type, + defaultUnpackState, zeroBuffer->data())); + } + else + { + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + ANGLE_TRY(image->loadData(context, fullImageArea, defaultUnpackState, formatInfo.type, + zeroBuffer->data(), false)); + + // Force an update to the tex storage so we avoid problems with subImage and dirty regions. + if (mTexStorage) + { + ANGLE_TRY(commitRegion(context, imageIndex, fullImageArea)); + image->markClean(); + } + else + { + mDirtyImages = true; + } + } + return gl::NoError(); +} + +TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { mEGLImageTarget = false; - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (auto &image : mImageArray) { - mImageArray[i] = renderer->createImage(); + image.reset(renderer->createImage()); } } -TextureD3D_2D::~TextureD3D_2D() +gl::Error TextureD3D_2D::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &image : mImageArray) { - delete mImageArray[i]; + image.reset(); } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_2D::~TextureD3D_2D() +{ } ImageD3D *TextureD3D_2D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const @@ -647,7 +779,7 @@ ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(!index.hasLayer()); ASSERT(index.type == GL_TEXTURE_2D); - return mImageArray[index.mipIndex]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_2D::getLayerCount(int level) const @@ -682,10 +814,16 @@ GLenum TextureD3D_2D::getInternalFormat(GLint level) const bool TextureD3D_2D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +bool TextureD3D_2D::isSRGB(GLint level) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; } -gl::Error TextureD3D_2D::setImage(GLenum target, +gl::Error TextureD3D_2D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -696,33 +834,29 @@ gl::Error TextureD3D_2D::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D && size.depth == 1); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); bool fastUnpacked = false; GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size, false); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::Make2D(level); // Attempt a fast gpu copy of the pixel data to the surface - if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && + isLevelComplete(level)) { // Will try to create RT storage if it does not exist - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -732,17 +866,14 @@ gl::Error TextureD3D_2D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setSubImage(GLenum target, +gl::Error TextureD3D_2D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -754,26 +885,26 @@ gl::Error TextureD3D_2D::setSubImage(GLenum target, GLint level = static_cast(imageLevel); gl::ImageIndex index = gl::ImageIndex::Make2D(level); - if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) - { - RenderTargetD3D *renderTarget = NULL; - gl::Error error = getRenderTarget(index, &renderTarget); - if (error.isError()) - { - return error; - } + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &renderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + renderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_2D::setCompressedImage(GLenum target, +gl::Error TextureD3D_2D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -785,84 +916,120 @@ gl::Error TextureD3D_2D::setCompressedImage(GLenum target, 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, false); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - return setCompressedImageImpl(gl::ImageIndex::Make2D(level), unpack, pixels, 0); + return setCompressedImageImpl(context, 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, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + 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(static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); - return commitRegion(index, area); + return commitRegion(context, index, area); } -gl::Error TextureD3D_2D::copyImage(GLenum target, +gl::Error TextureD3D_2D::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, 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), - false); + GLint level = static_cast(imageLevel); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); + gl::Extents sourceExtents(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, sourceExtents, + false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && + (context->getExtensions().webglCompatibility || context->isRobustResourceInitEnabled())) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, sourceExtents, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 0); // 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]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level)) { - error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::copySubImage(GLenum target, +gl::Error TextureD3D_2D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { - ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0); + ASSERT(target == GL_TEXTURE_2D && origDestOffset.z == 0); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 0); // 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) @@ -874,174 +1041,287 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (isValidLevel(level)) { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage2D(source, sourceArea, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2D::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) { - ASSERT(GL_TEXTURE_2D && size.depth == 1); + ASSERT(target == GL_TEXTURE_2D); - for (size_t level = 0; level < levels; level++) - { - gl::Extents levelSize(std::max(1, size.width >> level), - std::max(1, size.height >> level), - 1); - redefineImage(level, internalFormat, levelSize, true); - } + GLenum sourceTarget = source->getTarget(); - for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); - } + GLint destLevel = static_cast(level); - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage2D( - internalFormat, renderTarget, size.width, size.height, static_cast(levels), false); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY( + redefineImage(context, destLevel, internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) { - SafeDelete(storage); - return error; + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - error = updateStorage(); + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); - mImmutable = true; + mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2D::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) { - GLenum internalformat = surface->getConfig()->renderTargetFormat; + ASSERT(target == GL_TEXTURE_2D); - gl::Extents size(surface->getWidth(), surface->getHeight(), 1); - redefineImage(0, internalformat, size, true); + GLint destLevel = static_cast(level); - if (mTexStorage) + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel)), destOffset, mTexStorage, target, + destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source) +{ + GLenum sourceTarget = source->getTarget(); + GLint sourceLevel = 0; + + GLint destLevel = 0; + + GLenum sizedInternalFormat = + source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat; + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false)); + + ANGLE_TRY(initializeStorage(context, false)); + ASSERT(mTexStorage); + + ANGLE_TRY( + mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel)); + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + ASSERT(GL_TEXTURE_2D && size.depth == 1); + + for (size_t level = 0; level < levels; level++) + { + gl::Extents levelSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + 1); + ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true)); + } + + for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - SafeDelete(mTexStorage); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, + size.height, static_cast(levels), false)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ANGLE_TRY(updateStorage(context)); + + mImmutable = true; + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + GLenum internalformat = surface->getConfig()->renderTargetFormat; + + gl::Extents size(surface->getWidth(), surface->getHeight(), 1); + ANGLE_TRY(redefineImage(context, 0, internalformat, size, true)); + + ANGLE_TRY(releaseTexStorage(context)); + SurfaceD3D *surfaceD3D = GetImplAs(surface); ASSERT(surfaceD3D); mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); mEGLImageTarget = false; - mDirtyImages = true; + mDirtyImages = false; + mImageArray[0]->markClean(); + + return gl::NoError(); } -void TextureD3D_2D::releaseTexImage() +gl::Error TextureD3D_2D::releaseTexImage(const gl::Context *context) { if (mTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); } for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - redefineImage(i, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true)); } + + return gl::NoError(); } -gl::Error TextureD3D_2D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2D::setEGLImageTarget(const gl::Context *context, + 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(); + const auto &format = image->getFormat(); gl::Extents size(static_cast(image->getWidth()), static_cast(image->getHeight()), 1); - redefineImage(0, internalformat, size, true); + ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true)); // Clear all other images. - for (size_t level = 1; level < ArraySize(mImageArray); level++) + for (size_t level = 1; level < mImageArray.size(); level++) { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mImageArray[0]->markClean(); - mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d); + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); mEGLImageTarget = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::initMipmapsImages() +gl::Error TextureD3D_2D::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - 1); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), 1); - redefineImage(level, getBaseLevelInternalFormat(), levelSize, false); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + return gl::NoError(); } -gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } bool TextureD3D_2D::isValidLevel(int level) const @@ -1056,10 +1336,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const return true; } - const ImageD3D *baseImage = getBaseLevelImage(); - - GLsizei width = baseImage->getWidth(); - GLsizei height = baseImage->getHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); if (width <= 0 || height <= 0) { @@ -1067,15 +1345,16 @@ bool TextureD3D_2D::isLevelComplete(int level) const } // The base image level is complete if the width and height are positive - if (level == 0) + if (level == static_cast(getBaseLevel())) { return true; } - ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ImageD3D *image = mImageArray[level]; + ASSERT(level >= 0 && level <= static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); + ImageD3D *image = mImageArray[level].get(); - if (image->getInternalFormat() != baseImage->getInternalFormat()) + if (image->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } @@ -1099,52 +1378,41 @@ bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const } // Constructs a native texture resource from the texture images -gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2D::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0); @@ -1165,84 +1433,83 @@ gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage } // TODO(geofflang): Determine if the texture creation succeeded - *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, + levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2D::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level)); } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorage() +gl::Error TextureD3D_2D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorageLevel(int level) +gl::Error TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level <= static_cast(mImageArray.size()) && mImageArray[level] != nullptr); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make2D(level); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease) +gl::Error TextureD3D_2D::redefineImage(const gl::Context *context, + size_t level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { ASSERT(size.depth == 1); // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); if (mTexStorage) { @@ -1252,27 +1519,23 @@ void TextureD3D_2D::redefineImage(size_t level, // while orphaning if (level != 0 && mEGLImageTarget) { - // TODO(jmadill): Don't discard error. - mImageArray[0]->copyFromTexStorage(gl::ImageIndex::Make2D(0), mTexStorage); + ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0), + mTexStorage)); } - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + internalformat != storageFormat) // Discard mismatched storage { - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; + ANGLE_TRY(releaseTexStorage(context)); + markAllImagesDirty(); } } // Can't be an EGL image target after being redefined mEGLImageTarget = false; + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2D::imageIterator() const @@ -1292,46 +1555,58 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_2D::markAllImagesDirty() +{ + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - for (int i = 0; i < 6; i++) + for (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - mImageArray[i][j] = renderer->createImage(); + image.reset(renderer->createImage()); } } } -TextureD3D_Cube::~TextureD3D_Cube() +gl::Error TextureD3D_Cube::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < 6; i++) + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - SafeDelete(mImageArray[i][j]); + image.reset(); } } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_Cube::~TextureD3D_Cube() +{ } ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer >= 0 && layer < 6); - return mImageArray[layer][level]; + return mImageArray[layer][level].get(); } ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const { ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(index.layerIndex >= 0 && index.layerIndex < 6); - return mImageArray[index.layerIndex][index.mipIndex]; + return mImageArray[index.layerIndex][index.mipIndex].get(); } GLsizei TextureD3D_Cube::getLayerCount(int level) const @@ -1350,128 +1625,191 @@ GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const { - return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; } -gl::Error TextureD3D_Cube::setEGLImageTarget(GLenum target, egl::Image *image) +bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB; +} + +gl::Error TextureD3D_Cube::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -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) +gl::Error TextureD3D_Cube::setImage(const gl::Context *context, + 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); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - redefineImage(index.layerIndex, static_cast(level), sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, index.layerIndex, static_cast(level), + internalFormatInfo.sizedInternalFormat, size, false)); - return setImageImpl(index, type, unpack, pixels, 0); + return setImageImpl(context, index, type, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::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_Cube::setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) { ASSERT(area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, 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, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + 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(static_cast(faceIndex), static_cast(level), internalFormat, size); + ANGLE_TRY(redefineImage(context, static_cast(faceIndex), static_cast(level), + internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast(level)); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + 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, static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_Cube::copyImage(GLenum target, +gl::Error TextureD3D_Cube::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, GLenum internalFormat, const gl::Framebuffer *source) { int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); GLint level = static_cast(imageLevel); - gl::Extents size(sourceArea.width, sourceArea.height, 1); - redefineImage(static_cast(faceIndex), level, sizedInternalFormat, size); + gl::Extents size(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, static_cast(faceIndex), level, + internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && context->getExtensions().webglCompatibility && + !context->isRobustResourceInitEnabled()) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, size, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 0); // 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]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[faceIndex][level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); ASSERT(size.width == size.height); if (size.width > 0 && isValidFaceLevel(faceIndex, level)) { - error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, target, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::copySubImage(GLenum target, +gl::Error TextureD3D_Cube::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 0); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); GLint level = static_cast(imageLevel); @@ -1481,44 +1819,145 @@ gl::Error TextureD3D_Cube::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = - mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); + mDirtyImages = true; + } + else + { + ANGLE_TRY(ensureRenderTarget(context)); + if (isValidFaceLevel(faceIndex, level)) { - return error; + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, target, level)); } + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLenum sourceTarget = source->getTarget(); + + GLint destLevel = static_cast(level); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast(source->getWidth(sourceTarget, sourceLevel)), + static_cast(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, faceIndex, destLevel, internalFormatInfo.sizedInternalFormat, + size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLint destLevel = static_cast(level); + int faceIndex = static_cast(gl::CubeMapTextureTargetToLayerIndex(target)); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel, faceIndex)), destOffset, mTexStorage, + target, destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - if (isValidFaceLevel(faceIndex, level)) - { - error = updateStorageFaceLevel(faceIndex, level); - if (error.isError()) - { - return error; - } + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_Cube::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(size.width == size.height); ASSERT(size.depth == 1); @@ -1541,28 +1980,20 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); - TextureStorage *storage = mRenderer->createTextureStorageCube( - internalFormat, renderTarget, size.width, static_cast(levels), false); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, + static_cast(levels), false)); - error = updateStorage(); + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -1579,7 +2010,7 @@ bool TextureD3D_Cube::isCubeComplete() const for (int faceIndex = 1; faceIndex < 6; faceIndex++) { - const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()]; if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight || @@ -1592,97 +2023,85 @@ bool TextureD3D_Cube::isCubeComplete() const return true; } -void TextureD3D_Cube::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_Cube::releaseTexImage() +gl::Error TextureD3D_Cube::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_Cube::initMipmapsImages() +gl::Error TextureD3D_Cube::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. for (int faceIndex = 0; faceIndex < 6; faceIndex++) { - for (int level = 1; level < levelCount; level++) + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); - redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), - gl::Extents(faceLevelSize, faceLevelSize, 1)); + int faceLevelSize = + (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1)); + ANGLE_TRY(redefineImage(context, faceIndex, level, + mImageArray[faceIndex][baseLevel]->getInternalFormat(), + gl::Extents(faceLevelSize, faceLevelSize, 1), false)); } } + return gl::NoError(); } -gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(gl::IsCubeMapTextureTarget(index.type)); // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageFaceLevel(context, index.layerIndex, index.mipIndex)); - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) +gl::Error TextureD3D_Cube::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isFaceLevelComplete(0, 0)) + if (!isFaceLevelComplete(0, getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei size = getBaseLevelWidth(); + GLsizei size = getLevelZeroWidth(); ASSERT(size > 0); @@ -1705,12 +2124,14 @@ gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStora } // TODO (geofflang): detect if storage creation succeeded - *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorageCube( + getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { @@ -1718,25 +2139,27 @@ gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexS { for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube( + context, newCompleteTexStorage, faceIndex, level)); } } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::updateStorage() +gl::Error TextureD3D_Cube::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int face = 0; face < 6; face++) { @@ -1744,16 +2167,13 @@ gl::Error TextureD3D_Cube::updateStorage() { if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) { - gl::Error error = updateStorageFaceLevel(face, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageFaceLevel(context, face, level)); } } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const @@ -1763,16 +2183,21 @@ bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return false; + } + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); if (isImmutable()) { return true; } - int baseSize = getBaseLevelWidth(); + int levelZeroSize = getLevelZeroWidth(); - if (baseSize <= 0) + if (levelZeroSize <= 0) { return false; } @@ -1786,14 +2211,14 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const } // Check that non-zero levels are consistent with the base level. - const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get(); if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } - if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level)) { return false; } @@ -1806,57 +2231,55 @@ bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const return isFaceLevelComplete(index.layerIndex, index.mipIndex); } -gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context, + int faceIndex, + int level) { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); - ImageD3D *image = mImageArray[faceIndex][level]; + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); + ImageD3D *image = mImageArray[faceIndex][level].get(); if (image->isDirty()) { GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex); gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_Cube::redefineImage(const gl::Context *context, + int faceIndex, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty(); if (mTexStorage) { const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + internalformat != storageFormat) // Discard mismatched storage { - for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) - { - for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) - { - mImageArray[dirtyFace][dirtyLevel]->markDirty(); - } - } - - SafeDelete(mTexStorage); - - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const @@ -1876,33 +2299,48 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_Cube::markAllImagesDirty() { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) { - mImageArray[i] = renderer->createImage(); + for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) + { + mImageArray[dirtyFace][dirtyLevel]->markDirty(); + } } + mDirtyImages = true; } -TextureD3D_3D::~TextureD3D_3D() +TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) { - delete mImageArray[i]; + mImageArray[i].reset(renderer->createImage()); } +} - SafeDelete(mTexStorage); +gl::Error TextureD3D_3D::onDestroy(const gl::Context *context) +{ + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &image : mImageArray) + { + image.reset(); + } + return TextureD3D::onDestroy(context); +} + +TextureD3D_3D::~TextureD3D_3D() +{ } ImageD3D *TextureD3D_3D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const @@ -1910,7 +2348,7 @@ ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(!index.hasLayer()); ASSERT(index.type == GL_TEXTURE_3D); - return mImageArray[index.mipIndex]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_3D::getLayerCount(int level) const @@ -1953,16 +2391,19 @@ GLenum TextureD3D_3D::getInternalFormat(GLint level) const bool TextureD3D_3D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_3D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_3D::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_3D::setImage(GLenum target, +gl::Error TextureD3D_3D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -1972,33 +2413,29 @@ gl::Error TextureD3D_3D::setImage(GLenum target, const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); bool fastUnpacked = false; 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 - if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty()) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && !size.empty() && + isLevelComplete(level)) { // Will try to create RT storage if it does not exist - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -2008,17 +2445,14 @@ gl::Error TextureD3D_3D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setSubImage(GLenum target, +gl::Error TextureD3D_3D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2032,26 +2466,25 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target, 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 - if (isFastUnpackable(unpack, getInternalFormat(level))) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) { - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + destRenderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_3D::setCompressedImage(GLenum target, +gl::Error TextureD3D_3D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2063,35 +2496,41 @@ gl::Error TextureD3D_3D::setCompressedImage(GLenum target, 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); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::Make3D(level); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_3D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); gl::ImageIndex index = gl::ImageIndex::Make3D(static_cast(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_3D::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); + return gl::InternalError() << "Copying 3D textures is unimplemented."; } -gl::Error TextureD3D_3D::copySubImage(GLenum target, +gl::Error TextureD3D_3D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2099,49 +2538,47 @@ gl::Error TextureD3D_3D::copySubImage(GLenum target, { ASSERT(target == GL_TEXTURE_3D); - GLint level = static_cast(imageLevel); - gl::ImageIndex index = gl::ImageIndex::Make3D(level); + GLint level = static_cast(imageLevel); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } + return gl::NoError(); + } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); - mDirtyImages = true; + // Currently, copying directly to the storage is not possible because it's not possible to + // create an SRV from a single layer of a 3D texture. Instead, make sure the image is up to + // date before the copy and then copy back to the storage afterwards if needed. + // TODO: Investigate 3D blits in D3D11. + + bool syncTexStorage = mTexStorage && isLevelComplete(level); + if (syncTexStorage) + { + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + ANGLE_TRY(mImageArray[level]->copyFromTexStorage(context, index, mTexStorage)); } - else + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, clippedDestOffset, clippedSourceArea, + source)); + mDirtyImages = true; + + if (syncTexStorage) { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage3D(source, sourceArea, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } + ANGLE_TRY(updateStorageLevel(context, level)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_3D); @@ -2159,130 +2596,106 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = - mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, - size.depth, static_cast(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_3D::releaseTexImage() +gl::Error TextureD3D_3D::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_3D::initMipmapsImages() +gl::Error TextureD3D_3D::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - std::max(getBaseLevelDepth() >> level, 1)); - redefineImage(level, getBaseLevelInternalFormat(), levelSize); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), + std::max(getLevelZeroDepth() >> level, 1)); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_3D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (index.hasLayer()) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } else { - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); } - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_3D::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2291,40 +2704,44 @@ gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); // TODO: Verify creation of the storage succeeded - *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, + depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_3D::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; // We do not support managed 3D storage, as that is D3D9/ES2-only ASSERT(!mTexStorage->isManaged()); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::updateStorage() +gl::Error TextureD3D_3D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_3D::isValidLevel(int level) const @@ -2334,28 +2751,29 @@ bool TextureD3D_3D::isValidLevel(int level) const bool TextureD3D_3D::isLevelComplete(int level) const { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); if (isImmutable()) { return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); if (width <= 0 || height <= 0 || depth <= 0) { return false; } - if (level == 0) + if (level == static_cast(getBaseLevel())) { return true; } - ImageD3D *levelImage = mImageArray[level]; + ImageD3D *levelImage = mImageArray[level].get(); if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) { @@ -2385,54 +2803,51 @@ bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_3D::updateStorageLevel(int level) +gl::Error TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast(mImageArray.size()) && + mImageArray[level] != nullptr); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make3D(level); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_3D::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = std::max(1, getBaseLevelDepth() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const int storageDepth = std::max(1, getLevelZeroDepth() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); + mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); if (mTexStorage) { const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || - size.height != storageHeight || - size.depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || + size.height != storageHeight || size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_3D::imageIterator() const @@ -2453,23 +2868,42 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_3D::markAllImagesDirty() +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +GLint TextureD3D_3D::getLevelZeroDepth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast(getBaseLevelDepth())) > getBaseLevel()); + return getBaseLevelDepth() << getBaseLevel(); +} + +TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) { mLayerCounts[level] = 0; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; } } -TextureD3D_2DArray::~TextureD3D_2DArray() +gl::Error TextureD3D_2DArray::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. deleteImages(); - SafeDelete(mTexStorage); + return TextureD3D::onDestroy(context); +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ } ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const @@ -2477,16 +2911,17 @@ ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]); - return (mImageArray[level] ? mImageArray[level][layer] : NULL); + return (mImageArray[level] ? mImageArray[level][layer] : nullptr); } ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const { ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(index.layerIndex != gl::ImageIndex::ENTIRE_LEVEL); ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) || index.layerIndex < mLayerCounts[index.mipIndex]); ASSERT(index.type == GL_TEXTURE_2D_ARRAY); - return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL); + return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : nullptr); } GLsizei TextureD3D_2DArray::getLayerCount(int level) const @@ -2512,16 +2947,19 @@ GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const bool TextureD3D_2DArray::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_2DArray::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_2DArray::setImage(GLenum target, +gl::Error TextureD3D_2DArray::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2532,30 +2970,28 @@ gl::Error TextureD3D_2DArray::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D_ARRAY); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, formatInfo.sizedInternalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch( - type, size.width, size.height, unpack.alignment, unpack.rowLength, unpack.imageHeight); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); 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 = setImageImpl(index, type, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setSubImage(GLenum target, +gl::Error TextureD3D_2DArray::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2565,9 +3001,12 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, { 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, unpack.imageHeight); + const gl::InternalFormat &formatInfo = + gl::GetInternalFormatInfo(getInternalFormat(level), type); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2577,17 +3016,15 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImage(context, index, layerArea, format, type, unpack, pixels, + layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, +gl::Error TextureD3D_2DArray::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2599,35 +3036,41 @@ gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, 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); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - GLsizei inputDepthPitch = - formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0), + inputDepthPitch); 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 = setCompressedImageImpl(index, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setCompressedImageImpl(context, index, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2637,30 +3080,27 @@ 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(static_cast(level), layer); - gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } - - error = commitRegion(index, layerArea); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, layerArea, format, unpack, pixels, + layerOffset)); + ANGLE_TRY(commitRegion(context, index, layerArea)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_2DArray::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); + return gl::InternalError() << "Copying 2D array textures is unimplemented."; } -gl::Error TextureD3D_2DArray::copySubImage(GLenum target, +gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2671,46 +3111,45 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level = static_cast(imageLevel); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); - gl::Error error = mImageArray[level][destOffset.z]->copyFromFramebuffer(destLayerOffset, - sourceArea, source); - if (error.isError()) - { - return error; - } + return gl::NoError(); + } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); + if (!canCreateRenderTargetForImage(index)) + { + gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0); + ANGLE_TRY(mImageArray[level][clippedDestOffset.z]->copyFromFramebuffer( + context, destLayerOffset, clippedSourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (isValidLevel(level)) { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY( + mRenderer->copyImage2DArray(context, source, clippedSourceArea, + gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())), + clippedDestOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -2738,124 +3177,103 @@ 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, static_cast(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_2DArray::releaseTexImage() +gl::Error TextureD3D_2DArray::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_2DArray::initMipmapsImages() +gl::Error TextureD3D_2DArray::initMipmapImages(const gl::Context *context) { - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - int baseDepth = getLayerCount(0); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + int baseWidth = getLevelZeroWidth(); + int baseHeight = getLevelZeroHeight(); + int baseDepth = getLayerCount(getBaseLevel()); GLenum baseFormat = getBaseLevelInternalFormat(); - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1u; level <= maxLevel; level++) { + ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0); gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); - redefineImage(level, baseFormat, levelLayerSize); + ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2DArray::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLayerCount(getBaseLevel()); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2864,40 +3282,44 @@ gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureSt GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); // TODO(geofflang): Verify storage creation succeeds - *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + outStorage->reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, + height, depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only ASSERT(!mTexStorage->isManaged()); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::updateStorage() +gl::Error TextureD3D_2DArray::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_2DArray::isValidLevel(int level) const @@ -2914,21 +3336,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); - if (width <= 0 || height <= 0 || layers <= 0) + if (width <= 0 || height <= 0) { return false; } - if (level == 0) + // Layers check needs to happen after the above checks, otherwise out-of-range base level may be + // queried. + GLsizei layers = getLayerCount(getBaseLevel()); + + if (layers <= 0) + { + return false; + } + + if (level == static_cast(getBaseLevel())) { return true; } - if (getInternalFormat(level) != getInternalFormat(0)) + if (getInternalFormat(level) != getInternalFormat(getBaseLevel())) { return false; } @@ -2956,27 +3386,23 @@ bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_2DArray::updateStorageLevel(int level) +gl::Error TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(level >= 0 && level < static_cast(ArraySize(mLayerCounts))); ASSERT(isLevelComplete(level)); for (int layer = 0; layer < mLayerCounts[level]; layer++) { - ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr); if (mImageArray[level][layer]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void TextureD3D_2DArray::deleteImages() @@ -2988,18 +3414,26 @@ void TextureD3D_2DArray::deleteImages() delete mImageArray[level][layer]; } delete[] mImageArray[level]; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; mLayerCounts[level] = 0; } } -void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = getLayerCount(0); - const GLenum storageFormat = getBaseLevelInternalFormat(); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const GLuint baseLevel = getBaseLevel(); + int storageDepth = 0; + if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + storageDepth = getLayerCount(baseLevel); + } // Only reallocate the layers if the size doesn't match if (size.depth != mLayerCounts[level]) @@ -3026,33 +3460,27 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const for (int layer = 0; layer < mLayerCounts[level]; layer++) { mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, - gl::Extents(size.width, size.height, 1), false); + gl::Extents(size.width, size.height, 1), + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty(); } } if (mTexStorage) { + const GLenum storageFormat = getBaseLevelInternalFormat(); const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || - size.height != storageHeight || - size.depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || + size.height != storageHeight || size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage { - for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) - { - for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) - { - mImageArray[dirtyLevel][dirtyLayer]->markDirty(); - } - } - - delete mTexStorage; - mTexStorage = NULL; - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const @@ -3083,4 +3511,464 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); } +void TextureD3D_2DArray::markAllImagesDirty() +{ + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) + { + mImageArray[dirtyLevel][dirtyLayer]->markDirty(); + } + } + mDirtyImages = true; } + +TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_External::~TextureD3D_External() +{ +} + +ImageD3D *TextureD3D_External::getImage(const gl::ImageIndex &index) const +{ + UNREACHABLE(); + return nullptr; +} + +GLsizei TextureD3D_External::getLayerCount(int level) const +{ + return 1; +} + +gl::Error TextureD3D_External::setImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + // Image setting is not supported for external images + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setSubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copyImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copySubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) +{ + ASSERT(target == GL_TEXTURE_EXTERNAL_OES); + + ANGLE_TRY(releaseTexStorage(context)); + + // If the stream is null, the external image is unbound and we release the storage + if (stream != nullptr) + { + mTexStorage = mRenderer->createTextureStorageExternal(stream, desc); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_External::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + EGLImageD3D *eglImaged3d = GetImplAs(image); + + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); + + return gl::NoError(); +} + +gl::Error TextureD3D_External::initMipmapImages(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const +{ + return (index.mipIndex == 0) ? (mTexStorage != nullptr) : false; +} + +gl::Error TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Texture storage is created when an external image is bound + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::Error TextureD3D_External::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::updateStorage(const gl::Context *context) +{ + // Texture storage does not need to be updated since it is already loaded with the latest + // external image + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::ImageIndexIterator TextureD3D_External::imageIterator() const +{ + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} + +bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0); +} + +void TextureD3D_External::markAllImagesDirty() +{ + UNREACHABLE(); +} + +TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state, + RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_2DMultisample::~TextureD3D_2DMultisample() +{ +} + +ImageD3D *TextureD3D_2DMultisample::getImage(const gl::ImageIndex &index) const +{ + return nullptr; +} + +gl::Error TextureD3D_2DMultisample::setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + ASSERT(target == GL_TEXTURE_2D_MULTISAMPLE && size.depth == 1); + + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DMultisample(internalFormat, size.width, + size.height, static_cast(0), + samples, fixedSampleLocations)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ANGLE_TRY(updateStorage(context)); + + mImmutable = false; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + // ensure the underlying texture is created + ANGLE_TRY(ensureRenderTarget(context)); + + return mTexStorage->getRenderTarget(context, index, outRT); +} + +gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const +{ + return gl::ImageIndexIterator::Make2DMultisample(); +} + +gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DMultisample(); +} + +bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D_MULTISAMPLE && index.mipIndex == 0); +} + +GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const +{ + return 1; +} + +void TextureD3D_2DMultisample::markAllImagesDirty() +{ +} + +gl::Error TextureD3D_2DMultisample::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::NoError(); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); + + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ASSERT(mTexStorage); + + // flush image data to the storage + ANGLE_TRY(updateStorage(context)); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + outStorage->reset(mTexStorage); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = newCompleteTexStorage; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::updateStorage(const gl::Context *context) +{ + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::NoError(); +} + +bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const +{ + return true; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h index 1d5faee703..eb206a6ccc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h @@ -9,9 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ #define LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ -#include "libANGLE/renderer/TextureImpl.h" -#include "libANGLE/angletypes.h" +#include "common/Color.h" #include "libANGLE/Constants.h" +#include "libANGLE/Stream.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" namespace gl { @@ -26,29 +29,51 @@ class RendererD3D; class RenderTargetD3D; class TextureStorage; +template +using TexLevelsArray = std::array; + class TextureD3D : public TextureImpl { public: - TextureD3D(RendererD3D *renderer); - virtual ~TextureD3D(); + TextureD3D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D() override; + + gl::Error onDestroy(const gl::Context *context) override; - gl::Error getNativeTexture(TextureStorage **outStorage); + gl::Error getNativeTexture(const gl::Context *context, TextureStorage **outStorage); - virtual void setUsage(GLenum usage) { mUsage = usage; } bool hasDirtyImages() const { return mDirtyImages; } void resetDirty() { mDirtyImages = false; } virtual ImageD3D *getImage(const gl::ImageIndex &index) const = 0; virtual GLsizei getLayerCount(int level) const = 0; + gl::Error getImageAndSyncFromStorage(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D **outImage); + GLint getBaseLevelWidth() const; GLint getBaseLevelHeight() const; - GLint getBaseLevelDepth() const; GLenum getBaseLevelInternalFormat() const; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) override; + bool isImmutable() const { return mImmutable; } - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) = 0; // Returns an iterator over all "Images" for this particular Texture. virtual gl::ImageIndexIterator imageIterator() const = 0; @@ -58,47 +83,91 @@ class TextureD3D : public TextureImpl virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; - gl::Error generateMipmaps(const gl::TextureState &textureState) override; + gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + gl::Error generateMipmap(const gl::Context *context) override; TextureStorage *getStorage(); ImageD3D *getBaseLevelImage() const; - gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, + gl::Error getAttachmentRenderTarget(const gl::Context *context, + GLenum binding, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) override; + gl::Error setBaseLevel(const gl::Context *context, GLuint baseLevel) override; + + void syncState(const gl::Texture::DirtyBits &dirtyBits) override; + + gl::Error initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndex) override; + protected: - gl::Error setImageImpl(const gl::ImageIndex &index, + gl::Error setImageImpl(const gl::Context *context, + 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 setCompressedImageImpl(const gl::ImageIndex &index, + gl::Error subImage(const gl::Context *context, + 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 setCompressedImageImpl(const gl::Context *context, + 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); - gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget); + gl::Error subImageCompressed(const gl::Context *context, + 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::Buffer *unpackBuffer, GLenum sizedInternalFormat); + gl::Error fastUnpackPixels(const gl::Context *context, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + const gl::Box &destArea, + GLenum sizedInternalFormat, + GLenum type, + RenderTargetD3D *destRenderTarget); + + GLint getLevelZeroWidth() const; + GLint getLevelZeroHeight() const; + virtual GLint getLevelZeroDepth() const; GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; - int mipLevels() const; - virtual void initMipmapsImages() = 0; + virtual gl::Error initMipmapImages(const gl::Context *context) = 0; bool isBaseImageZeroSize() const; virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; - virtual gl::Error ensureRenderTarget(); + gl::Error ensureRenderTarget(const gl::Context *context); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; - gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const = 0; + virtual gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) = 0; + gl::Error commitRegion(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box ®ion); - RendererD3D *mRenderer; + gl::Error releaseTexStorage(const gl::Context *context); + + GLuint getBaseLevel() const { return mBaseLevel; }; - GLenum mUsage; + virtual void markAllImagesDirty() = 0; + + GLint getBaseLevelDepth() const; + + RendererD3D *mRenderer; bool mDirtyImages; @@ -106,154 +175,301 @@ class TextureD3D : public TextureImpl TextureStorage *mTexStorage; private: - virtual gl::Error initializeStorage(bool renderTarget) = 0; + virtual gl::Error initializeStorage(const gl::Context *context, bool renderTarget) = 0; - virtual gl::Error updateStorage() = 0; + virtual gl::Error updateStorage(const gl::Context *context) = 0; bool shouldUseSetData(const ImageD3D *image) const; - gl::Error generateMipmapsUsingImages(); + gl::Error generateMipmapUsingImages(const gl::Context *context, const GLuint maxLevel); + + GLuint mBaseLevel; }; class TextureD3D_2D : public TextureD3D { public: - TextureD3D_2D(RendererD3D *renderer); - virtual ~TextureD3D_2D(); + TextureD3D_2D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2D() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; + + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; + bool isSRGB(GLint level) const; - gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; - gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - 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, 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, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) override; - gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; - - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); + gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copyCompressedTexture(const gl::Context *context, const gl::Texture *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; + bool isImageComplete(const gl::ImageIndex &index) const override; - gl::Error updateStorageLevel(int level); + gl::Error updateStorageLevel(const gl::Context *context, int level); - void redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease); + gl::Error redefineImage(const gl::Context *context, + size_t level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); bool mEGLImageTarget; - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelsArray> mImageArray; }; class TextureD3D_Cube : public TextureD3D { public: - TextureD3D_Cube(RendererD3D *renderer); - virtual ~TextureD3D_Cube(); + TextureD3D_Cube(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_Cube() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; - virtual bool hasDirtyImages() const { return mDirtyImages; } - virtual void resetDirty() { mDirtyImages = false; } - virtual void setUsage(GLenum usage) { mUsage = usage; } + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLenum getInternalFormat(GLint level, GLint layer) const; bool isDepth(GLint level, GLint layer) const; + bool isSRGB(GLint level, GLint layer) const; - gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; - gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - 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, 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, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) override; - gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + gl::Error copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + gl::Error copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - 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 gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidFaceLevel(int faceIndex, int level) const; bool isFaceLevelComplete(int faceIndex, int level) const; bool isCubeComplete() const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageFaceLevel(int faceIndex, int level); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageFaceLevel(const gl::Context *context, int faceIndex, int level); - void redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + int faceIndex, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); - ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + std::array>, 6> mImageArray; }; class TextureD3D_3D : public TextureD3D { public: - TextureD3D_3D(RendererD3D *renderer); - virtual ~TextureD3D_3D(); + TextureD3D_3D(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_3D() override; - virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + gl::Error onDestroy(const gl::Context *context) override; + + ImageD3D *getImage(int level, int layer) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; @@ -261,110 +477,213 @@ class TextureD3D_3D : public TextureD3D GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; - gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; - gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - 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, 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, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) override; - gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + protected: + void markAllImagesDirty() override; + GLint getLevelZeroDepth() const override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageLevel(const gl::Context *context, int level); - void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelsArray> mImageArray; }; class TextureD3D_2DArray : public TextureD3D { public: - TextureD3D_2DArray(RendererD3D *renderer); - virtual ~TextureD3D_2DArray(); + TextureD3D_2DArray(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2DArray() override; + + gl::Error onDestroy(const gl::Context *context) override; virtual ImageD3D *getImage(int level, int layer) const; - virtual ImageD3D *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; - gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; - gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - 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, 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, size_t imageSize, const uint8_t *pixels) override; - - gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) override; - gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; - gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; + protected: + void markAllImagesDirty() override; private: - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); + bool isImageComplete(const gl::ImageIndex &index) const override; + gl::Error updateStorageLevel(const gl::Context *context, int level); void deleteImages(); - void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + gl::Error redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease); // Storing images as an array of single depth textures since D3D11 treats each array level of a // Texture2D object as a separate subresource. Each layer would have to be looped over @@ -374,6 +693,199 @@ class TextureD3D_2DArray : public TextureD3D ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; +class TextureD3D_External : public TextureD3D +{ + public: + TextureD3D_External(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_External() override; + + ImageD3D *getImage(const gl::ImageIndex &index) const override; + GLsizei getLayerCount(int level) const override; + + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) override; + + gl::Error setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + protected: + void markAllImagesDirty() override; + + private: + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; + + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; + + bool isImageComplete(const gl::ImageIndex &index) const override; +}; + +class TextureD3D_2DMultisample : public TextureD3D +{ + public: + TextureD3D_2DMultisample(const gl::TextureState &data, RendererD3D *renderer); + ~TextureD3D_2DMultisample() override; + + ImageD3D *getImage(const gl::ImageIndex &index) const override; + gl::Error setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + gl::Error setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) override; + + gl::Error setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + gl::Error setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) override; + + gl::Error copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) override; + + gl::Error bindTexImage(const gl::Context *context, egl::Surface *surface) override; + gl::Error releaseTexImage(const gl::Context *context) override; + + gl::Error setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) override; + + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::ImageIndexIterator imageIterator() const override; + gl::ImageIndex getImageIndex(GLint mip, GLint layer) const override; + bool isValidIndex(const gl::ImageIndex &index) const override; + + GLsizei getLayerCount(int level) const override; + + protected: + void markAllImagesDirty() override; + + private: + gl::Error initializeStorage(const gl::Context *context, bool renderTarget) override; + gl::Error createCompleteStorage(bool renderTarget, + TexStoragePointer *outTexStorage) const override; + gl::Error setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) override; + + gl::Error updateStorage(const gl::Context *context) override; + gl::Error initMipmapImages(const gl::Context *context) override; + + bool isImageComplete(const gl::ImageIndex &index) const override; +}; } #endif // LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp deleted file mode 100644 index abb83a14d5..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// 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. -// - -// TextureStorage.cpp: Shared members of abstract rx::TextureStorage class. - -#include "libANGLE/renderer/d3d/TextureStorage.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/renderer/d3d/RenderTargetD3D.h" -#include "libANGLE/renderer/Renderer.h" -#include "libANGLE/Renderbuffer.h" -#include "libANGLE/Texture.h" - -#include "common/debug.h" -#include "common/mathutil.h" - -namespace rx -{ - -TextureStorage::TextureStorage() - : mFirstRenderTargetSerial(0), - mRenderTargetSerialsLayerStride(0) -{} - -void TextureStorage::initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride) -{ - mFirstRenderTargetSerial = RenderTargetD3D::issueSerials(rtSerialsToReserve); - mRenderTargetSerialsLayerStride = rtSerialsLayerStride; -} - -unsigned int TextureStorage::getRenderTargetSerial(const gl::ImageIndex &index) const -{ - unsigned int layerOffset = (index.hasLayer() ? (static_cast(index.layerIndex) * mRenderTargetSerialsLayerStride) : 0); - return mFirstRenderTargetSerial + static_cast(index.mipIndex) + layerOffset; -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h index 417237495d..383fbc2141 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h @@ -9,20 +9,19 @@ #ifndef LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ #define LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ -#include "libANGLE/Error.h" - #include "common/debug.h" -#include "libANGLE/Error.h" +#include "libANGLE/angletypes.h" #include #include namespace gl { +class Context; struct ImageIndex; struct Box; struct PixelUnpackState; -} +} // namespace gl namespace rx { @@ -36,23 +35,48 @@ class TextureStorage : angle::NonCopyable TextureStorage() {} virtual ~TextureStorage() {} + virtual gl::Error onDestroy(const gl::Context *context); + 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; - virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; + virtual gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) = 0; + virtual gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) = 0; - virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; - 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; + virtual gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) = 0; // 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); } + virtual gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture); }; +inline gl::Error TextureStorage::onDestroy(const gl::Context *context) +{ + return gl::NoError(); } +inline gl::Error TextureStorage::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) +{ + return gl::NoError(); +} + +using TexStoragePointer = angle::UniqueObjectPointer; + +} // namespace rx + #endif // LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp deleted file mode 100644 index 80a4ec3ae1..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// 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. -// - -// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers. - -#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" - -namespace rx -{ - -TransformFeedbackD3D::TransformFeedbackD3D() -{ -} - -TransformFeedbackD3D::~TransformFeedbackD3D() -{ -} - -void TransformFeedbackD3D::begin(GLenum primitiveMode) -{ -} - -void TransformFeedbackD3D::end() -{ -} - -void TransformFeedbackD3D::pause() -{ -} - -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 deleted file mode 100644 index 6925966153..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// 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. -// - -// TransformFeedbackD3D.h: Implements the abstract rx::TransformFeedbackImpl class. - -#ifndef LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ -#define LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ - -#include "libANGLE/renderer/TransformFeedbackImpl.h" -#include "libANGLE/angletypes.h" - -namespace rx -{ - -class TransformFeedbackD3D : public TransformFeedbackImpl -{ - public: - TransformFeedbackD3D(); - virtual ~TransformFeedbackD3D(); - - 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; -}; - -} - -#endif // LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp deleted file mode 100644 index f2654d34e3..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.cpp +++ /dev/null @@ -1,397 +0,0 @@ -// -// 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 deleted file mode 100644 index ca4640b000..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VaryingPacking.h +++ /dev/null @@ -1,175 +0,0 @@ -// -// 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 9efee9db7c..7c2d5aec70 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp @@ -8,18 +8,19 @@ // class with derivations, classes that perform graphics API agnostic vertex buffer operations. #include "libANGLE/renderer/d3d/VertexBuffer.h" + +#include "common/mathutil.h" #include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/VertexAttribute.h" -#include "common/mathutil.h" - namespace rx { +// VertexBuffer Implementation unsigned int VertexBuffer::mNextSerial = 1; -VertexBuffer::VertexBuffer() +VertexBuffer::VertexBuffer() : mRefCount(1) { updateSerial(); } @@ -38,19 +39,34 @@ unsigned int VertexBuffer::getSerial() const return mSerial; } -VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) - : mFactory(factory) +void VertexBuffer::addRef() { - mDynamic = dynamic; - mWritePosition = 0; - mReservedSpace = 0; + mRefCount++; +} + +void VertexBuffer::release() +{ + ASSERT(mRefCount > 0); + mRefCount--; + + if (mRefCount == 0) + { + delete this; + } +} - mVertexBuffer = factory->createVertexBuffer(); +// VertexBufferInterface Implementation +VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) + : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic) +{ } VertexBufferInterface::~VertexBufferInterface() { - delete mVertexBuffer; + if (mVertexBuffer) + { + mVertexBuffer->release(); + } } unsigned int VertexBufferInterface::getSerial() const @@ -69,181 +85,172 @@ gl::Error VertexBufferInterface::setBufferSize(unsigned int size) { return mVertexBuffer->initialize(size, mDynamic); } - else + + return mVertexBuffer->setBufferSize(size); +} + +gl::ErrorOrResult VertexBufferInterface::getSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const +{ + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances), + spaceRequired); + + // Align to 16-byte boundary + unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u); + + if (alignedSpaceRequired < spaceRequired) { - return mVertexBuffer->setBufferSize(size); + return gl::OutOfMemory() + << "Vertex buffer overflow in VertexBufferInterface::getSpaceRequired."; } + + return alignedSpaceRequired; } -unsigned int VertexBufferInterface::getWritePosition() const +gl::Error VertexBufferInterface::discard() { - return mWritePosition; + return mVertexBuffer->discard(); } -void VertexBufferInterface::setWritePosition(unsigned int writePosition) +VertexBuffer *VertexBufferInterface::getVertexBuffer() const { - mWritePosition = writePosition; + return mVertexBuffer; } -gl::Error VertexBufferInterface::discard() +// StreamingVertexBufferInterface Implementation +StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, + std::size_t initialSize) + : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0) { - return mVertexBuffer->discard(); + // TODO(jmadill): Make an initialize method that can return an error. + ANGLE_SWALLOW_ERR(setBufferSize(static_cast(initialSize))); } -gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData) +StreamingVertexBufferInterface::~StreamingVertexBufferInterface() { - gl::Error error(GL_NO_ERROR); +} - unsigned int spaceRequired; - error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); - if (error.isError()) +gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curBufferSize = getBufferSize(); + if (size > curBufferSize) + { + ANGLE_TRY(setBufferSize(std::max(size, 3 * curBufferSize / 2))); + mWritePosition = 0; + } + else if (mWritePosition + size > curBufferSize) { - return error; + ANGLE_TRY(discard()); + mWritePosition = 0; } - // Align to 16-byte boundary - unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u); + return gl::NoError(); +} + +gl::Error StreamingVertexBufferInterface::storeDynamicAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLenum currentValueType, + GLint start, + GLsizei count, + GLsizei instances, + unsigned int *outStreamOffset, + const uint8_t *sourceData) +{ + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired); // Protect against integer overflow - if (!IsUnsignedAdditionSafe(mWritePosition, alignedSpaceRequired) || - alignedSpaceRequired < spaceRequired) + angle::CheckedNumeric checkedPosition(mWritePosition); + checkedPosition += spaceRequired; + if (!checkedPosition.IsValid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); + return gl::OutOfMemory() + << "Internal error, new vertex buffer write position would overflow."; } - error = reserveSpace(mReservedSpace); - if (error.isError()) - { - return error; - } + ANGLE_TRY(reserveSpace(mReservedSpace)); mReservedSpace = 0; - error = mVertexBuffer->storeVertexAttributes(attrib, currentValueType, start, count, instances, mWritePosition, sourceData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, currentValueType, start, count, + instances, mWritePosition, sourceData)); if (outStreamOffset) { *outStreamOffset = mWritePosition; } - mWritePosition += alignedSpaceRequired; + mWritePosition += spaceRequired; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) +gl::Error StreamingVertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) { - gl::Error error(GL_NO_ERROR); - - unsigned int requiredSpace; - error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace); - if (error.isError()) - { - return error; - } + unsigned int requiredSpace = 0; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances), + requiredSpace); // Align to 16-byte boundary - unsigned int alignedRequiredSpace = roundUp(requiredSpace, 16u); + auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u); + alignedRequiredSpace += mReservedSpace; // Protect against integer overflow - if (!IsUnsignedAdditionSafe(mReservedSpace, alignedRequiredSpace) || - alignedRequiredSpace < requiredSpace) + if (!alignedRequiredSpace.IsValid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " - "it would result in an overflow.", requiredSpace); + return gl::OutOfMemory() + << "Unable to reserve " << requiredSpace + << " extra bytes in internal vertex buffer, it would result in an overflow."; } - mReservedSpace += alignedRequiredSpace; + mReservedSpace = alignedRequiredSpace.ValueOrDie(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -VertexBuffer* VertexBufferInterface::getVertexBuffer() const +// StaticVertexBufferInterface Implementation +StaticVertexBufferInterface::AttributeSignature::AttributeSignature() + : type(GL_NONE), size(0), stride(0), normalized(false), pureInteger(false), offset(0) { - return mVertexBuffer; } -bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, - GLenum currentValueType) const +bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const { - gl::Buffer *buffer = attrib.buffer.get(); - BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + size_t attribStride = ComputeVertexAttributeStride(attrib, binding); - if (!storage || !storage->supportsDirectBinding()) + if (type != attrib.type || size != attrib.size || static_cast(stride) != attribStride || + normalized != attrib.normalized || pureInteger != attrib.pureInteger) { return false; } - // Alignment restrictions: In D3D, vertex data must be aligned to - // the format stride, or to a 4-byte boundary, whichever is smaller. - // (Undocumented, and experimentally confirmed) - size_t alignment = 4; - bool requiresConversion = false; - - if (attrib.type != GL_FLOAT) - { - 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(vertexFormatType) & VERTEX_CONVERT_CPU) != 0; - } - - bool isAligned = (static_cast(ComputeVertexAttributeStride(attrib)) % alignment == 0) && - (static_cast(attrib.offset) % alignment == 0); - - return !requiresConversion && isAligned; + size_t attribOffset = + (static_cast(ComputeVertexAttributeOffset(attrib, binding)) % attribStride); + return (offset == attribOffset); } -StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize) - : VertexBufferInterface(factory, true) +void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) { - setBufferSize(static_cast(initialSize)); -} - -StreamingVertexBufferInterface::~StreamingVertexBufferInterface() -{ -} - -gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) -{ - unsigned int curBufferSize = getBufferSize(); - if (size > curBufferSize) - { - gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2)); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - else if (getWritePosition() + size > curBufferSize) - { - gl::Error error = discard(); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - - return gl::Error(GL_NO_ERROR); + type = attrib.type; + size = attrib.size; + normalized = attrib.normalized; + pureInteger = attrib.pureInteger; + offset = stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)) % + ComputeVertexAttributeStride(attrib, binding); } StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) - : VertexBufferInterface(factory, false), mIsCommitted(false) + : VertexBufferInterface(factory, false) { } @@ -251,82 +258,36 @@ StaticVertexBufferInterface::~StaticVertexBufferInterface() { } -bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) +bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const { - for (unsigned int element = 0; element < mCache.size(); element++) - { - 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) % attribStride); - if (mCache[element].attributeOffset == offset) - { - if (outStreamOffset) - { - *outStreamOffset = mCache[element].streamOffset; - } - return true; - } - } - } - - return false; + return mSignature.matchesAttribute(attrib, binding); } -gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) +void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) { - unsigned int curSize = getBufferSize(); - if (curSize == 0) - { - return setBufferSize(size); - } - else if (curSize >= size) - { - return gl::Error(GL_NO_ERROR); - } - else - { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized."); - } + return mSignature.set(attrib, binding); } -gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, - GLenum currentValueType, - GLint start, - GLsizei count, - GLsizei instances, - unsigned int *outStreamOffset, - const uint8_t *sourceData) +gl::Error StaticVertexBufferInterface::storeStaticAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLint start, + GLsizei count, + GLsizei instances, + const uint8_t *sourceData) { - unsigned int streamOffset; - gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValueType, start, count, instances, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } + unsigned int spaceRequired = 0; + ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired); + ANGLE_TRY(setBufferSize(spaceRequired)); - size_t attributeOffset = static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib); - VertexElement element = { attrib.type, attrib.size, static_cast(ComputeVertexAttributeStride(attrib)), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; - mCache.push_back(element); - - if (outStreamOffset) - { - *outStreamOffset = streamOffset; - } + ASSERT(attrib.enabled); + ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, GL_NONE, start, count, + instances, 0, sourceData)); - return gl::Error(GL_NO_ERROR); + mSignature.set(attrib, binding); + mVertexBuffer->hintUnmapResource(); + return gl::NoError(); } -void StaticVertexBufferInterface::commit() -{ - if (getBufferSize() > 0) - { - mIsCommitted = true; - } -} -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h index 692b6ac506..df8085d3cb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h @@ -22,6 +22,7 @@ namespace gl { struct VertexAttribute; +class VertexBinding; struct VertexAttribCurrentValueData; } @@ -29,23 +30,25 @@ namespace rx { class BufferFactoryD3D; +// Use a ref-counting scheme with self-deletion on release. We do this so that we can more +// easily manage the static buffer cache, without deleting currently bound buffers. class VertexBuffer : angle::NonCopyable { public: VertexBuffer(); - virtual ~VertexBuffer(); virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, 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; virtual unsigned int getBufferSize() const = 0; virtual gl::Error setBufferSize(unsigned int size) = 0; @@ -56,12 +59,18 @@ class VertexBuffer : angle::NonCopyable // This may be overridden (e.g. by VertexBuffer11) if necessary. virtual void hintUnmapResource() { }; + // Reference counting. + void addRef(); + void release(); + protected: void updateSerial(); + virtual ~VertexBuffer(); private: unsigned int mSerial; static unsigned int mNextSerial; + unsigned int mRefCount; }; class VertexBufferInterface : angle::NonCopyable @@ -70,42 +79,24 @@ class VertexBufferInterface : angle::NonCopyable VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic); virtual ~VertexBufferInterface(); - gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); - unsigned int getBufferSize() const; + bool empty() const { return getBufferSize() == 0; } unsigned int getSerial() const; - 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, - GLenum currentValueType) const; - - VertexBuffer* getVertexBuffer() const; + VertexBuffer *getVertexBuffer() const; protected: - virtual gl::Error reserveSpace(unsigned int size) = 0; - - unsigned int getWritePosition() const; - void setWritePosition(unsigned int writePosition); - gl::Error discard(); gl::Error setBufferSize(unsigned int size); - private: + gl::ErrorOrResult getSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const; BufferFactoryD3D *const mFactory; - - VertexBuffer* mVertexBuffer; - - unsigned int mWritePosition; - unsigned int mReservedSpace; + VertexBuffer *mVertexBuffer; bool mDynamic; }; @@ -113,53 +104,72 @@ class StreamingVertexBufferInterface : public VertexBufferInterface { public: StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize); - ~StreamingVertexBufferInterface(); + ~StreamingVertexBufferInterface() override; - protected: + gl::Error storeDynamicAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLenum currentValueType, + GLint start, + GLsizei count, + GLsizei instances, + unsigned int *outStreamOffset, + const uint8_t *sourceData); + + gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances); + + private: gl::Error reserveSpace(unsigned int size); + + unsigned int mWritePosition; + unsigned int mReservedSpace; }; class StaticVertexBufferInterface : public VertexBufferInterface { public: explicit StaticVertexBufferInterface(BufferFactoryD3D *factory); - ~StaticVertexBufferInterface(); + ~StaticVertexBufferInterface() override; - 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); + // Warning: you should ensure binding really matches attrib.bindingIndex before using these + // functions. + gl::Error storeStaticAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLint start, + GLsizei count, + GLsizei instances, + const uint8_t *sourceData); - // 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; } + bool matchesAttribute(const gl::VertexAttribute &attribute, + const gl::VertexBinding &binding) const; - protected: - gl::Error reserveSpace(unsigned int size); + void setAttribute(const gl::VertexAttribute &attribute, const gl::VertexBinding &binding); private: - struct VertexElement + class AttributeSignature final : angle::NonCopyable { + public: + AttributeSignature(); + + bool matchesAttribute(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) const; + + void set(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding); + + private: GLenum type; GLuint size; GLuint stride; bool normalized; bool pureInteger; - size_t attributeOffset; - - unsigned int streamOffset; + size_t offset; }; - bool mIsCommitted; - std::vector mCache; + AttributeSignature mSignature; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp index b392d0f4da..54ad5e54f5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -9,25 +9,38 @@ #include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "common/bitset_utils.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" #include "libANGLE/State.h" -#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/VertexBuffer.h" -namespace -{ - enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; - // This has to be at least 4k or else it fails on ATI cards. - enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; -} +using namespace angle; namespace rx { +namespace +{ +enum +{ + INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024 +}; +// This has to be at least 4k or else it fails on ATI cards. +enum +{ + CONSTANT_VERTEX_BUFFER_SIZE = 4096 +}; -static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +int ElementsInBuffer(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + unsigned int size) { // Size cannot be larger than a GLsizei if (size > static_cast(std::numeric_limits::max())) @@ -35,15 +48,139 @@ static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size size = static_cast(std::numeric_limits::max()); } - GLsizei stride = static_cast(ComputeVertexAttributeStride(attrib)); - return (size - attrib.offset % stride + + GLsizei stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + GLsizei offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)); + return (size - offset % stride + (stride - static_cast(ComputeVertexAttributeTypeSize(attrib)))) / stride; } -VertexDataManager::CurrentValueState::CurrentValueState() - : buffer(nullptr), - offset(0) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +bool DirectStoragePossible(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding) +{ + // Current value attribs may not use direct storage. + if (!attrib.enabled) + { + return false; + } + + gl::Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + return false; + } + + BufferD3D *bufferD3D = GetImplAs(buffer); + ASSERT(bufferD3D); + if (!bufferD3D->supportsDirectBinding()) + { + return false; + } + + // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a + // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed) + size_t alignment = 4; + + // TODO(jmadill): add VertexFormatCaps + BufferFactoryD3D *factory = bufferD3D->getFactory(); + + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib); + + // CPU-converted vertex data must be converted (naturally). + if ((factory->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_CPU) != 0) + { + return false; + } + + if (attrib.type != GL_FLOAT) + { + auto errorOrElementSize = factory->getVertexSpaceRequired(attrib, binding, 1, 0); + if (errorOrElementSize.isError()) + { + ERR() << "Unlogged error in DirectStoragePossible."; + return false; + } + + alignment = std::min(errorOrElementSize.getResult(), 4); + } + + GLintptr offset = ComputeVertexAttributeOffset(attrib, binding); + // Final alignment check - unaligned data must be converted. + return (static_cast(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) && + (static_cast(offset) % alignment == 0); +} +} // anonymous namespace + +TranslatedAttribute::TranslatedAttribute() + : active(false), + attribute(nullptr), + binding(nullptr), + currentValueType(GL_NONE), + baseOffset(0), + usesFirstVertexOffset(false), + stride(0), + vertexBuffer(), + storage(nullptr), + serial(0), + divisor(0) +{ +} + +TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default; + +gl::ErrorOrResult TranslatedAttribute::computeOffset(GLint startVertex) const +{ + if (!usesFirstVertexOffset) + { + return baseOffset; + } + + CheckedNumeric offset; + + offset = baseOffset + stride * static_cast(startVertex); + ANGLE_TRY_CHECKED_MATH(offset); + return offset.ValueOrDie(); +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) +{ + // If attribute is disabled, we use the current value. + if (!attrib.enabled) + { + return VertexStorageType::CURRENT_VALUE; + } + + // If specified with immediate data, we must use dynamic storage. + auto *buffer = binding.getBuffer().get(); + if (!buffer) + { + return VertexStorageType::DYNAMIC; + } + + // Check if the buffer supports direct storage. + if (DirectStoragePossible(attrib, binding)) + { + return VertexStorageType::DIRECT; + } + + // Otherwise the storage is static or dynamic. + BufferD3D *bufferD3D = GetImplAs(buffer); + ASSERT(bufferD3D); + switch (bufferD3D->getUsage()) + { + case D3DBufferUsage::DYNAMIC: + return VertexStorageType::DYNAMIC; + case D3DBufferUsage::STATIC: + return VertexStorageType::STATIC; + default: + UNREACHABLE(); + return VertexStorageType::UNKNOWN; + } +} + +VertexDataManager::CurrentValueState::CurrentValueState() : buffer(), offset(0) { data.FloatValues[0] = std::numeric_limits::quiet_NaN(); data.FloatValues[1] = std::numeric_limits::quiet_NaN(); @@ -54,379 +191,456 @@ VertexDataManager::CurrentValueState::CurrentValueState() VertexDataManager::CurrentValueState::~CurrentValueState() { - SafeDelete(buffer); } VertexDataManager::VertexDataManager(BufferFactoryD3D *factory) - : mFactory(factory), - mStreamingBuffer(nullptr), - // TODO(jmadill): use context caps - mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) + : mFactory(factory), mStreamingBuffer(), mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) { - 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() { - SafeDelete(mStreamingBuffer); } -void VertexDataManager::hintUnmapAllResources(const std::vector &vertexAttributes) +gl::Error VertexDataManager::initialize() { - mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); - - for (const TranslatedAttribute *translated : mActiveEnabledAttributes) + mStreamingBuffer.reset( + new StreamingVertexBufferInterface(mFactory, INITIAL_STREAM_BUFFER_SIZE)); + if (!mStreamingBuffer) { - 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) - { - // 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(); - - staticBuffer->getVertexBuffer()->hintUnmapResource(); - } + return gl::OutOfMemory() << "Failed to allocate the streaming vertex buffer."; } - for (auto ¤tValue : mCurrentValueCache) - { - if (currentValue.buffer != nullptr) - { - currentValue.buffer->getVertexBuffer()->hintUnmapResource(); - } - } + return gl::NoError(); } -gl::Error VertexDataManager::prepareVertexData(const gl::State &state, +void VertexDataManager::deinitialize() +{ + mStreamingBuffer.reset(); + mCurrentValueCache.clear(); +} + +gl::Error VertexDataManager::prepareVertexData(const gl::Context *context, 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."); - } + ASSERT(mStreamingBuffer); - // Compute active enabled and active disable attributes, for speed. - // TODO(jmadill): don't recompute if there was no state change + const gl::State &state = context->getGLState(); const gl::VertexArray *vertexArray = state.getVertexArray(); - const gl::Program *program = state.getProgram(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); + const auto &vertexBindings = vertexArray->getVertexBindings(); + + mDynamicAttribsMaskCache.reset(); + const gl::Program *program = state.getProgram(); - mActiveEnabledAttributes.clear(); - mActiveDisabledAttributes.clear(); translatedAttribs->clear(); for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { - if (program->isAttribLocationActive(attribIndex)) - { - // Resize automatically puts in empty attribs - translatedAttribs->resize(attribIndex + 1); + // Skip attrib locations the program doesn't use. + if (!program->isAttribLocationActive(attribIndex)) + continue; + + const auto &attrib = vertexAttributes[attribIndex]; + const auto &binding = vertexBindings[attrib.bindingIndex]; - TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + // Resize automatically puts in empty attribs + translatedAttribs->resize(attribIndex + 1); - // Record the attribute now - translated->active = true; - translated->attribute = &vertexAttributes[attribIndex]; - translated->currentValueType = - state.getVertexAttribCurrentValue(static_cast(attribIndex)).Type; - translated->divisor = vertexAttributes[attribIndex].divisor; + TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + auto currentValueData = state.getVertexAttribCurrentValue(attribIndex); - if (vertexAttributes[attribIndex].enabled) + // Record the attribute now + translated->active = true; + translated->attribute = &attrib; + translated->binding = &binding; + translated->currentValueType = currentValueData.Type; + translated->divisor = binding.getDivisor(); + + switch (ClassifyAttributeStorage(attrib, binding)) + { + case VertexStorageType::STATIC: { - 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(); - } + // Store static attribute. + ANGLE_TRY(StoreStaticAttrib(context, translated)); + break; } - else + case VertexStorageType::DYNAMIC: + // Dynamic attributes must be handled together. + mDynamicAttribsMaskCache.set(attribIndex); + break; + case VertexStorageType::DIRECT: + // Update translated data for direct attributes. + StoreDirectAttrib(translated); + break; + case VertexStorageType::CURRENT_VALUE: { - mActiveDisabledAttributes.push_back(attribIndex); + ANGLE_TRY(storeCurrentValue(currentValueData, translated, attribIndex)); + break; } + default: + UNREACHABLE(); + break; } } - // Reserve the required space in the buffers - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + if (mDynamicAttribsMaskCache.none()) { - gl::Error error = reserveSpaceForAttrib(*activeAttrib, count, instances); - if (error.isError()) - { - return error; - } + return gl::NoError(); } - // Perform the vertex data translations - for (TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start, + count, instances)); + + PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count); + + return gl::NoError(); +} + +// static +void VertexDataManager::StoreDirectAttrib(TranslatedAttribute *directAttrib) +{ + ASSERT(directAttrib->attribute && directAttrib->binding); + const auto &attrib = *directAttrib->attribute; + const auto &binding = *directAttrib->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer); + BufferD3D *bufferD3D = GetImplAs(buffer); + + ASSERT(DirectStoragePossible(attrib, binding)); + directAttrib->vertexBuffer.set(nullptr); + directAttrib->storage = bufferD3D; + directAttrib->serial = bufferD3D->getSerial(); + directAttrib->stride = static_cast(ComputeVertexAttributeStride(attrib, binding)); + directAttrib->baseOffset = + static_cast(ComputeVertexAttributeOffset(attrib, binding)); + + // Instanced vertices do not apply the 'start' offset + directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0); +} + +// static +gl::Error VertexDataManager::StoreStaticAttrib(const gl::Context *context, + TranslatedAttribute *translated) +{ + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer && attrib.enabled && !DirectStoragePossible(attrib, binding)); + BufferD3D *bufferD3D = GetImplAs(buffer); + + // Compute source data pointer + const uint8_t *sourceData = nullptr; + const int offset = static_cast(ComputeVertexAttributeOffset(attrib, binding)); + + ANGLE_TRY(bufferD3D->getData(context, &sourceData)); + sourceData += offset; + + unsigned int streamOffset = 0; + + translated->storage = nullptr; + ANGLE_TRY_RESULT(bufferD3D->getFactory()->getVertexSpaceRequired(attrib, binding, 1, 0), + translated->stride); + + auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding); + ASSERT(staticBuffer); + + if (staticBuffer->empty()) { - gl::Error error = storeAttribute(activeAttrib, start, count, instances); + // Convert the entire buffer + int totalCount = + ElementsInBuffer(attrib, binding, static_cast(bufferD3D->getSize())); + int startIndex = offset / static_cast(ComputeVertexAttributeStride(attrib, binding)); - if (error.isError()) - { - hintUnmapAllResources(vertexAttributes); - return error; - } + ANGLE_TRY(staticBuffer->storeStaticAttribute(attrib, binding, -startIndex, totalCount, 0, + sourceData)); } - for (size_t attribIndex : mActiveDisabledAttributes) + unsigned int firstElementOffset = + (static_cast(offset) / + static_cast(ComputeVertexAttributeStride(attrib, binding))) * + translated->stride; + + VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer(); + + CheckedNumeric checkedOffset(streamOffset); + checkedOffset += firstElementOffset; + + if (!checkedOffset.IsValid()) { - if (mCurrentValueCache[attribIndex].buffer == nullptr) - { - mCurrentValueCache[attribIndex].buffer = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); - } + return gl::InternalError() << "Integer overflow in VertexDataManager::StoreStaticAttrib"; + } + + translated->vertexBuffer.set(vertexBuffer); + translated->serial = vertexBuffer->getSerial(); + translated->baseOffset = streamOffset + firstElementOffset; + + // Instanced vertices do not apply the 'start' offset + translated->usesFirstVertexOffset = (binding.getDivisor() == 0); - gl::Error error = storeCurrentValue( - state.getVertexAttribCurrentValue(static_cast(attribIndex)), - &(*translatedAttribs)[attribIndex], &mCurrentValueCache[attribIndex]); - if (error.isError()) + return gl::NoError(); +} + +gl::Error VertexDataManager::storeDynamicAttribs( + const gl::Context *context, + std::vector *translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLint start, + GLsizei count, + GLsizei instances) +{ + // Instantiating this class will ensure the streaming buffer is never left mapped. + class StreamingBufferUnmapper final : NonCopyable + { + public: + StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer) + : mStreamingBuffer(streamingBuffer) { - hintUnmapAllResources(vertexAttributes); - return error; + ASSERT(mStreamingBuffer); } + ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); } + + private: + StreamingVertexBufferInterface *mStreamingBuffer; + }; + + // Will trigger unmapping on return. + StreamingBufferUnmapper localUnmapper(mStreamingBuffer.get()); + + // Reserve the required space for the dynamic buffers. + for (auto attribIndex : dynamicAttribsMask) + { + const auto &dynamicAttrib = (*translatedAttribs)[attribIndex]; + ANGLE_TRY(reserveSpaceForAttrib(dynamicAttrib, start, count, instances)); + } + + // Store dynamic attributes + for (auto attribIndex : dynamicAttribsMask) + { + auto *dynamicAttrib = &(*translatedAttribs)[attribIndex]; + ANGLE_TRY(storeDynamicAttrib(context, dynamicAttrib, start, count, instances)); } - // Hint to unmap all the resources - hintUnmapAllResources(vertexAttributes); + return gl::NoError(); +} - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) +void VertexDataManager::PromoteDynamicAttribs( + const gl::Context *context, + const std::vector &translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLsizei count) +{ + for (auto attribIndex : dynamicAttribsMask) { - gl::Buffer *buffer = activeAttrib->attribute->buffer.get(); + const auto &dynamicAttrib = translatedAttribs[attribIndex]; + ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding); + const auto &binding = *dynamicAttrib.binding; + gl::Buffer *buffer = binding.getBuffer().get(); if (buffer) { BufferD3D *bufferD3D = GetImplAs(buffer); - size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute); - bufferD3D->promoteStaticUsage(count * static_cast(typeSize)); + size_t typeSize = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute); + bufferD3D->promoteStaticUsage(context, count * static_cast(typeSize)); } } - - return gl::Error(GL_NO_ERROR); } gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, + GLint start, 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(attrib, D3D_BUFFER_CREATE_IF_NECESSARY) - : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); - - if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType)) + ASSERT(translatedAttrib.attribute && translatedAttrib.binding); + const auto &attrib = *translatedAttrib.attribute; + const auto &binding = *translatedAttrib.binding; + + ASSERT(!DirectStoragePossible(attrib, binding)); + + gl::Buffer *buffer = binding.getBuffer().get(); + BufferD3D *bufferD3D = buffer ? GetImplAs(buffer) : nullptr; + ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr); + + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast(count), static_cast(instances)); + // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead + // of invalid operation here. + if (bufferD3D) { - if (staticBuffer) + // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing + // a non-instanced draw call + GLint firstVertexIndex = binding.getDivisor() > 0 ? 0 : start; + int64_t maxVertexCount = + static_cast(firstVertexIndex) + static_cast(totalCount); + int elementsInBuffer = + ElementsInBuffer(attrib, binding, static_cast(bufferD3D->getSize())); + + if (maxVertexCount > elementsInBuffer) { - if (staticBuffer->getBufferSize() == 0) - { - int totalCount = - ElementsInBuffer(attrib, static_cast(bufferImpl->getSize())); - gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); - if (error.isError()) - { - return error; - } - } - } - else - { - size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); - ASSERT(!bufferImpl || - ElementsInBuffer(attrib, static_cast(bufferImpl->getSize())) >= - static_cast(totalCount)); - - gl::Error error = mStreamingBuffer->reserveVertexSpace( - attrib, static_cast(totalCount), instances); - if (error.isError()) - { - return error; - } + return gl::InvalidOperation() << "Vertex buffer is not big enough for the draw call."; } } - - return gl::Error(GL_NO_ERROR); + return mStreamingBuffer->reserveVertexSpace(attrib, binding, static_cast(totalCount), + instances); } -gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances) +gl::Error VertexDataManager::storeDynamicAttrib(const gl::Context *context, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Buffer *buffer = attrib.buffer.get(); + gl::Buffer *buffer = binding.getBuffer().get(); ASSERT(buffer || attrib.pointer); ASSERT(attrib.enabled); - BufferD3D *storage = buffer ? GetImplAs(buffer) : 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, translated->currentValueType); + BufferD3D *storage = buffer ? GetImplAs(buffer) : nullptr; // Instanced vertices do not apply the 'start' offset - GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start); - - translated->vertexBuffer = vertexBuffer->getVertexBuffer(); - - if (directStorage) - { - 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); - } + GLint firstVertexIndex = (binding.getDivisor() > 0 ? 0 : start); // 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); + ANGLE_TRY(storage->getData(context, &sourceData)); + sourceData += static_cast(ComputeVertexAttributeOffset(attrib, binding)); } else { + // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state. + // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt sourceData = static_cast(attrib.pointer); } unsigned int streamOffset = 0; - unsigned int outputElementSize = 0; - if (staticBuffer) - { - gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - if (error.isError()) - { - return error; - } - - if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) - { - // Convert the entire buffer - 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; - } - } + translated->storage = nullptr; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, 1, 0), translated->stride); - 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); - } + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast(count), static_cast(instances)); - streamOffset += firstElementOffset + startOffset; - } - else - { - size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); - gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mStreamingBuffer->storeDynamicAttribute( + attrib, binding, translated->currentValueType, firstVertexIndex, + static_cast(totalCount), instances, &streamOffset, sourceData)); - error = mStreamingBuffer->storeVertexAttributes( - attrib, translated->currentValueType, firstVertexIndex, - static_cast(totalCount), instances, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } - } + VertexBuffer *vertexBuffer = mStreamingBuffer->getVertexBuffer(); - translated->storage = nullptr; + translated->vertexBuffer.set(vertexBuffer); translated->serial = vertexBuffer->getSerial(); - translated->stride = outputElementSize; - translated->offset = streamOffset; + translated->baseOffset = streamOffset; + translated->usesFirstVertexOffset = false; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, TranslatedAttribute *translated, - CurrentValueState *cachedState) + size_t attribIndex) { + CurrentValueState *cachedState = &mCurrentValueCache[attribIndex]; + auto &buffer = cachedState->buffer; + + if (!buffer) + { + buffer.reset(new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE)); + } + if (cachedState->data != currentValue) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Error error = cachedState->buffer->reserveVertexSpace(attrib, 1, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->reserveVertexSpace(attrib, binding, 1, 0)); const uint8_t *sourceData = reinterpret_cast(currentValue.FloatValues); unsigned int streamOffset; - error = cachedState->buffer->storeVertexAttributes(attrib, currentValue.Type, 0, 1, 0, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->storeDynamicAttribute(attrib, binding, currentValue.Type, 0, 1, 0, + &streamOffset, sourceData)); + + buffer->getVertexBuffer()->hintUnmapResource(); cachedState->data = currentValue; cachedState->offset = streamOffset; } - translated->storage = NULL; - translated->vertexBuffer = cachedState->buffer->getVertexBuffer(); - translated->serial = cachedState->buffer->getSerial(); + translated->vertexBuffer.set(buffer->getVertexBuffer()); + + translated->storage = nullptr; + translated->serial = buffer->getSerial(); translated->divisor = 0; + translated->stride = 0; + translated->baseOffset = static_cast(cachedState->offset); + translated->usesFirstVertexOffset = false; - translated->stride = 0; - translated->offset = static_cast(cachedState->offset); + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +// VertexBufferBinding implementation +VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) +{ } +VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other) + : mBoundVertexBuffer(other.mBoundVertexBuffer) +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } +} + +VertexBufferBinding::~VertexBufferBinding() +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } } + +VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other) +{ + mBoundVertexBuffer = other.mBoundVertexBuffer; + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } + return *this; +} + +void VertexBufferBinding::set(VertexBuffer *vertexBuffer) +{ + if (mBoundVertexBuffer == vertexBuffer) + return; + + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } + if (vertexBuffer) + { + vertexBuffer->addRef(); + } + + mBoundVertexBuffer = vertexBuffer; +} + +VertexBuffer *VertexBufferBinding::get() const +{ + return mBoundVertexBuffer; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h index fb349c4cc2..694366deb7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h @@ -10,14 +10,16 @@ #ifndef LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ #define LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" #include "libANGLE/Constants.h" #include "libANGLE/VertexAttribute.h" -#include "common/angleutils.h" namespace gl { class State; struct VertexAttribute; +class VertexBinding; struct VertexAttribCurrentValueData; } @@ -28,81 +30,123 @@ class BufferFactoryD3D; class StreamingVertexBufferInterface; class VertexBuffer; +class VertexBufferBinding final +{ + public: + VertexBufferBinding(); + VertexBufferBinding(const VertexBufferBinding &other); + ~VertexBufferBinding(); + + void set(VertexBuffer *vertexBuffer); + VertexBuffer *get() const; + VertexBufferBinding &operator=(const VertexBufferBinding &other); + + private: + VertexBuffer *mBoundVertexBuffer; +}; + struct TranslatedAttribute { - TranslatedAttribute() - : active(false), - attribute(NULL), - currentValueType(GL_NONE), - offset(0), - stride(0), - vertexBuffer(NULL), - storage(NULL), - serial(0), - divisor(0) - {} + TranslatedAttribute(); + TranslatedAttribute(const TranslatedAttribute &other); + + // Computes the correct offset from baseOffset, usesFirstVertexOffset, stride and startVertex. + // Can throw an error on integer overflow. + gl::ErrorOrResult computeOffset(GLint startVertex) const; bool active; const gl::VertexAttribute *attribute; + const gl::VertexBinding *binding; GLenum currentValueType; - unsigned int offset; + unsigned int baseOffset; + bool usesFirstVertexOffset; unsigned int stride; // 0 means not to advance the read pointer at all - VertexBuffer *vertexBuffer; + VertexBufferBinding vertexBuffer; BufferD3D *storage; unsigned int serial; unsigned int divisor; }; +enum class VertexStorageType +{ + UNKNOWN, + STATIC, // Translate the vertex data once and re-use it. + DYNAMIC, // Translate the data every frame into a ring buffer. + DIRECT, // Bind a D3D buffer directly without any translation. + CURRENT_VALUE, // Use a single value for the attribute. +}; + +// Given a vertex attribute, return the type of storage it will use. +VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding); + class VertexDataManager : angle::NonCopyable { public: VertexDataManager(BufferFactoryD3D *factory); virtual ~VertexDataManager(); - gl::Error prepareVertexData(const gl::State &state, + gl::Error initialize(); + void deinitialize(); + + gl::Error prepareVertexData(const gl::Context *context, GLint start, GLsizei count, std::vector *translatedAttribs, GLsizei instances); + static void StoreDirectAttrib(TranslatedAttribute *directAttrib); + + static gl::Error StoreStaticAttrib(const gl::Context *context, TranslatedAttribute *translated); + + gl::Error storeDynamicAttribs(const gl::Context *context, + std::vector *translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLint start, + GLsizei count, + GLsizei instances); + + // Promote static usage of dynamic buffers. + static void PromoteDynamicAttribs(const gl::Context *context, + const std::vector &translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLsizei count); + + gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + size_t attribIndex); + private: struct CurrentValueState { CurrentValueState(); ~CurrentValueState(); - StreamingVertexBufferInterface *buffer; + std::unique_ptr buffer; gl::VertexAttribCurrentValueData data; size_t offset; }; gl::Error reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, GLsizei count, + GLint start, GLsizei instances) const; - gl::Error storeAttribute(TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances); - - gl::Error storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - CurrentValueState *cachedState); - - void hintUnmapAllResources(const std::vector &vertexAttributes); + gl::Error storeDynamicAttrib(const gl::Context *context, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances); BufferFactoryD3D *const mFactory; - StreamingVertexBufferInterface *mStreamingBuffer; + std::unique_ptr mStreamingBuffer; std::vector mCurrentValueCache; - - // Cache variables - std::vector mActiveEnabledAttributes; - std::vector mActiveDisabledAttributes; + gl::AttributesMask mDynamicAttribsMaskCache; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h deleted file mode 100644 index 58f65f6496..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/WorkaroundsD3D.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// 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/copyimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp deleted file mode 100644 index b1798454ca..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp +++ /dev/null @@ -1,22 +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. -// - -// copyimage.cpp: Defines image copying functions - -#include "libANGLE/renderer/d3d/copyimage.h" - -namespace rx -{ - -void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest) -{ - uint32_t argb = *reinterpret_cast(source); - *reinterpret_cast(dest) = (argb & 0xFF00FF00) | // Keep alpha and green - (argb & 0x00FF0000) >> 16 | // Move red to blue - (argb & 0x000000FF) << 16; // Move blue to red -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h deleted file mode 100644 index 189654ca39..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// copyimage.h: Defines image copying functions - -#ifndef LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ -#define LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ - -#include "common/mathutil.h" -#include "libANGLE/angletypes.h" - -#include - -namespace rx -{ - -template -void ReadColor(const uint8_t *source, uint8_t *dest); - -template -void WriteColor(const uint8_t *source, uint8_t *dest); - -template -void CopyPixel(const uint8_t *source, uint8_t *dest); - -void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest); - -} - -#include "copyimage.inl" - -#endif // LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl deleted file mode 100644 index 0498cf7750..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// copyimage.inl: Defines image copying functions - -namespace rx -{ - -template -inline void ReadColor(const uint8_t *source, uint8_t *dest) -{ - sourceType::readColor(reinterpret_cast*>(dest), reinterpret_cast(source)); -} - -template -inline void WriteColor(const uint8_t *source, uint8_t *dest) -{ - destType::writeColor(reinterpret_cast(dest), reinterpret_cast*>(source)); -} - -template -inline void CopyPixel(const uint8_t *source, uint8_t *dest) -{ - colorDataType temp; - ReadColor(source, &temp); - WriteColor(&temp, dest); -} - -} 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 e951e13408..f032e888f1 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp @@ -10,112 +10,404 @@ #include +#include "common/utilities.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.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/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "third_party/trace_event/trace_event.h" +namespace rx +{ + +namespace +{ + +// Include inline shaders in the anonymous namespace to make sure no symbols are exported #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrougha2d11ps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum2d11ps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_luma_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_lumaalpha_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_pm_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_luma_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_lumaalpha_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftof_um_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pm_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pm_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pt_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_pt_rgba_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_um_rgb_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/multiplyalpha_ftou_um_rgba_ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11gs.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum3d11ps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepth11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvestencil11_ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" -namespace rx +void StretchedBlitNearest_RowByRow(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + size_t pixelSize, + const uint8_t *sourceData, + uint8_t *destData) { + int srcHeightSubOne = (sourceArea.height - 1); + size_t copySize = pixelSize * destArea.width; + size_t srcOffset = sourceArea.x * pixelSize; + size_t destOffset = destArea.x * pixelSize; -namespace + for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) + { + 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 = static_cast( + gl::clamp(sourceArea.y + floor(yPerc * srcHeightSubOne + 0.5f), 0, srcHeightSubOne)); + unsigned int writeRow = y; + + const uint8_t *sourceRow = sourceData + readRow * sourceRowPitch + srcOffset; + uint8_t *destRow = destData + writeRow * destRowPitch + destOffset; + memcpy(destRow, sourceRow, copySize); + } +} + +void StretchedBlitNearest_PixelByPixel(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) { + auto xMax = clippedDestArea.x + clippedDestArea.width; + auto yMax = clippedDestArea.y + clippedDestArea.height; -DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) + for (int writeRow = clippedDestArea.y; writeRow < yMax; writeRow++) + { + // Interpolate using the original source rectangle to determine which row to sample from + // while clamping to the edges + float yPerc = static_cast(writeRow - destArea.y) / (destArea.height - 1); + float yRounded = floor(yPerc * (sourceArea.height - 1) + 0.5f); + unsigned int readRow = + static_cast(gl::clamp(sourceArea.y + yRounded, 0, sourceSize.height - 1)); + + for (int writeColumn = clippedDestArea.x; writeColumn < xMax; writeColumn++) + { + // Interpolate the original source rectangle to determine which column to sample + // from while clamping to the edges + float xPerc = static_cast(writeColumn - destArea.x) / (destArea.width - 1); + float xRounded = floor(xPerc * (sourceArea.width - 1) + 0.5f); + unsigned int readColumn = static_cast( + gl::clamp(sourceArea.x + xRounded, 0, sourceSize.height - 1)); + + const uint8_t *sourcePixel = + sourceData + readRow * sourceRowPitch + readColumn * srcPixelStride + readOffset; + + uint8_t *destPixel = + destData + writeRow * destRowPitch + writeColumn * destPixelStride + writeOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } +} + +void StretchedBlitNearest(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clipRect, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) { - ID3D11Texture2D *texture = d3d11::DynamicCastComObject(resource); - if (!texture) + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + gl::ClipRectangle(clippedDestArea, clipRect, &clippedDestArea); + + // Determine if entire rows can be copied at once instead of each individual pixel. There + // must be no out of bounds lookups, whole rows copies, and no scale. + if (sourceArea.width == clippedDestArea.width && sourceArea.x >= 0 && + sourceArea.x + sourceArea.width <= sourceSize.width && copySize == srcPixelStride && + copySize == destPixelStride) + { + StretchedBlitNearest_RowByRow(sourceArea, destArea, clippedDestArea, sourceSize, + sourceRowPitch, destRowPitch, srcPixelStride, sourceData, + destData); + } + else { - return DXGI_FORMAT_UNKNOWN; + StretchedBlitNearest_PixelByPixel(sourceArea, destArea, clippedDestArea, sourceSize, + sourceRowPitch, destRowPitch, readOffset, writeOffset, + copySize, srcPixelStride, destPixelStride, sourceData, + destData); } +} - D3D11_TEXTURE2D_DESC desc; - texture->GetDesc(&desc); +using DepthStencilLoader = void(const float *, uint8_t *); - SafeRelease(texture); +void LoadDepth16(const float *source, uint8_t *dest) +{ + uint32_t convertedDepth = gl::floatToNormalized<16, uint32_t>(source[0]); + memcpy(dest, &convertedDepth, 2u); +} - return desc.Format; +void LoadDepth24(const float *source, uint8_t *dest) +{ + uint32_t convertedDepth = gl::floatToNormalized<24, uint32_t>(source[0]); + memcpy(dest, &convertedDepth, 3u); } -ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, - ID3D11Resource *source, unsigned int subresource, - const gl::Extents &size, unsigned int cpuAccessFlags) +void LoadStencilHelper(const float *source, uint8_t *dest) { - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = size.width; - stagingDesc.Height = size.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = GetTextureFormat(source); - stagingDesc.SampleDesc.Count = 1; - stagingDesc.SampleDesc.Quality = 0; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.CPUAccessFlags = cpuAccessFlags; - stagingDesc.MiscFlags = 0; - stagingDesc.BindFlags = 0; - - ID3D11Texture2D *stagingTexture = nullptr; - HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture); - if (FAILED(result)) + uint32_t convertedStencil = gl::getShiftedData<8, 0>(static_cast(source[1])); + memcpy(dest, &convertedStencil, 1u); +} + +void LoadStencil8(const float *source, uint8_t *dest) +{ + // STENCIL_INDEX8 is implemented with D24S8, with the depth bits unused. Writes zero for safety. + float zero = 0.0f; + LoadDepth24(&zero, &dest[0]); + LoadStencilHelper(source, &dest[3]); +} + +void LoadDepth24Stencil8(const float *source, uint8_t *dest) +{ + LoadDepth24(source, &dest[0]); + LoadStencilHelper(source, &dest[3]); +} + +void LoadDepth32F(const float *source, uint8_t *dest) +{ + memcpy(dest, source, sizeof(float)); +} + +void LoadDepth32FStencil8(const float *source, uint8_t *dest) +{ + LoadDepth32F(source, &dest[0]); + LoadStencilHelper(source, &dest[4]); +} + +template +void CopyDepthStencil(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) + { + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const float *sourcePixel = reinterpret_cast(sourceData + offset); + + uint8_t *destPixel = destData + row * destRowPitch + column * destPixelStride; + + loader(sourcePixel, destPixel); + } + } +} + +void Depth32FStencil8ToDepth32F(const float *source, float *dest) +{ + *dest = *source; +} + +void Depth24Stencil8ToDepth32F(const uint32_t *source, float *dest) +{ + uint32_t normDepth = source[0] & 0x00FFFFFF; + float floatDepth = gl::normalizedToFloat<24>(normDepth); + *dest = floatDepth; +} + +void BlitD24S8ToD32F(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) { - ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); - return nullptr; + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const uint32_t *sourcePixel = reinterpret_cast(sourceData + offset); + + float *destPixel = + reinterpret_cast(destData + row * destRowPitch + column * destPixelStride); + + Depth24Stencil8ToDepth32F(sourcePixel, destPixel); + } } +} - context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, nullptr); +void BlitD32FS8ToD32F(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clippedDestArea, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData) +{ + // No stretching or subregions are supported, only full blits. + ASSERT(sourceArea == destArea); + ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && + sourceSize.depth == 1); + ASSERT(clippedDestArea.width == sourceSize.width && + clippedDestArea.height == sourceSize.height); + ASSERT(readOffset == 0 && writeOffset == 0); + ASSERT(destArea.x == 0 && destArea.y == 0); + + for (int row = 0; row < destArea.height; ++row) + { + for (int column = 0; column < destArea.width; ++column) + { + ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; + const float *sourcePixel = reinterpret_cast(sourceData + offset); + float *destPixel = + reinterpret_cast(destData + row * destRowPitch + column * destPixelStride); - return stagingTexture; + Depth32FStencil8ToDepth32F(sourcePixel, destPixel); + } + } +} + +Blit11::BlitConvertFunction *GetCopyDepthStencilFunction(GLenum internalFormat) +{ + switch (internalFormat) + { + case GL_DEPTH_COMPONENT16: + return &CopyDepthStencil; + case GL_DEPTH_COMPONENT24: + return &CopyDepthStencil; + case GL_DEPTH_COMPONENT32F: + return &CopyDepthStencil; + case GL_STENCIL_INDEX8: + return &CopyDepthStencil; + case GL_DEPTH24_STENCIL8: + return &CopyDepthStencil; + case GL_DEPTH32F_STENCIL8: + return &CopyDepthStencil; + default: + UNREACHABLE(); + return nullptr; + } } -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) +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; @@ -128,37 +420,49 @@ inline void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &s *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); } -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, +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); + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, + &u2, &v2); - d3d11::PositionTexCoordVertex *vertices = static_cast(outVertices); + d3d11::PositionTexCoordVertex *vertices = + static_cast(outVertices); d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); - *outStride = sizeof(d3d11::PositionTexCoordVertex); + *outStride = sizeof(d3d11::PositionTexCoordVertex); *outVertexCount = 4; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; } -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, +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); float x1, y1, x2, y2, u1, v1, u2, v2; - GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, + &u2, &v2); - d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast(outVertices); + d3d11::PositionLayerTexCoord3DVertex *vertices = + static_cast(outVertices); for (int i = 0; i < destSize.depth; i++) { @@ -173,24 +477,38 @@ void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); } - *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); *outVertexCount = destSize.depth * 6; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } -inline unsigned int GetSwizzleIndex(GLenum swizzle) +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; + 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; @@ -213,30 +531,50 @@ D3D11_BLEND_DESC GetAlphaMaskBlendStateDesc() 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 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 }, +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 +DXGI_FORMAT GetStencilSRVFormat(const d3d11::Format &formatSet) +{ + switch (formatSet.texFormat) + { + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + case DXGI_FORMAT_R24G8_TYPELESS: + return DXGI_FORMAT_X24_TYPELESS_G8_UINT; + default: + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } +} + +} // namespace + +Blit11::Shader::Shader() = default; + +Blit11::Shader::Shader(Shader &&other) = default; + +Blit11::Shader::~Shader() = default; + +Blit11::Shader &Blit11::Shader::operator=(Blit11::Shader &&other) = default; Blit11::Blit11(Renderer11 *renderer) : mRenderer(renderer), mResourcesInitialized(false), - mVertexBuffer(nullptr), - mPointSampler(nullptr), - mLinearSampler(nullptr), - mScissorEnabledRasterizerState(nullptr), - mScissorDisabledRasterizerState(nullptr), - mDepthStencilState(nullptr), + mVertexBuffer(), + mPointSampler(), + mLinearSampler(), + mScissorEnabledRasterizerState(), + mScissorDisabledRasterizerState(), + mDepthStencilState(), mQuad2DIL(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, @@ -254,516 +592,552 @@ Blit11::Blit11(Renderer11 *renderer) 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) + mSwizzleCB(), + mResolveDepthStencilVS(g_VS_ResolveDepthStencil, + ArraySize(g_VS_ResolveDepthStencil), + "Blit11::mResolveDepthStencilVS"), + mResolveDepthPS(g_PS_ResolveDepth, ArraySize(g_PS_ResolveDepth), "Blit11::mResolveDepthPS"), + mResolveDepthStencilPS(g_PS_ResolveDepthStencil, + ArraySize(g_PS_ResolveDepthStencil), + "Blit11::mResolveDepthStencilPS"), + mResolveStencilPS(g_PS_ResolveStencil, + ArraySize(g_PS_ResolveStencil), + "Blit11::mResolveStencilPS"), + mStencilSRV(), + mResolvedDepthStencilRTView() { } 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); + return gl::NoError(); } TRACE_EVENT0("gpu.angle", "Blit11::initResources"); - HRESULT result; - ID3D11Device *device = mRenderer->getDevice(); - D3D11_BUFFER_DESC vbDesc; 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; + 6 * mRenderer->getNativeCaps().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, 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"); + ANGLE_TRY(mRenderer->allocateResource(vbDesc, &mVertexBuffer)); + mVertexBuffer.setDebugName("Blit11 vertex buffer"); D3D11_SAMPLER_DESC pointSamplerDesc; - pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.MipLODBias = 0.0f; - pointSamplerDesc.MaxAnisotropy = 0; + pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.MipLODBias = 0.0f; + pointSamplerDesc.MaxAnisotropy = 0; pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; pointSamplerDesc.BorderColor[0] = 0.0f; pointSamplerDesc.BorderColor[1] = 0.0f; pointSamplerDesc.BorderColor[2] = 0.0f; pointSamplerDesc.BorderColor[3] = 0.0f; - pointSamplerDesc.MinLOD = 0.0f; - pointSamplerDesc.MaxLOD = FLT_MAX; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = FLT_MAX; - 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"); + ANGLE_TRY(mRenderer->allocateResource(pointSamplerDesc, &mPointSampler)); + mPointSampler.setDebugName("Blit11 point sampler"); D3D11_SAMPLER_DESC linearSamplerDesc; - linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.MipLODBias = 0.0f; - linearSamplerDesc.MaxAnisotropy = 0; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 0; linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; linearSamplerDesc.BorderColor[0] = 0.0f; linearSamplerDesc.BorderColor[1] = 0.0f; linearSamplerDesc.BorderColor[2] = 0.0f; linearSamplerDesc.BorderColor[3] = 0.0f; - linearSamplerDesc.MinLOD = 0.0f; - linearSamplerDesc.MaxLOD = FLT_MAX; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = FLT_MAX; - 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"); + ANGLE_TRY(mRenderer->allocateResource(linearSamplerDesc, &mLinearSampler)); + mLinearSampler.setDebugName("Blit11 linear sampler"); // Use a rasterizer state that will not cull so that inverted quads will not be culled D3D11_RASTERIZER_DESC rasterDesc; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; rasterDesc.FrontCounterClockwise = FALSE; - rasterDesc.DepthBias = 0; - rasterDesc.SlopeScaledDepthBias = 0.0f; - rasterDesc.DepthBiasClamp = 0.0f; - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.MultisampleEnable = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; rasterDesc.AntialiasedLineEnable = FALSE; 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"); + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mScissorEnabledRasterizerState)); + mScissorEnabledRasterizerState.setDebugName("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"); + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mScissorDisabledRasterizerState)); + mScissorDisabledRasterizerState.setDebugName("Blit11 no scissoring rasterizer state"); D3D11_DEPTH_STENCIL_DESC depthStencilDesc; - depthStencilDesc.DepthEnable = true; - depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.StencilEnable = FALSE; - depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.DepthEnable = TRUE; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - - result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - freeResources(); - return gl::Error(GL_OUT_OF_MEMORY, - "Failed to create blit depth stencil state, HRESULT: 0x%X", result); - } - d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + ANGLE_TRY(mRenderer->allocateResource(depthStencilDesc, &mDepthStencilState)); + mDepthStencilState.setDebugName("Blit11 depth stencil state"); D3D11_BUFFER_DESC swizzleBufferDesc; - swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; - swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; - swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - swizzleBufferDesc.MiscFlags = 0; + swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; + swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + swizzleBufferDesc.MiscFlags = 0; swizzleBufferDesc.StructureByteStride = 0; - 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"); + ANGLE_TRY(mRenderer->allocateResource(swizzleBufferDesc, &mSwizzleCB)); + mSwizzleCB.setDebugName("Blit11 swizzle constant buffer"); mResourcesInitialized = true; - return gl::Error(GL_NO_ERROR); -} - -void Blit11::freeResources() -{ - SafeRelease(mVertexBuffer); - SafeRelease(mPointSampler); - SafeRelease(mLinearSampler); - SafeRelease(mScissorEnabledRasterizerState); - SafeRelease(mScissorDisabledRasterizerState); - SafeRelease(mDepthStencilState); - SafeRelease(mSwizzleCB); - - mResourcesInitialized = false; + return gl::NoError(); } // static -Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension) +Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension) { if (dimension == SHADER_3D) { + ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha); + 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; + 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; + 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) { + ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha); + 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; + 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) + bool floatToIntBlit = + !gl::IsIntegerFormat(sourceFormat) && gl::IsIntegerFormat(destinationFormat); + if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha || floatToIntBlit) { - 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; + switch (destinationFormat) + { + case GL_RGBA: + case GL_BGRA_EXT: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBAF_PREMULTIPLY + : BLITSHADER_2D_RGBAF_UNMULTIPLY; + + case GL_RGB: + case GL_RG: + case GL_RED: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBF_PREMULTIPLY + : BLITSHADER_2D_RGBF_UNMULTIPLY; + + case GL_RGBA_INTEGER: + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) + { + return BLITSHADER_2D_RGBAF_TOUI; + } + else + { + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY + : BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY; + } + + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_RED_INTEGER: + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) + { + return BLITSHADER_2D_RGBF_TOUI; + } + else + { + return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY + : BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY; + } + case GL_LUMINANCE: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_LUMAF_PREMULTIPLY + : BLITSHADER_2D_LUMAF_UNMULTIPLY; + case GL_LUMINANCE_ALPHA: + ASSERT(!floatToIntBlit); + return unpackPremultiplyAlpha ? BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY + : BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY; + case GL_ALPHA: + ASSERT(!floatToIntBlit); + return BLITSHADER_2D_ALPHA; + 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; + } } } } // static -Blit11::SwizzleShaderType Blit11::GetSwizzleShaderType(GLenum type, D3D11_SRV_DIMENSION dimensionality) +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: + 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; - } - default: - UNREACHABLE(); - return SWIZZLESHADER_INVALID; } } -Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader) +gl::Error Blit11::getShaderSupport(const Shader &shader, Blit11::ShaderSupport *supportOut) { - ID3D11Device *device = mRenderer->getDevice(); - ShaderSupport support; - if (shader.dimension == SHADER_2D) { - support.inputLayout = mQuad2DIL.resolve(device); - support.vertexShader = mQuad2DVS.resolve(device); - support.geometryShader = nullptr; - support.vertexWriteFunction = Write2DVertices; + ANGLE_TRY(mQuad2DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad2DVS.resolve(mRenderer)); + supportOut->inputLayout = &mQuad2DIL.getObj(); + supportOut->vertexShader = &mQuad2DVS.getObj(); + supportOut->geometryShader = nullptr; + supportOut->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; + ANGLE_TRY(mQuad3DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad3DVS.resolve(mRenderer)); + ANGLE_TRY(mQuad3DGS.resolve(mRenderer)); + supportOut->inputLayout = &mQuad2DIL.getObj(); + supportOut->vertexShader = &mQuad3DVS.getObj(); + supportOut->geometryShader = &mQuad3DGS.getObj(); + supportOut->vertexWriteFunction = Write3DVertices; } - return support; + return gl::NoError(); } -gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, - ID3D11RenderTargetView *dest, +gl::Error Blit11::swizzleTexture(const gl::Context *context, + const d3d11::SharedSRV &source, + const d3d11::RenderTargetView &dest, const gl::Extents &size, - GLenum swizzleRed, - GLenum swizzleGreen, - GLenum swizzleBlue, - GLenum swizzleAlpha) + const gl::SwizzleState &swizzleTarget) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; - source->GetDesc(&sourceSRVDesc); + source.get()->GetDesc(&sourceSRVDesc); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); + if (componentType == GL_NONE) + { + // We're swizzling the depth component of a depth-stencil texture. + switch (sourceSRVDesc.Format) + { + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + componentType = GL_UNSIGNED_NORMALIZED; + break; + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + componentType = GL_FLOAT; + break; + default: + UNREACHABLE(); + break; + } + } GLenum shaderType = GL_NONE; - switch (sourceFormatInfo.componentType) + switch (componentType) { - case GL_UNSIGNED_NORMALIZED: - case GL_SIGNED_NORMALIZED: - case GL_FLOAT: - shaderType = GL_FLOAT; - break; - case GL_INT: - shaderType = GL_INT; - break; - case GL_UNSIGNED_INT: - shaderType = GL_UNSIGNED_INT; - break; - default: - UNREACHABLE(); - break; + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + shaderType = GL_FLOAT; + break; + case GL_INT: + shaderType = GL_INT; + break; + case GL_UNSIGNED_INT: + shaderType = GL_UNSIGNED_INT; + break; + default: + UNREACHABLE(); + break; } const Shader *shader = nullptr; - error = getSwizzleShader(shaderType, sourceSRVDesc.ViewDimension, &shader); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getSwizzleShader(shaderType, sourceSRVDesc.ViewDimension, &shader)); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for swizzle, HRESULT: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for swizzle, " + << gl::FmtHR(result); } - const ShaderSupport &support = getShaderSupport(*shader); + ShaderSupport support; + ANGLE_TRY(getShaderSupport(*shader, &support)); - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; gl::Box area(0, 0, 0, size.width, size.height, size.depth); - support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, + &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); // Set constant buffer - result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = deviceContext->Map(mSwizzleCB.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal constant buffer for swizzle, HRESULT: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map internal constant buffer for swizzle, " + << gl::FmtHR(result); } - unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); - swizzleIndices[0] = GetSwizzleIndex(swizzleRed); - swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); - swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); - swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleTarget.swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleTarget.swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleTarget.swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleTarget.swizzleAlpha); - deviceContext->Unmap(mSwizzleCB, 0); + deviceContext->Unmap(mSwizzleCB.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply constant buffer - deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + stateManager->setPixelConstantBuffer(0, &mSwizzleCB); // Apply state - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF); - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); // Apply shaders - deviceContext->IASetInputLayout(support.inputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(support.vertexShader, nullptr, 0); - - deviceContext->PSSetShader(shader->pixelShader, nullptr, 0); - deviceContext->GSSetShader(support.geometryShader, nullptr, 0); + stateManager->setInputLayout(support.inputLayout); + stateManager->setPrimitiveTopology(topology); - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(support.vertexShader, support.geometryShader, + &shader->pixelShader); // Apply render target - mRenderer->setOneTimeRenderTarget(dest); + stateManager->setRenderTarget(dest.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - 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 - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + stateManager->setSimpleViewport(size); - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); + // Apply textures and sampler + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); // Draw the quad deviceContext->Draw(drawCount, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, +gl::Error Blit11::copyTexture(const gl::Context *context, + const d3d11::SharedSRV &source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, + GLenum sourceFormat, + const d3d11::RenderTargetView &dest, const gl::Box &destArea, const gl::Extents &destSize, const gl::Rectangle *scissor, GLenum destFormat, GLenum filter, - bool maskOffAlpha) + bool maskOffAlpha, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -771,635 +1145,1009 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, // Determine if the source format is a signed integer format, the destFormat will already // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; - source->GetDesc(&sourceSRVDesc); + source.get()->GetDesc(&sourceSRVDesc); + + GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + ASSERT(componentType != GL_NONE); + ASSERT(componentType != GL_SIGNED_NORMALIZED); + bool isSigned = (componentType == GL_INT); - bool isSigned = (internalFormatInfo.componentType == GL_INT); - ShaderDimension dimension = (sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D; + ShaderDimension dimension = + (sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D; const Shader *shader = nullptr; - error = getBlitShader(destFormat, isSigned, dimension, &shader); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getBlitShader(destFormat, sourceFormat, isSigned, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha, dimension, &shader)); - const ShaderSupport &support = getShaderSupport(*shader); + ShaderSupport support; + ANGLE_TRY(getShaderSupport(*shader, &support)); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, " + << gl::FmtHR(result); } - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; support.vertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride, &drawCount, &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply state if (maskOffAlpha) { - ID3D11BlendState *blendState = mAlphaMaskBlendState.resolve(mRenderer->getDevice()); - ASSERT(blendState); - deviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFF); + ANGLE_TRY(mAlphaMaskBlendState.resolve(mRenderer)); + stateManager->setSimpleBlendState(&mAlphaMaskBlendState.getObj()); } else { - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); + stateManager->setSimpleBlendState(nullptr); } - deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); if (scissor) { - D3D11_RECT scissorRect; - scissorRect.left = scissor->x; - scissorRect.right = scissor->x + scissor->width; - scissorRect.top = scissor->y; - scissorRect.bottom = scissor->y + scissor->height; - - deviceContext->RSSetScissorRects(1, &scissorRect); - deviceContext->RSSetState(mScissorEnabledRasterizerState); + stateManager->setSimpleScissorRect(*scissor); + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); } else { - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); } // Apply shaders - deviceContext->IASetInputLayout(support.inputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(support.vertexShader, nullptr, 0); - - deviceContext->PSSetShader(shader->pixelShader, nullptr, 0); - deviceContext->GSSetShader(support.geometryShader, nullptr, 0); + stateManager->setInputLayout(support.inputLayout); + stateManager->setPrimitiveTopology(topology); - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(support.vertexShader, support.geometryShader, + &shader->pixelShader); // Apply render target - mRenderer->setOneTimeRenderTarget(dest); + stateManager->setRenderTarget(dest.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - 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 - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); - - // Apply samplers - ID3D11SamplerState *sampler = nullptr; + stateManager->setSimpleViewport(destSize); + + // Apply texture and sampler switch (filter) { - case GL_NEAREST: sampler = mPointSampler; break; - case GL_LINEAR: sampler = mLinearSampler; break; - - default: - UNREACHABLE(); - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, unknown blit filter mode."); + case GL_NEAREST: + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); + break; + case GL_LINEAR: + stateManager->setSimplePixelTextureAndSampler(source, mLinearSampler); + break; + + default: + UNREACHABLE(); + return gl::InternalError() << "Internal error, unknown blit filter mode."; } - deviceContext->PSSetSamplers(0, 1, &sampler); // Draw the quad deviceContext->Draw(drawCount, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::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, +gl::Error Blit11::copyStencil(const gl::Context *context, + const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor) { - return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, - dest, destSubresource, destArea, destSize, - scissor, true); + return copyDepthStencilImpl(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, true); } -gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, +gl::Error Blit11::copyDepth(const gl::Context *context, + const d3d11::SharedSRV &source, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const d3d11::DepthStencilView &dest, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor) { - gl::Error error = initResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initResources()); HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + result = + deviceContext->Map(mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, " + << gl::FmtHR(result); } - UINT stride = 0; - UINT startIdx = 0; + UINT stride = 0; UINT drawCount = 0; D3D11_PRIMITIVE_TOPOLOGY topology; - Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, - &stride, &drawCount, &topology); + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride, + &drawCount, &topology); - deviceContext->Unmap(mVertexBuffer, 0); + deviceContext->Unmap(mVertexBuffer.get(), 0); + + StateManager11 *stateManager = mRenderer->getStateManager(); // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); // Apply state - deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(&mDepthStencilState, 0xFFFFFFFF); if (scissor) { - D3D11_RECT scissorRect; - scissorRect.left = scissor->x; - scissorRect.right = scissor->x + scissor->width; - scissorRect.top = scissor->y; - scissorRect.bottom = scissor->y + scissor->height; - - deviceContext->RSSetScissorRects(1, &scissorRect); - deviceContext->RSSetState(mScissorEnabledRasterizerState); + stateManager->setSimpleScissorRect(*scissor); + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); } else { - deviceContext->RSSetState(mScissorDisabledRasterizerState); + stateManager->setRasterizerState(&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"); - } + ANGLE_TRY(mQuad2DIL.resolve(mRenderer)); + ANGLE_TRY(mQuad2DVS.resolve(mRenderer)); + ANGLE_TRY(mDepthPS.resolve(mRenderer)); // Apply shaders - deviceContext->IASetInputLayout(mQuad2DIL.resolve(device)); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(quad2DVS, nullptr, 0); + stateManager->setInputLayout(&mQuad2DIL.getObj()); + stateManager->setPrimitiveTopology(topology); - deviceContext->PSSetShader(mDepthPS.resolve(device), nullptr, 0); - deviceContext->GSSetShader(nullptr, nullptr, 0); - - // Unset the currently bound shader resource to avoid conflicts - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); + stateManager->setDrawShaders(&mQuad2DVS.getObj(), nullptr, &mDepthPS.getObj()); // Apply render target - deviceContext->OMSetRenderTargets(0, nullptr, dest); + stateManager->setRenderTarget(nullptr, dest.get()); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - 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 - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + stateManager->setSimpleViewport(destSize); - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); + // Apply texture and sampler + stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); // Draw the quad deviceContext->Draw(drawCount, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = nullptr; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::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, +gl::Error Blit11::copyDepthStencil(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor) { - return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, - dest, destSubresource, destArea, destSize, - scissor, false); + return copyDepthStencilImpl(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, false); } -gl::Error Blit11::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) +gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &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; - } + auto srcDXGIFormat = source.getFormat(); + const auto &srcSizeInfo = d3d11::GetDXGIFormatSizeInfo(srcDXGIFormat); + unsigned int srcPixelSize = srcSizeInfo.pixelBytes; + unsigned int copyOffset = 0; + unsigned int copySize = srcPixelSize; + auto destDXGIFormat = dest.getFormat(); + const auto &destSizeInfo = d3d11::GetDXGIFormatSizeInfo(destDXGIFormat); + unsigned int destPixelSize = destSizeInfo.pixelBytes; - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ASSERT(srcDXGIFormat == destDXGIFormat || destDXGIFormat == DXGI_FORMAT_R32_TYPELESS); - ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); - // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called - // using it's mapped data as a source - ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + if (stencilOnly) + { + const auto &srcFormat = source.getFormatSet().format(); + + // Stencil channel should be right after the depth channel. Some views to depth/stencil + // resources have red channel for depth, in which case the depth channel bit width is in + // redBits. + ASSERT((srcFormat.redBits != 0) != (srcFormat.depthBits != 0)); + GLuint depthBits = srcFormat.redBits + srcFormat.depthBits; + // Known formats have either 24 or 32 bits of depth. + ASSERT(depthBits == 24 || depthBits == 32); + copyOffset = depthBits / 8; + + // Stencil is assumed to be 8-bit - currently this is true for all possible formats. + copySize = 1; + } - if (!sourceStaging || !destStaging) + if (srcDXGIFormat != destDXGIFormat) { - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); + if (srcDXGIFormat == DXGI_FORMAT_R24G8_TYPELESS) + { + ASSERT(sourceArea == destArea && sourceSize == destSize && scissor == nullptr); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, copyOffset, + copyOffset, copySize, srcPixelSize, destPixelSize, + BlitD24S8ToD32F); + } + ASSERT(srcDXGIFormat == DXGI_FORMAT_R32G8X24_TYPELESS); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, + destSubresource, destArea, destSize, scissor, copyOffset, copyOffset, + copySize, srcPixelSize, destPixelSize, BlitD32FS8ToD32F); } - DXGI_FORMAT format = GetTextureFormat(source); - ASSERT(format == GetTextureFormat(dest)); + return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource, + destArea, destSize, scissor, copyOffset, copyOffset, copySize, + srcPixelSize, destPixelSize, StretchedBlitNearest); +} - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); - unsigned int pixelSize = dxgiFormatInfo.pixelBytes; - unsigned int copyOffset = 0; - unsigned int copySize = pixelSize; - if (stencilOnly) - { - copyOffset = dxgiFormatInfo.depthBits / 8; - copySize = dxgiFormatInfo.stencilBits / 8; +gl::Error Blit11::copyAndConvertImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &destStaging, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction) +{ + ANGLE_TRY(initResources()); - // It would be expensive to have non-byte sized stencil sizes since it would - // require reading from the destination, currently there aren't any though. - ASSERT(dxgiFormatInfo.stencilBits % 8 == 0 && - dxgiFormatInfo.depthBits % 8 == 0); - } + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + TextureHelper11 sourceStaging; + ANGLE_TRY_RESULT(mRenderer->createStagingTexture(ResourceType::Texture2D, source.getFormatSet(), + sourceSize, StagingAccess::READ), + sourceStaging); + + deviceContext->CopySubresourceRegion(sourceStaging.get(), 0, 0, 0, 0, source.get(), + sourceSubresource, nullptr); D3D11_MAPPED_SUBRESOURCE sourceMapping; - HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + HRESULT result = deviceContext->Map(sourceStaging.get(), 0, D3D11_MAP_READ, 0, &sourceMapping); if (FAILED(result)) { - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal source staging texture for depth stencil blit, HRESULT: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to map internal source staging texture for depth stencil blit, " + << gl::FmtHR(result); } D3D11_MAPPED_SUBRESOURCE destMapping; - result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + result = deviceContext->Map(destStaging.get(), 0, D3D11_MAP_WRITE, 0, &destMapping); if (FAILED(result)) { - deviceContext->Unmap(sourceStaging, 0); - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal destination staging texture for depth stencil blit, HRESULT: 0x%X.", result); + deviceContext->Unmap(sourceStaging.get(), 0); + return gl::OutOfMemory() + << "Failed to map internal destination staging texture for depth stencil blit, " + << gl::FmtHR(result); } - gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); - // Clip dest area to the destination size - gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); + gl::Rectangle clipRect = gl::Rectangle(0, 0, destSize.width, destSize.height); // Clip dest area to the scissor if (scissor) { - gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + gl::ClipRectangle(clipRect, *scissor, &clipRect); } - // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is - // no out of bounds lookups required, the entire pixel is copied and no stretching - bool wholeRowCopy = sourceArea.width == clippedDestArea.width && - sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && - copySize == pixelSize; + convertFunction(sourceArea, destArea, clipRect, sourceSize, sourceMapping.RowPitch, + destMapping.RowPitch, readOffset, writeOffset, copySize, srcPixelStride, + destPixelStride, static_cast(sourceMapping.pData), + static_cast(destMapping.pData)); - for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) - { - float yPerc = static_cast(y - destArea.y) / (destArea.height - 1); + deviceContext->Unmap(sourceStaging.get(), 0); + deviceContext->Unmap(destStaging.get(), 0); - // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges - 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) - { - void *sourceRow = reinterpret_cast(sourceMapping.pData) + - readRow * sourceMapping.RowPitch + - sourceArea.x * pixelSize; + return gl::NoError(); +} - void *destRow = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - destArea.x * pixelSize; +gl::Error Blit11::copyAndConvert(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction) +{ + ANGLE_TRY(initResources()); - memcpy(destRow, sourceRow, pixelSize * destArea.width); - } - else - { - for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) - { - float xPerc = static_cast(x - destArea.x) / (destArea.width - 1); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges - unsigned int readColumn = static_cast(gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1)); - unsigned int writeColumn = x; + // HACK: Create the destination staging buffer as a read/write texture so + // ID3D11DevicContext::UpdateSubresource can be called + // using it's mapped data as a source + TextureHelper11 destStaging; + ANGLE_TRY_RESULT(mRenderer->createStagingTexture(ResourceType::Texture2D, dest.getFormatSet(), + destSize, StagingAccess::READ_WRITE), + destStaging); - void *sourcePixel = reinterpret_cast(sourceMapping.pData) + - readRow * sourceMapping.RowPitch + - readColumn * pixelSize + - copyOffset; + deviceContext->CopySubresourceRegion(destStaging.get(), 0, 0, 0, 0, dest.get(), destSubresource, + nullptr); - void *destPixel = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - writeColumn * pixelSize + - copyOffset; + ANGLE_TRY(copyAndConvertImpl(source, sourceSubresource, sourceArea, sourceSize, destStaging, + destArea, destSize, scissor, readOffset, writeOffset, copySize, + srcPixelStride, destPixelStride, convertFunction)); - memcpy(destPixel, sourcePixel, copySize); - } - } + // Work around timeouts/TDRs in older NVIDIA drivers. + if (mRenderer->getWorkarounds().depthStencilBlitExtraCopy) + { + D3D11_MAPPED_SUBRESOURCE mapped; + deviceContext->Map(destStaging.get(), 0, D3D11_MAP_READ, 0, &mapped); + deviceContext->UpdateSubresource(dest.get(), destSubresource, nullptr, mapped.pData, + mapped.RowPitch, mapped.DepthPitch); + deviceContext->Unmap(destStaging.get(), 0); + } + else + { + deviceContext->CopySubresourceRegion(dest.get(), destSubresource, 0, 0, 0, + destStaging.get(), 0, nullptr); } - // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion - // according to MSDN. - 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, nullptr); - - SafeRelease(sourceStaging); - SafeRelease(destStaging); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Blit11::addBlitShaderToMap(BlitShaderType blitShaderType, ShaderDimension dimension, ID3D11PixelShader *ps) +gl::Error Blit11::addBlitShaderToMap(BlitShaderType blitShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name) { ASSERT(mBlitShaderMap.find(blitShaderType) == mBlitShaderMap.end()); - ASSERT(ps); + + d3d11::PixelShader ps; + ANGLE_TRY(mRenderer->allocateResource(shaderData, &ps)); + ps.setDebugName(name); Shader shader; - shader.dimension = dimension; - shader.pixelShader = ps; + shader.dimension = dimension; + shader.pixelShader = std::move(ps); - mBlitShaderMap[blitShaderType] = shader; + mBlitShaderMap[blitShaderType] = std::move(shader); + return gl::NoError(); } -void Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps) +gl::Error Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name) { ASSERT(mSwizzleShaderMap.find(swizzleShaderType) == mSwizzleShaderMap.end()); - ASSERT(ps); + + d3d11::PixelShader ps; + ANGLE_TRY(mRenderer->allocateResource(shaderData, &ps)); + ps.setDebugName(name); Shader shader; - shader.dimension = dimension; - shader.pixelShader = ps; + shader.dimension = dimension; + shader.pixelShader = std::move(ps); - mSwizzleShaderMap[swizzleShaderType] = shader; + mSwizzleShaderMap[swizzleShaderType] = std::move(shader); + return gl::NoError(); } void Blit11::clearShaderMap() { - for (auto &blitShader : mBlitShaderMap) - { - SafeRelease(blitShader.second.pixelShader); - } mBlitShaderMap.clear(); - - for (auto &swizzleShader : mSwizzleShaderMap) - { - SafeRelease(swizzleShader.second.pixelShader); - } mSwizzleShaderMap.clear(); } -gl::Error Blit11::getBlitShader(GLenum destFormat, bool isSigned, ShaderDimension dimension, const Shader **shader) +gl::Error Blit11::getBlitShader(GLenum destFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension, + const Shader **shader) { - BlitShaderType blitShaderType = GetBlitShaderType(destFormat, isSigned, dimension); + BlitShaderType blitShaderType = + GetBlitShaderType(destFormat, sourceFormat, isSigned, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha, dimension); if (blitShaderType == BLITSHADER_INVALID) { - return gl::Error(GL_INVALID_OPERATION, "Internal blit shader type mismatch"); + return gl::InternalError() << "Internal blit shader type mismatch"; } auto blitShaderIt = mBlitShaderMap.find(blitShaderType); if (blitShaderIt != mBlitShaderMap.end()) { *shader = &blitShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } 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(); - return gl::Error(GL_INVALID_OPERATION, "Internal error"); + case BLITSHADER_2D_RGBAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2D), + "Blit11 2D RGBA pixel shader")); + break; + case BLITSHADER_2D_BGRAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2D), + "Blit11 2D BGRA pixel shader")); + break; + case BLITSHADER_2D_RGBF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2D), + "Blit11 2D RGB pixel shader")); + break; + case BLITSHADER_2D_RGF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2D), + "Blit11 2D RG pixel shader")); + break; + case BLITSHADER_2D_RF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_PassthroughR2D), + "Blit11 2D R pixel shader")); + break; + case BLITSHADER_2D_ALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_PassthroughA2D), + "Blit11 2D alpha pixel shader")); + break; + case BLITSHADER_2D_LUMA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughLum2D), + "Blit11 2D lum pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughLumAlpha2D), + "Blit11 2D luminance alpha pixel shader")); + break; + case BLITSHADER_2D_RGBAUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2DUI), + "Blit11 2D RGBA UI pixel shader")); + break; + case BLITSHADER_2D_RGBAI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGBA2DI), + "Blit11 2D RGBA I pixel shader")); + break; + case BLITSHADER_2D_RGBUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2DUI), + "Blit11 2D RGB UI pixel shader")); + break; + case BLITSHADER_2D_RGBI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRGB2DI), + "Blit11 2D RGB I pixel shader")); + break; + case BLITSHADER_2D_RGUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2DUI), + "Blit11 2D RG UI pixel shader")); + break; + case BLITSHADER_2D_RGI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughRG2DI), + "Blit11 2D RG I pixel shader")); + break; + case BLITSHADER_2D_RUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughR2DUI), + "Blit11 2D R UI pixel shader")); + break; + case BLITSHADER_2D_RI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_PassthroughR2DI), + "Blit11 2D R I pixel shader")); + break; + case BLITSHADER_3D_RGBAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D RGBA pixel shader")); + break; + case BLITSHADER_3D_RGBAUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3DUI), + "Blit11 3D UI RGBA pixel shader")); + break; + case BLITSHADER_3D_RGBAI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3DI), + "Blit11 3D I RGBA pixel shader")); + break; + case BLITSHADER_3D_BGRAF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D BGRA pixel shader")); + break; + case BLITSHADER_3D_RGBF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3D), + "Blit11 3D RGB pixel shader")); + break; + case BLITSHADER_3D_RGBUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3DUI), + "Blit11 3D RGB UI pixel shader")); + break; + case BLITSHADER_3D_RGBI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGB3DI), + "Blit11 3D RGB I pixel shader")); + break; + case BLITSHADER_3D_RGF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3D), + "Blit11 3D RG pixel shader")); + break; + case BLITSHADER_3D_RGUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3DUI), + "Blit11 3D RG UI pixel shader")); + break; + case BLITSHADER_3D_RGI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRG3DI), + "Blit11 3D RG I pixel shader")); + break; + case BLITSHADER_3D_RF: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, ShaderData(g_PS_PassthroughR3D), + "Blit11 3D R pixel shader")); + break; + case BLITSHADER_3D_RUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughR3DUI), + "Blit11 3D R UI pixel shader")); + break; + case BLITSHADER_3D_RI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughR3DI), + "Blit11 3D R I pixel shader")); + break; + case BLITSHADER_3D_ALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughRGBA3D), + "Blit11 3D alpha pixel shader")); + break; + case BLITSHADER_3D_LUMA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughLum3D), + "Blit11 3D luminance pixel shader")); + break; + case BLITSHADER_3D_LUMAALPHA: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_3D, + ShaderData(g_PS_PassthroughLumAlpha3D), + "Blit11 3D luminance alpha pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_RGBA), + "Blit11 2D RGBA premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_RGBA), + "Blit11 2D RGBA unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_RGB), + "Blit11 2D RGB premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_RGB), + "Blit11 2D RGB unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PT_RGBA), + "Blit11 2D RGBA to uint pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PM_RGBA), + "Blit11 2D RGBA to uint premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_UM_RGBA), + "Blit11 2D RGBA to uint unmultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PT_RGB), + "Blit11 2D RGB to uint pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_PM_RGB), + "Blit11 2D RGB to uint premultiply pixel shader")); + break; + + case BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoU_UM_RGB), + "Blit11 2D RGB to uint unmultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_PM_LUMA), + "Blit11 2D LUMA premultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, ShaderData(g_PS_FtoF_UM_LUMA), + "Blit11 2D LUMA unmultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_FtoF_PM_LUMAALPHA), + "Blit11 2D LUMAALPHA premultiply pixel shader")); + break; + case BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY: + ANGLE_TRY(addBlitShaderToMap(blitShaderType, SHADER_2D, + ShaderData(g_PS_FtoF_UM_LUMAALPHA), + "Blit11 2D LUMAALPHA unmultiply pixel shader")); + break; + + default: + UNREACHABLE(); + return gl::InternalError() << "Internal error"; } blitShaderIt = mBlitShaderMap.find(blitShaderType); ASSERT(blitShaderIt != mBlitShaderMap.end()); *shader = &blitShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit11::getSwizzleShader(GLenum type, D3D11_SRV_DIMENSION viewDimension, const Shader **shader) +gl::Error Blit11::getSwizzleShader(GLenum type, + D3D11_SRV_DIMENSION viewDimension, + const Shader **shader) { SwizzleShaderType swizzleShaderType = GetSwizzleShaderType(type, viewDimension); if (swizzleShaderType == SWIZZLESHADER_INVALID) { - return gl::Error(GL_INVALID_OPERATION, "Swizzle shader type not found"); + return gl::InternalError() << "Swizzle shader type not found"; } auto swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); if (swizzleShaderIt != mSwizzleShaderMap.end()) { *shader = &swizzleShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Swizzling shaders (OpenGL ES 3+) ASSERT(mRenderer->isES3Capable()); - ID3D11Device *device = mRenderer->getDevice(); - switch (swizzleShaderType) { - 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"); + case SWIZZLESHADER_2D_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleF2D), + "Blit11 2D F swizzle pixel shader")); + break; + case SWIZZLESHADER_2D_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleUI2D), + "Blit11 2D UI swizzle pixel shader")); + break; + case SWIZZLESHADER_2D_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_2D, + ShaderData(g_PS_SwizzleI2D), + "Blit11 2D I swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF2DArray), + "Blit11 2D Cube F swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI2DArray), + "Blit11 2D Cube UI swizzle pixel shader")); + break; + case SWIZZLESHADER_CUBE_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI2DArray), + "Blit11 2D Cube I swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF3D), + "Blit11 3D F swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI3D), + "Blit11 3D UI swizzle pixel shader")); + break; + case SWIZZLESHADER_3D_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI3D), + "Blit11 3D I swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_FLOAT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleF2DArray), + "Blit11 2D Array F swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_UINT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleUI2DArray), + "Blit11 2D Array UI swizzle pixel shader")); + break; + case SWIZZLESHADER_ARRAY_INT: + ANGLE_TRY(addSwizzleShaderToMap(swizzleShaderType, SHADER_3D, + ShaderData(g_PS_SwizzleI2DArray), + "Blit11 2D Array I swizzle pixel shader")); + break; + default: + UNREACHABLE(); + return gl::InternalError() << "Internal error"; } swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); ASSERT(swizzleShaderIt != mSwizzleShaderMap.end()); *shader = &swizzleShaderIt->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } +gl::ErrorOrResult Blit11::resolveDepth(const gl::Context *context, + RenderTarget11 *depth) +{ + ANGLE_TRY(initResources()); + + // Multisampled depth stencil SRVs are not available in feature level 10.0 + ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); + + const auto &extents = depth->getExtents(); + auto *deviceContext = mRenderer->getDeviceContext(); + auto *stateManager = mRenderer->getStateManager(); + + ANGLE_TRY(initResolveDepthOnly(depth->getFormatSet(), extents)); + + ANGLE_TRY(mResolveDepthStencilVS.resolve(mRenderer)); + ANGLE_TRY(mResolveDepthPS.resolve(mRenderer)); + + // Apply the necessary state changes to the D3D11 immediate device context. + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, + &mResolveDepthPS.getObj()); + stateManager->setRasterizerState(nullptr); + stateManager->setDepthStencilState(&mDepthStencilState, 0xFFFFFFFF); + stateManager->setRenderTargets(nullptr, 0, mResolvedDepthDSView.get()); + stateManager->setSimpleBlendState(nullptr); + stateManager->setSimpleViewport(extents); + + // Set the viewport + stateManager->setShaderResourceShared(gl::SAMPLER_PIXEL, 0, &depth->getShaderResourceView()); + + // Trigger the blit on the GPU. + deviceContext->Draw(6, 0); + + return mResolvedDepth; } + +gl::Error Blit11::initResolveDepthOnly(const d3d11::Format &format, const gl::Extents &extents) +{ + if (mResolvedDepth.valid() && extents == mResolvedDepth.getExtents() && + format.texFormat == mResolvedDepth.getFormat()) + { + return gl::NoError(); + } + + D3D11_TEXTURE2D_DESC textureDesc; + textureDesc.Width = extents.width; + textureDesc.Height = extents.height; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = format.texFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateTexture(textureDesc, format, &mResolvedDepth)); + mResolvedDepth.setDebugName("Blit11::mResolvedDepth"); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = 0; + dsvDesc.Format = format.dsvFormat; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, mResolvedDepth.get(), &mResolvedDepthDSView)); + mResolvedDepthDSView.setDebugName("Blit11::mResolvedDepthDSView"); + + // Possibly D3D11 bug or undefined behaviour: Clear the DSV so that our first render + // works as expected. Otherwise the results of the first use seem to be incorrect. + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->ClearDepthStencilView(mResolvedDepthDSView.get(), D3D11_CLEAR_DEPTH, 1.0f, 0); + + return gl::NoError(); +} + +gl::Error Blit11::initResolveDepthStencil(const gl::Extents &extents) +{ + // Check if we need to recreate depth stencil view + if (mResolvedDepthStencil.valid() && extents == mResolvedDepthStencil.getExtents()) + { + ASSERT(mResolvedDepthStencil.getFormat() == DXGI_FORMAT_R32G32_FLOAT); + return gl::NoError(); + } + + if (mResolvedDepthStencil.valid()) + { + releaseResolveDepthStencilResources(); + } + + const auto &formatSet = d3d11::Format::Get(GL_RG32F, mRenderer->getRenderer11DeviceCaps()); + + D3D11_TEXTURE2D_DESC textureDesc; + textureDesc.Width = extents.width; + textureDesc.Height = extents.height; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = formatSet.texFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateTexture(textureDesc, formatSet, &mResolvedDepthStencil)); + mResolvedDepthStencil.setDebugName("Blit11::mResolvedDepthStencil"); + + ANGLE_TRY(mRenderer->allocateResourceNoDesc(mResolvedDepthStencil.get(), + &mResolvedDepthStencilRTView)); + mResolvedDepthStencilRTView.setDebugName("Blit11::mResolvedDepthStencilRTView"); + + return gl::NoError(); +} + +gl::ErrorOrResult Blit11::resolveStencil(const gl::Context *context, + RenderTarget11 *depthStencil, + bool alsoDepth) +{ + ANGLE_TRY(initResources()); + + // Multisampled depth stencil SRVs are not available in feature level 10.0 + ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); + + const auto &extents = depthStencil->getExtents(); + + ANGLE_TRY(initResolveDepthStencil(extents)); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto *stateManager = mRenderer->getStateManager(); + ID3D11Resource *stencilResource = depthStencil->getTexture().get(); + + // Check if we need to re-create the stencil SRV. + if (mStencilSRV.valid()) + { + ID3D11Resource *priorResource = nullptr; + mStencilSRV.get()->GetResource(&priorResource); + + if (stencilResource != priorResource) + { + mStencilSRV.reset(); + } + + SafeRelease(priorResource); + } + + if (!mStencilSRV.valid()) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srViewDesc; + srViewDesc.Format = GetStencilSRVFormat(depthStencil->getFormatSet()); + srViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + + ANGLE_TRY(mRenderer->allocateResource(srViewDesc, stencilResource, &mStencilSRV)); + mStencilSRV.setDebugName("Blit11::mStencilSRV"); + } + + // Notify the Renderer that all state should be invalidated. + ANGLE_TRY(mResolveDepthStencilVS.resolve(mRenderer)); + + // Resolving the depth buffer works by sampling the depth in the shader using a SRV, then + // writing to the resolved depth buffer using SV_Depth. We can't use this method for stencil + // because SV_StencilRef isn't supported until HLSL 5.1/D3D11.3. + const d3d11::PixelShader *pixelShader = nullptr; + if (alsoDepth) + { + ANGLE_TRY(mResolveDepthStencilPS.resolve(mRenderer)); + pixelShader = &mResolveDepthStencilPS.getObj(); + } + else + { + ANGLE_TRY(mResolveStencilPS.resolve(mRenderer)); + pixelShader = &mResolveStencilPS.getObj(); + } + + // Apply the necessary state changes to the D3D11 immediate device context. + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, pixelShader); + stateManager->setRasterizerState(nullptr); + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setRenderTarget(mResolvedDepthStencilRTView.get(), nullptr); + stateManager->setSimpleBlendState(nullptr); + + // Set the viewport + stateManager->setSimpleViewport(extents); + stateManager->setShaderResourceShared(gl::SAMPLER_PIXEL, 0, + &depthStencil->getShaderResourceView()); + stateManager->setShaderResource(gl::SAMPLER_PIXEL, 1, &mStencilSRV); + + // Trigger the blit on the GPU. + deviceContext->Draw(6, 0); + + gl::Box copyBox(0, 0, 0, extents.width, extents.height, 1); + + TextureHelper11 dest; + ANGLE_TRY_RESULT( + mRenderer->createStagingTexture(ResourceType::Texture2D, depthStencil->getFormatSet(), + extents, StagingAccess::READ_WRITE), + dest); + + const auto ©Function = GetCopyDepthStencilFunction(depthStencil->getInternalFormat()); + const auto &dsFormatSet = depthStencil->getFormatSet(); + const auto &dsDxgiInfo = d3d11::GetDXGIFormatSizeInfo(dsFormatSet.texFormat); + + ANGLE_TRY(copyAndConvertImpl(mResolvedDepthStencil, 0, copyBox, extents, dest, copyBox, extents, + nullptr, 0, 0, 0, 8u, dsDxgiInfo.pixelBytes, copyFunction)); + + // Return the resolved depth texture, which the caller must Release. + return dest; +} + +void Blit11::releaseResolveDepthStencilResources() +{ + mStencilSRV.reset(); + mResolvedDepthStencilRTView.reset(); +} + +} // namespace rx 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 906616131e..14078f9db8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h @@ -10,8 +10,9 @@ #define LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ #include "common/angleutils.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Error.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include @@ -26,36 +27,84 @@ class Blit11 : angle::NonCopyable explicit Blit11(Renderer11 *renderer); ~Blit11(); - gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, - GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + gl::Error swizzleTexture(const gl::Context *context, + const d3d11::SharedSRV &source, + const d3d11::RenderTargetView &dest, + const gl::Extents &size, + const gl::SwizzleState &swizzleTarget); - gl::Error copyTexture(ID3D11ShaderResourceView *source, + gl::Error copyTexture(const gl::Context *context, + const d3d11::SharedSRV &source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, + GLenum sourceFormat, + const d3d11::RenderTargetView &dest, const gl::Box &destArea, const gl::Extents &destSize, const gl::Rectangle *scissor, GLenum destFormat, GLenum filter, - bool maskOffAlpha); + bool maskOffAlpha, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); - 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, + gl::Error copyStencil(const gl::Context *context, + const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor); - gl::Error copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + gl::Error copyDepth(const gl::Context *context, + const d3d11::SharedSRV &source, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const d3d11::DepthStencilView &dest, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor); - 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, + gl::Error copyDepthStencil(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, const gl::Rectangle *scissor); + gl::ErrorOrResult resolveDepth(const gl::Context *context, + RenderTarget11 *depth); + + gl::ErrorOrResult resolveStencil(const gl::Context *context, + RenderTarget11 *depthStencil, + bool alsoDepth); + + using BlitConvertFunction = void(const gl::Box &sourceArea, + const gl::Box &destArea, + const gl::Rectangle &clipRect, + const gl::Extents &sourceSize, + unsigned int sourceRowPitch, + unsigned int destRowPitch, + ptrdiff_t readOffset, + ptrdiff_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + const uint8_t *sourceData, + uint8_t *destData); + private: enum BlitShaderType { BLITSHADER_INVALID, + + // Passthrough shaders BLITSHADER_2D_RGBAF, BLITSHADER_2D_BGRAF, BLITSHADER_2D_RGBF, @@ -88,6 +137,27 @@ class Blit11 : angle::NonCopyable BLITSHADER_3D_ALPHA, BLITSHADER_3D_LUMA, BLITSHADER_3D_LUMAALPHA, + + // Multiply alpha shaders + BLITSHADER_2D_RGBAF_PREMULTIPLY, + BLITSHADER_2D_RGBAF_UNMULTIPLY, + + BLITSHADER_2D_RGBF_PREMULTIPLY, + BLITSHADER_2D_RGBF_UNMULTIPLY, + + BLITSHADER_2D_RGBAF_TOUI, + BLITSHADER_2D_RGBAF_TOUI_PREMULTIPLY, + BLITSHADER_2D_RGBAF_TOUI_UNMULTIPLY, + + BLITSHADER_2D_RGBF_TOUI, + BLITSHADER_2D_RGBF_TOUI_PREMULTIPLY, + BLITSHADER_2D_RGBF_TOUI_UNMULTIPLY, + + BLITSHADER_2D_LUMAF_PREMULTIPLY, + BLITSHADER_2D_LUMAF_UNMULTIPLY, + + BLITSHADER_2D_LUMAALPHAF_PREMULTIPLY, + BLITSHADER_2D_LUMAALPHAF_UNMULTIPLY }; enum SwizzleShaderType @@ -107,9 +177,13 @@ class Blit11 : angle::NonCopyable 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, + 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); enum ShaderDimension @@ -120,38 +194,102 @@ class Blit11 : angle::NonCopyable struct Shader { + Shader(); + Shader(Shader &&other); + ~Shader(); + Shader &operator=(Shader &&other); + ShaderDimension dimension; - ID3D11PixelShader *pixelShader; + d3d11::PixelShader pixelShader; }; struct ShaderSupport { - ID3D11InputLayout *inputLayout; - ID3D11VertexShader *vertexShader; - ID3D11GeometryShader *geometryShader; + const d3d11::InputLayout *inputLayout; + const d3d11::VertexShader *vertexShader; + const d3d11::GeometryShader *geometryShader; WriteVertexFunction vertexWriteFunction; }; gl::Error initResources(); - void freeResources(); - ShaderSupport getShaderSupport(const Shader &shader); + gl::Error getShaderSupport(const Shader &shader, ShaderSupport *supportOut); - static BlitShaderType GetBlitShaderType(GLenum destinationFormat, bool isSigned, ShaderDimension dimension); + static BlitShaderType GetBlitShaderType(GLenum destinationFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + 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); - - 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(SwizzleShaderType swizzleShaderType, ShaderDimension dimension, ID3D11PixelShader *ps); + gl::Error copyDepthStencilImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + bool stencilOnly); + + gl::Error copyAndConvertImpl(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &destStaging, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction); + + gl::Error copyAndConvert(const TextureHelper11 &source, + unsigned int sourceSubresource, + const gl::Box &sourceArea, + const gl::Extents &sourceSize, + const TextureHelper11 &dest, + unsigned int destSubresource, + const gl::Box &destArea, + const gl::Extents &destSize, + const gl::Rectangle *scissor, + size_t readOffset, + size_t writeOffset, + size_t copySize, + size_t srcPixelStride, + size_t destPixelStride, + BlitConvertFunction *convertFunction); + + gl::Error addBlitShaderToMap(BlitShaderType blitShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name); + + gl::Error getBlitShader(GLenum destFormat, + GLenum sourceFormat, + bool isSigned, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + ShaderDimension dimension, + const Shader **shaderOut); + gl::Error getSwizzleShader(GLenum type, + D3D11_SRV_DIMENSION viewDimension, + const Shader **shaderOut); + + gl::Error addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType, + ShaderDimension dimension, + const ShaderData &shaderData, + const char *name); void clearShaderMap(); + void releaseResolveDepthStencilResources(); + gl::Error initResolveDepthOnly(const d3d11::Format &format, const gl::Extents &extents); + gl::Error initResolveDepthStencil(const gl::Extents &extents); Renderer11 *mRenderer; @@ -159,12 +297,12 @@ class Blit11 : angle::NonCopyable std::map mSwizzleShaderMap; bool mResourcesInitialized; - ID3D11Buffer *mVertexBuffer; - ID3D11SamplerState *mPointSampler; - ID3D11SamplerState *mLinearSampler; - ID3D11RasterizerState *mScissorEnabledRasterizerState; - ID3D11RasterizerState *mScissorDisabledRasterizerState; - ID3D11DepthStencilState *mDepthStencilState; + d3d11::Buffer mVertexBuffer; + d3d11::SamplerState mPointSampler; + d3d11::SamplerState mLinearSampler; + d3d11::RasterizerState mScissorEnabledRasterizerState; + d3d11::RasterizerState mScissorDisabledRasterizerState; + d3d11::DepthStencilState mDepthStencilState; d3d11::LazyInputLayout mQuad2DIL; d3d11::LazyShader mQuad2DVS; @@ -176,9 +314,19 @@ class Blit11 : angle::NonCopyable d3d11::LazyBlendState mAlphaMaskBlendState; - ID3D11Buffer *mSwizzleCB; + d3d11::Buffer mSwizzleCB; + + d3d11::LazyShader mResolveDepthStencilVS; + d3d11::LazyShader mResolveDepthPS; + d3d11::LazyShader mResolveDepthStencilPS; + d3d11::LazyShader mResolveStencilPS; + d3d11::ShaderResourceView mStencilSRV; + TextureHelper11 mResolvedDepthStencil; + d3d11::RenderTargetView mResolvedDepthStencilRTView; + TextureHelper11 mResolvedDepth; + d3d11::DepthStencilView mResolvedDepthDSView; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ +#endif // LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ 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 0d5dc08b03..2317c9abdb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -13,10 +13,14 @@ #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/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ namespace { @@ -27,41 +31,41 @@ 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 -} D3D11_MAP_FLAG; -#endif -namespace rx -{ -PackPixelsParams::PackPixelsParams() - : format(GL_NONE), type(GL_NONE), outputPitch(0), packBuffer(nullptr), offset(0) +enum class CopyResult { -} + RECREATED, + NOT_RECREATED, +}; -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) +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 } +} // anonymous namespace + namespace gl_d3d11 { -D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access) { bool readBit = ((access & GL_MAP_READ_BIT) != 0); bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); @@ -77,7 +81,8 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) } else if (writeBit && !readBit) { - return D3D11_MAP_WRITE; + // Special case for uniform storage - we only allow full buffer updates. + return usage == BUFFER_USAGE_UNIFORM ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE; } else if (writeBit && readBit) { @@ -89,7 +94,7 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) return D3D11_MAP_READ; } } -} +} // namespace gl_d3d11 // Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points // - vertex/transform feedback buffers @@ -106,16 +111,22 @@ class Buffer11::BufferStorage : angle::NonCopyable size_t getSize() const { return mBufferSize; } void setDataRevision(DataRevision rev) { mRevision = rev; } - virtual bool isMappable() const = 0; + virtual bool isCPUAccessible(GLbitfield access) const = 0; + + virtual bool isGPUAccessible() const = 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 gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) = 0; + virtual gl::Error resize(const gl::Context *context, size_t size, bool preserveData) = 0; - virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0; - virtual void unmap() = 0; + virtual gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) = 0; + virtual void unmap() = 0; gl::Error setData(const uint8_t *data, size_t offset, size_t size); @@ -133,28 +144,41 @@ class Buffer11::BufferStorage : angle::NonCopyable class Buffer11::NativeStorage : public Buffer11::BufferStorage { public: - NativeStorage(Renderer11 *renderer, BufferUsage usage); + NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged); ~NativeStorage() override; - bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } + bool isCPUAccessible(GLbitfield access) const override; + + bool isGPUAccessible() const override { return true; } - ID3D11Buffer *getNativeStorage() const { return mNativeStorage; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + const d3d11::Buffer &getBuffer() const { return mBuffer; } + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; + gl::ErrorOrResult getSRVForFormat(DXGI_FORMAT srvFormat); + private: - static void fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, + static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); + void clearSRVs(); - ID3D11Buffer *mNativeStorage; + d3d11::Buffer mBuffer; + const OnBufferDataDirtyChannel *mOnStorageChanged; + std::map mBufferResourceViews; }; // A emulated indexed buffer storage represents an underlying D3D11 buffer for data @@ -166,28 +190,32 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage EmulatedIndexedStorage(Renderer11 *renderer); ~EmulatedIndexedStorage() override; - bool isMappable() const override { return true; } + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - ID3D11Buffer *getNativeStorage(); + gl::ErrorOrResult getBuffer(SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex); - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) 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 + d3d11::Buffer mBuffer; // contains expanded data for use by D3D + angle::MemoryBuffer mMemoryBuffer; // original data (not expanded) + angle::MemoryBuffer mIndicesMemoryBuffer; // indices data }; // Pack storage represents internal storage for pack buffers. We implement pack buffers @@ -198,24 +226,32 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage explicit PackStorage(Renderer11 *renderer); ~PackStorage() override; - bool isMappable() const override { return true; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + bool isCPUAccessible(GLbitfield access) const override { return true; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + bool isGPUAccessible() const override { return false; } + + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + gl::Error packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms); private: gl::Error flushQueuedPackCommand(); TextureHelper11 mStagingTexture; - MemoryBuffer mMemoryBuffer; + angle::MemoryBuffer mMemoryBuffer; std::unique_ptr mQueuedPackCommand; PackPixelsParams mPackParams; bool mDataModified; @@ -230,37 +266,46 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage explicit SystemMemoryStorage(Renderer11 *renderer); ~SystemMemoryStorage() override {} - bool isMappable() const override { return true; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::ErrorOrResult copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - MemoryBuffer *getSystemCopy() { return &mSystemCopy; } + angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; } protected: - MemoryBuffer mSystemCopy; + angle::MemoryBuffer mSystemCopy; }; -Buffer11::Buffer11(Renderer11 *renderer) - : BufferD3D(renderer), +Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer) + : BufferD3D(state, renderer), mRenderer(renderer), mSize(0), mMappedStorage(nullptr), - mBufferStorages(BUFFER_USAGE_COUNT, nullptr), + mBufferStorages({}), + mLatestBufferStorage(nullptr), + mDeallocThresholds({}), + mIdleness({}), mConstantBufferStorageAdditionalSize(0), - mMaxConstantBufferLruCount(0), - mReadUsageCount(0) + mMaxConstantBufferLruCount(0) { } Buffer11::~Buffer11() { - for (auto &storage : mBufferStorages) + for (BufferStorage *&storage : mBufferStorages) { SafeDelete(storage); } @@ -273,79 +318,74 @@ Buffer11::~Buffer11() mRenderer->onBufferDelete(this); } -gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) +gl::Error Buffer11::setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) { - gl::Error error = setSubData(data, size, 0); - if (error.isError()) - { - return error; - } - - updateD3DBufferUsage(usage); - return error; + updateD3DBufferUsage(context, usage); + ANGLE_TRY(setSubData(context, target, data, size, 0)); + return gl::NoError(); } -gl::Error Buffer11::getData(const uint8_t **outData) +gl::Error Buffer11::getData(const gl::Context *context, const uint8_t **outData) { SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - - if (error.isError()) - { - *outData = nullptr; - return error; - } - - mReadUsageCount = 0; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), systemMemoryStorage); ASSERT(systemMemoryStorage->getSize() >= mSize); *outData = systemMemoryStorage->getSystemCopy()->data(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::getSystemMemoryStorage(SystemMemoryStorage **storageOut) +gl::ErrorOrResult Buffer11::getSystemMemoryStorage( + const gl::Context *context) { - BufferStorage *memStorageUntyped = getBufferStorage(BUFFER_USAGE_SYSTEM_MEMORY); - - if (memStorageUntyped == nullptr) - { - // TODO(jmadill): convert all to errors - return gl::Error(GL_OUT_OF_MEMORY); - } - - *storageOut = GetAs(memStorageUntyped); - return gl::Error(GL_NO_ERROR); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY), storage); + return GetAs(storage); } -gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) +gl::Error Buffer11::setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) { size_t requiredSize = size + offset; if (data && size > 0) { // Use system memory storage for dynamic buffers. - + // Try using a constant storage for constant buffers BufferStorage *writeBuffer = nullptr; - if (supportsDirectBinding()) + if (target == gl::BufferBinding::Uniform) { - writeBuffer = getStagingStorage(); - - if (!writeBuffer) + // If we are a very large uniform buffer, keep system memory storage around so that we + // aren't forced to read back from a constant buffer. We also check the workaround for + // Intel - this requires us to use system memory so we don't end up having to copy from + // a constant buffer to a staging buffer. + // TODO(jmadill): Use Context caps. + if (offset == 0 && size >= mSize && + size <= static_cast(mRenderer->getNativeCaps().maxUniformBlockSize) && + !mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) + { + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), writeBuffer); + } + else { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } } + else if (supportsDirectBinding()) + { + ANGLE_TRY_RESULT(getStagingStorage(context), writeBuffer); + } else { - SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - if (error.isError()) - { - return error; - } - - writeBuffer = systemMemoryStorage; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } ASSERT(writeBuffer); @@ -355,24 +395,25 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) if (writeBuffer->getSize() < requiredSize) { bool preserveData = (offset > 0); - gl::Error error = writeBuffer->resize(requiredSize, preserveData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData)); } - writeBuffer->setData(static_cast(data), offset, size); - writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); + ANGLE_TRY(writeBuffer->setData(static_cast(data), offset, size)); + onStorageUpdate(writeBuffer); + + // Notify any vertex arrays that we have dirty data. + // TODO(jmadill): Use a more fine grained notification for data updates. + mDirectBroadcastChannel.signal(context); } mSize = std::max(mSize, requiredSize); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::copySubData(BufferImpl *source, +gl::Error Buffer11::copySubData(const gl::Context *context, + BufferImpl *source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) @@ -380,28 +421,32 @@ gl::Error Buffer11::copySubData(BufferImpl *source, Buffer11 *sourceBuffer = GetAs(source); ASSERT(sourceBuffer != nullptr); - BufferStorage *copyDest = getLatestBufferStorage(); + BufferStorage *copyDest = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), copyDest); + if (!copyDest) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } - BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); + BufferStorage *copySource = nullptr; + ANGLE_TRY_RESULT(sourceBuffer->getLatestBufferStorage(context), copySource); - if (!copySource || !copyDest) + if (!copySource) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - // If copying to/from a pixel pack buffer, we must have a staging or - // pack buffer partner, because other native buffers can't be mapped - if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) + ASSERT(copySource && copyDest); + + // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable. + if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT)) { - copySource = sourceBuffer->getStagingStorage(); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) + else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT)) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } // D3D11 does not allow overlapped copies until 11.1, and only if the @@ -411,36 +456,48 @@ gl::Error Buffer11::copySubData(BufferImpl *source, { if (copySource->getUsage() == BUFFER_USAGE_STAGING) { - copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + copySource); } else { - copySource = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copySource); } } - copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); - copyDest->setDataRevision(copyDest->getDataRevision() + 1); + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset), + copyResult); + onStorageUpdate(copyDest); mSize = std::max(mSize, destOffset + size); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + + // Also notify that direct buffers are dirty. + mDirectBroadcastChannel.signal(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::map(GLenum access, GLvoid **mapPtr) +gl::Error Buffer11::map(const gl::Context *context, GLenum access, void **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); + return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr); } -gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +gl::Error Buffer11::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) { ASSERT(!mMappedStorage); - BufferStorage *latestStorage = getLatestBufferStorage(); + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || latestStorage->getUsage() == BUFFER_USAGE_STAGING)) { @@ -449,34 +506,32 @@ gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GL } else { - // Fall back to using the staging buffer if the latest storage does - // not exist or is not CPU-accessible. - mMappedStorage = getStagingStorage(); + // Fall back to using the staging buffer if the latest storage does not exist or is not + // CPU-accessible. + ANGLE_TRY_RESULT(getStagingStorage(context), mMappedStorage); } if (!mMappedStorage) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); + return gl::OutOfMemory() << "Failed to allocate mappable internal buffer."; } if ((access & GL_MAP_WRITE_BIT) > 0) { // 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); + onStorageUpdate(mMappedStorage); + invalidateStaticData(context); } - uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); - if (!mappedBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + uint8_t *mappedBuffer = nullptr; + ANGLE_TRY(mMappedStorage->map(offset, length, access, &mappedBuffer)); + ASSERT(mappedBuffer); - *mapPtr = static_cast(mappedBuffer); - return gl::Error(GL_NO_ERROR); + *mapPtr = static_cast(mappedBuffer); + return gl::NoError(); } -gl::Error Buffer11::unmap(GLboolean *result) +gl::Error Buffer11::unmap(const gl::Context *context, GLboolean *result) { ASSERT(mMappedStorage); mMappedStorage->unmap(); @@ -485,168 +540,171 @@ gl::Error Buffer11::unmap(GLboolean *result) // TODO: detect if we had corruption. if so, return false. *result = GL_TRUE; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Buffer11::markTransformFeedbackUsage() +gl::Error Buffer11::markTransformFeedbackUsage(const gl::Context *context) { - BufferStorage *transformFeedbackStorage = - getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + BufferStorage *transformFeedbackStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + transformFeedbackStorage); if (transformFeedbackStorage) { - transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + onStorageUpdate(transformFeedbackStorage); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + return gl::NoError(); } -void Buffer11::markBufferUsage() +void Buffer11::updateDeallocThreshold(BufferUsage usage) { - mReadUsageCount++; + // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/) + // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11) + + // First readback: 8 unmodified uses before we free buffer memory. + // After that, double the threshold each time until we reach the max. + if (mDeallocThresholds[usage] == 0) + { + mDeallocThresholds[usage] = 8; + } + else if (mDeallocThresholds[usage] < std::numeric_limits::max() / 2u) + { + mDeallocThresholds[usage] *= 2u; + } + else + { + mDeallocThresholds[usage] = std::numeric_limits::max(); + } +} - // Free the system memory storage if we decide it isn't being used very often. - const unsigned int usageLimit = 5; +// Free the storage if we decide it isn't being used very often. +gl::Error Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage) +{ + mIdleness[usage]++; - BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY]; - if (mReadUsageCount > usageLimit && sysMemUsage != nullptr) + BufferStorage *&storage = mBufferStorages[usage]; + if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage]) { - if (getLatestBufferStorage() != sysMemUsage) + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage != storage) { - SafeDelete(sysMemUsage); + SafeDelete(storage); } } + + return gl::NoError(); } -ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +// Keep system memory when we are using it for the canonical version of data. +bool Buffer11::canDeallocateSystemMemory() const { - markBufferUsage(); - - BufferStorage *bufferStorage = getBufferStorage(usage); - - if (!bufferStorage) + // Must keep system memory on Intel. + if (mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) { - // Storage out-of-memory - return nullptr; + return false; } - return GetAs(bufferStorage)->getNativeStorage(); + return (!mBufferStorages[BUFFER_USAGE_UNIFORM] || + mSize <= mRenderer->getNativeCaps().maxUniformBlockSize); } -ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo, - const TranslatedAttribute *attribute) +void Buffer11::markBufferUsage(BufferUsage usage) { - markBufferUsage(); - - assert(indexInfo != nullptr); - assert(attribute != nullptr); + mIdleness[usage] = 0; +} - BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX); - if (!bufferStorage) +gl::Error Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage) +{ + if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory()) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY)); } - EmulatedIndexedStorage *emulatedStorage = GetAs(bufferStorage); - if (!emulatedStorage->update(indexInfo, attribute)) + if (currentUsage != BUFFER_USAGE_STAGING) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING)); } - return emulatedStorage->getNativeStorage(); + return gl::NoError(); } -ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size) +gl::ErrorOrResult Buffer11::getBuffer(const gl::Context *context, BufferUsage usage) { - markBufferUsage(); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, usage), storage); + return GetAs(storage)->getBuffer().get(); +} - BufferStorage *bufferStorage; +gl::ErrorOrResult Buffer11::getEmulatedIndexedBuffer( + const gl::Context *context, + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) +{ + ASSERT(indexInfo); - if (offset == 0) - { - bufferStorage = getBufferStorage(BUFFER_USAGE_UNIFORM); - } - else - { - bufferStorage = getConstantBufferRangeStorage(offset, size); - } + BufferStorage *untypedStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), + untypedStorage); - if (!bufferStorage) - { - // Storage out-of-memory - return nullptr; - } + EmulatedIndexedStorage *emulatedStorage = GetAs(untypedStorage); + + const d3d11::Buffer *nativeStorage = nullptr; + ANGLE_TRY_RESULT(emulatedStorage->getBuffer(indexInfo, attribute, startVertex), nativeStorage); - return GetAs(bufferStorage)->getNativeStorage(); + return nativeStorage->get(); } -ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +gl::Error Buffer11::getConstantBufferRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + const d3d11::Buffer **bufferOut, + UINT *firstConstantOut, + UINT *numConstantsOut) { - BufferStorage *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + BufferStorage *bufferStorage = nullptr; - if (!storage) + if (offset == 0 || mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), bufferStorage); + CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut); } - - ID3D11Buffer *buffer = GetAs(storage)->getNativeStorage(); - - auto bufferSRVIt = mBufferResourceViews.find(srvFormat); - - if (bufferSRVIt != mBufferResourceViews.end()) + else { - if (bufferSRVIt->second.first == buffer) - { - return bufferSRVIt->second.second; - } - else - { - // The underlying buffer has changed since the SRV was created: recreate the SRV. - SafeRelease(bufferSRVIt->second.second); - } + ANGLE_TRY_RESULT(getConstantBufferRangeStorage(context, offset, size), bufferStorage); + *firstConstantOut = 0; + *numConstantsOut = 0; } - ID3D11Device *device = mRenderer->getDevice(); - ID3D11ShaderResourceView *bufferSRV = nullptr; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); + *bufferOut = &GetAs(bufferStorage)->getBuffer(); - D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; - bufferSRVDesc.Buffer.ElementOffset = 0; - 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); - ASSERT(SUCCEEDED(result)); - - mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + return gl::NoError(); +} - return bufferSRV; +gl::ErrorOrResult Buffer11::getSRV(const gl::Context *context, + DXGI_FORMAT srvFormat) +{ + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK), storage); + NativeStorage *nativeStorage = GetAs(storage); + return nativeStorage->getSRVForFormat(srvFormat); } -gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - PackStorage *packStorage = getPackStorage(); - BufferStorage *latestStorage = getLatestBufferStorage(); + PackStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getPackStorage(context), packStorage); - if (packStorage) - { - gl::Error error = packStorage->packPixels(readAttachment, params); - if (error.isError()) - { - return error; - } - packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); - } + ASSERT(packStorage); + ANGLE_TRY(packStorage->packPixels(context, readAttachment, params)); + onStorageUpdate(packStorage); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } size_t Buffer11::getTotalCPUBufferMemoryBytes() const @@ -662,48 +720,56 @@ size_t Buffer11::getTotalCPUBufferMemoryBytes() const return allocationSize; } -Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) +gl::ErrorOrResult Buffer11::getBufferStorage(const gl::Context *context, + BufferUsage usage) { ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT); BufferStorage *&newStorage = mBufferStorages[usage]; if (!newStorage) { - if (usage == BUFFER_USAGE_PIXEL_PACK) - { - newStorage = new PackStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) - { - newStorage = new SystemMemoryStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX) - { - newStorage = new EmulatedIndexedStorage(mRenderer); - } - else - { - // buffer is not allocated, create it - newStorage = new NativeStorage(mRenderer, usage); - } + newStorage = allocateStorage(usage); } + markBufferUsage(usage); + // resize buffer if (newStorage->getSize() < mSize) { - if (newStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + ANGLE_TRY(newStorage->resize(context, mSize, true)); } - updateBufferStorage(newStorage, 0, mSize); + ASSERT(newStorage); + + ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize)); + ANGLE_TRY(garbageCollection(context, usage)); return newStorage; } -Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size) +Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) +{ + updateDeallocThreshold(usage); + switch (usage) + { + case BUFFER_USAGE_PIXEL_PACK: + return new PackStorage(mRenderer); + case BUFFER_USAGE_SYSTEM_MEMORY: + return new SystemMemoryStorage(mRenderer); + case BUFFER_USAGE_EMULATED_INDEXED_VERTEX: + return new EmulatedIndexedStorage(mRenderer); + case BUFFER_USAGE_INDEX: + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel); + default: + return new NativeStorage(mRenderer, usage, nullptr); + } +} + +gl::ErrorOrResult Buffer11::getConstantBufferRangeStorage( + const gl::Context *context, + GLintptr offset, + GLsizeiptr size) { BufferStorage *newStorage; @@ -714,7 +780,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset if (!cacheEntry->storage) { - cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM); + cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM); cacheEntry->lruCount = ++mMaxConstantBufferLruCount; } @@ -722,6 +788,8 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage = cacheEntry->storage; } + markBufferUsage(BUFFER_USAGE_UNIFORM); + if (newStorage->getSize() < static_cast(size)) { size_t maximumAllowedAdditionalSize = 2 * getSize(); @@ -733,8 +801,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache), std::end(mConstantBufferRangeStoragesCache), [](const ConstantBufferCache::value_type &a, - const ConstantBufferCache::value_type &b) - { + const ConstantBufferCache::value_type &b) { return a.second.lruCount < b.second.lruCount; }); @@ -746,12 +813,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset mConstantBufferRangeStoragesCache.erase(iter); } - if (newStorage->resize(size, false).isError()) - { - // Out of memory error - return nullptr; - } - + ANGLE_TRY(newStorage->resize(context, size, false)); mConstantBufferStorageAdditionalSize += sizeDelta; // We don't copy the old data when resizing the constant buffer because the data may be @@ -760,103 +822,148 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage->setDataRevision(0); } - updateBufferStorage(newStorage, offset, size); - + ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size)); + ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM)); return newStorage; } -void Buffer11::updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize) +gl::Error Buffer11::updateBufferStorage(const gl::Context *context, + BufferStorage *storage, + size_t sourceOffset, + size_t storageSize) { - BufferStorage *latestBuffer = getLatestBufferStorage(); - 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 && - storage->getUsage() != BUFFER_USAGE_STAGING && - (!latestBuffer->isMappable() || !storage->isMappable())) - { - NativeStorage *stagingBuffer = getStagingStorage(); + BufferStorage *latestBuffer = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestBuffer); - stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); - stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); - - latestBuffer = stagingBuffer; - } + ASSERT(storage); - // if copyFromStorage returns true, the D3D buffer has been recreated - // and we should update our serial - if (storage->copyFromStorage(latestBuffer, sourceOffset, storageSize, 0)) - { - updateSerial(); - } - storage->setDataRevision(latestBuffer->getDataRevision()); + if (!latestBuffer) + { + onStorageUpdate(storage); + return gl::NoError(); } -} -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 = nullptr; - DataRevision latestRevision = 0; - for (auto &storage : mBufferStorages) + if (latestBuffer->getDataRevision() <= storage->getDataRevision()) { - if (storage && (!latestStorage || storage->getDataRevision() > latestRevision)) - { - latestStorage = storage; - latestRevision = storage->getDataRevision(); - } + return gl::NoError(); } - // resize buffer - if (latestStorage && latestStorage->getSize() < mSize) + // 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 && + storage->getUsage() != BUFFER_USAGE_STAGING && + (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) || + !storage->isCPUAccessible(GL_MAP_WRITE_BIT))) { - if (latestStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + NativeStorage *stagingBuffer = nullptr; + ANGLE_TRY_RESULT(getStagingStorage(context), stagingBuffer); + + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT( + stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(), 0), + copyResult); + onCopyStorage(stagingBuffer, latestBuffer); + + latestBuffer = stagingBuffer; } - return latestStorage; + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0), + copyResult); + // If the D3D buffer has been recreated, we should update our serial. + if (copyResult == CopyResult::RECREATED) + { + updateSerial(); + } + onCopyStorage(storage, latestBuffer); + return gl::NoError(); } -Buffer11::NativeStorage *Buffer11::getStagingStorage() +gl::ErrorOrResult Buffer11::getLatestBufferStorage( + const gl::Context *context) const { - BufferStorage *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); - - if (!stagingStorage) + // resize buffer + if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize) { - // Out-of-memory - return nullptr; + ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true)); } - return GetAs(stagingStorage); + return mLatestBufferStorage; } -Buffer11::PackStorage *Buffer11::getPackStorage() +gl::ErrorOrResult Buffer11::getStagingStorage(const gl::Context *context) { - BufferStorage *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); - - if (!packStorage) - { - // Out-of-memory - return nullptr; - } + BufferStorage *stagingStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_STAGING), stagingStorage); + return GetAs(stagingStorage); +} +gl::ErrorOrResult Buffer11::getPackStorage(const gl::Context *context) +{ + BufferStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK), packStorage); return GetAs(packStorage); } +size_t Buffer11::getSize() const +{ + return mSize; +} + bool Buffer11::supportsDirectBinding() const { // Do not support direct buffers for dynamic data. The streaming buffer // offers better performance for data which changes every frame. - // Check for absence of static buffer interfaces to detect dynamic data. - return (mStaticVertexBuffer && mStaticIndexBuffer); + return (mUsage == D3DBufferUsage::STATIC); +} + +void Buffer11::initializeStaticData(const gl::Context *context) +{ + BufferD3D::initializeStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); } +void Buffer11::invalidateStaticData(const gl::Context *context) +{ + BufferD3D::invalidateStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); +} + +OnBufferDataDirtyChannel *Buffer11::getStaticBroadcastChannel() +{ + return &mStaticBroadcastChannel; +} + +OnBufferDataDirtyChannel *Buffer11::getDirectBroadcastChannel() +{ + return &mDirectBroadcastChannel; +} + +void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source) +{ + ASSERT(source && mLatestBufferStorage); + dest->setDataRevision(source->getDataRevision()); + + // Only update the latest buffer storage if our usage index is lower. See comment in header. + if (dest->getUsage() < mLatestBufferStorage->getUsage()) + { + mLatestBufferStorage = dest; + } +} + +void Buffer11::onStorageUpdate(BufferStorage *updatedStorage) +{ + updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1); + mLatestBufferStorage = updatedStorage; +} + +// Buffer11::BufferStorage implementation + Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0) { @@ -864,113 +971,118 @@ Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) { - ASSERT(isMappable()); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *writePointer = map(offset, size, GL_MAP_WRITE_BIT); - if (!writePointer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + // Uniform storage can have a different internal size than the buffer size. Ensure we don't + // overflow. + size_t mapSize = std::min(size, mBufferSize - offset); + + uint8_t *writePointer = nullptr; + ANGLE_TRY(map(offset, mapSize, GL_MAP_WRITE_BIT, &writePointer)); - memcpy(writePointer, data, size); + memcpy(writePointer, data, mapSize); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) - : BufferStorage(renderer, usage), mNativeStorage(nullptr) +// Buffer11::NativeStorage implementation + +Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged) + : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged) { } Buffer11::NativeStorage::~NativeStorage() { - SafeRelease(mNativeStorage); + clearSRVs(); } -// 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::isCPUAccessible(GLbitfield access) const { - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + if ((access & GL_MAP_READ_BIT) != 0) + { + // Read is more exclusive than write mappability. + return (mUsage == BUFFER_USAGE_STAGING); + } + ASSERT((access & GL_MAP_WRITE_BIT) != 0); + return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM); +} +// Returns true if it recreates the direct buffer +gl::ErrorOrResult Buffer11::NativeStorage::copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) +{ size_t requiredSize = destOffset + size; - bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; + bool createBuffer = !mBuffer.valid() || mBufferSize < requiredSize; // (Re)initialize D3D buffer if needed + bool preserveData = (destOffset > 0); if (createBuffer) { - bool preserveData = (destOffset > 0); - resize(requiredSize, preserveData); + ANGLE_TRY(resize(context, requiredSize, preserveData)); + } + + size_t clampedSize = size; + if (mUsage == BUFFER_USAGE_UNIFORM) + { + clampedSize = std::min(clampedSize, mBufferSize - destOffset); } if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) { - ASSERT(source->isMappable()); - - uint8_t *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource); - ASSERT(SUCCEEDED(hr)); - if (FAILED(hr)) - { - source->unmap(); - return false; - } + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *destPointer = static_cast(mappedResource.pData) + destOffset; + // Uniform buffers must be mapped with write/discard. + ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM)); - // Offset bounds are validated at the API layer - ASSERT(sourceOffset + size <= destOffset + mBufferSize); - memcpy(destPointer, sourcePointer, size); + uint8_t *sourcePointer = nullptr; + ANGLE_TRY(source->map(sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer)); - context->Unmap(mNativeStorage, 0); + auto err = setData(sourcePointer, destOffset, clampedSize); source->unmap(); + ANGLE_TRY(err); } else { D3D11_BOX srcBox; srcBox.left = static_cast(sourceOffset); - srcBox.right = static_cast(sourceOffset + size); + srcBox.right = static_cast(sourceOffset + clampedSize); srcBox.top = 0; srcBox.bottom = 1; srcBox.front = 0; srcBox.back = 1; - ID3D11Buffer *sourceBuffer = GetAs(source)->getNativeStorage(); + const d3d11::Buffer *sourceBuffer = &GetAs(source)->getBuffer(); - context->CopySubresourceRegion(mNativeStorage, 0, static_cast(destOffset), 0, - 0, sourceBuffer, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mBuffer.get(), 0, + static_cast(destOffset), 0, 0, + sourceBuffer->get(), 0, &srcBox); } - return createBuffer; + return createBuffer ? CopyResult::RECREATED : CopyResult::NOT_RECREATED; } -gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::NativeStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - D3D11_BUFFER_DESC bufferDesc; - fillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast(size)); - - ID3D11Buffer *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); - } + FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast(size)); - d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage"); + d3d11::Buffer newBuffer; + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &newBuffer)); + newBuffer.setDebugName("Buffer11::NativeStorage"); - if (mNativeStorage && preserveData) + if (mBuffer.valid() && preserveData) { // We don't call resize if the buffer is big enough already. ASSERT(mBufferSize <= size); @@ -983,19 +1095,30 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) srcBox.front = 0; srcBox.back = 1; - context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0, + &srcBox); } // No longer need the old buffer - SafeRelease(mNativeStorage); - mNativeStorage = newBuffer; + mBuffer = std::move(newBuffer); mBufferSize = bufferDesc.ByteWidth; - return gl::Error(GL_NO_ERROR); + // Free the SRVs. + clearSRVs(); + + // Notify that the storage has changed. + if (mOnStorageChanged) + { + mOnStorageChanged->signal(context); + } + + return gl::NoError(); } -void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, +// static +void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize) @@ -1030,6 +1153,13 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, bufferDesc->CPUAccessFlags = 0; break; + case BUFFER_USAGE_INDIRECT: + bufferDesc->MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = 0; + break; + case BUFFER_USAGE_PIXEL_UNPACK: bufferDesc->Usage = D3D11_USAGE_DEFAULT; bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; @@ -1044,9 +1174,12 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, // 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); + + // Note: it seems that D3D11 allows larger buffers on some platforms, but not all. + // (Windows 10 seems to allow larger constant buffers, but not Windows 7) bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, - static_cast(renderer->getRendererCaps().maxUniformBlockSize)); + static_cast(renderer->getNativeCaps().maxUniformBlockSize)); break; default: @@ -1054,67 +1187,146 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, } } -uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::NativeStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(access)); 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(mUsage, 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); + HRESULT result = context->Map(mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return nullptr; + return gl::OutOfMemory() << "Failed to map native storage in Buffer11::NativeStorage::map"; } - return static_cast(mappedResource.pData) + offset; + ASSERT(mappedResource.pData); + *mapPointerOut = static_cast(mappedResource.pData) + offset; + return gl::NoError(); } void Buffer11::NativeStorage::unmap() { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT)); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->Unmap(mNativeStorage, 0); + context->Unmap(mBuffer.get(), 0); +} + +gl::ErrorOrResult Buffer11::NativeStorage::getSRVForFormat( + DXGI_FORMAT srvFormat) +{ + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + return &bufferSRVIt->second; + } + + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat); + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = static_cast(mBufferSize) / dxgiFormatInfo.pixelBytes; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + ANGLE_TRY(mRenderer->allocateResource(bufferSRVDesc, mBuffer.get(), + &mBufferResourceViews[srvFormat])); + + return &mBufferResourceViews[srvFormat]; +} + +void Buffer11::NativeStorage::clearSRVs() +{ + mBufferResourceViews.clear(); } +// Buffer11::EmulatedIndexStorage implementation + Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer) - : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mNativeStorage(nullptr) + : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer() { } Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() { - SafeRelease(mNativeStorage); } -ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() +gl::ErrorOrResult Buffer11::EmulatedIndexedStorage::getBuffer( + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) { - if (!mNativeStorage) + // 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 (!mBuffer.valid() || indexInfo->srcIndicesChanged) + { + mBuffer.reset(); + + // 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 gl::OutOfMemory() << "Error resizing index memory buffer in " + "Buffer11::EmulatedIndexedStorage::getBuffer"; + } + + memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); + + indexInfo->srcIndicesChanged = false; + } + + if (!mBuffer.valid()) { + unsigned int offset = 0; + ANGLE_TRY_RESULT(attribute.computeOffset(startVertex), offset); + // Expand the memory storage upon request and cache the results. unsigned int expandedDataSize = - static_cast((mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset); - MemoryBuffer expandedData; + static_cast((indexInfo->srcCount * attribute.stride) + offset); + angle::MemoryBuffer expandedData; if (!expandedData.resize(expandedDataSize)) { - return nullptr; + return gl::OutOfMemory() + << "Error resizing buffer in Buffer11::EmulatedIndexedStorage::getBuffer"; } // Clear the contents of the allocated buffer ZeroMemory(expandedData.data(), expandedDataSize); uint8_t *curr = expandedData.data(); - const uint8_t *ptr = static_cast(mIndexInfo.srcIndices); + const uint8_t *ptr = static_cast(indexInfo->srcIndices); // Ensure that we start in the correct place for the emulated data copy operation to // maintain offset behaviors. - curr += mAttributeOffset; + curr += offset; ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices; - switch (mIndexInfo.srcIndexType) + switch (indexInfo->srcIndexType) { case GL_UNSIGNED_INT: readIndexValue = ReadIndexValueFromIndices; @@ -1128,17 +1340,15 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() } // Iterate over the cached index data and copy entries indicated into the emulated buffer. - for (GLuint i = 0; i < mIndexInfo.srcCount; i++) + for (GLuint i = 0; i < indexInfo->srcCount; i++) { GLuint idx = readIndexValue(ptr, i); - memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride); - curr += mAttributeStride; + memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride); + curr += attribute.stride; } // 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; @@ -1149,99 +1359,53 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() 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"); + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &subResourceData, &mBuffer)); + mBuffer.setDebugName("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; + return &mBuffer; } -bool Buffer11::EmulatedIndexedStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult Buffer11::EmulatedIndexedStorage::copyFromStorage( + const gl::Context *context, + 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(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mMemoryBuffer.size()); memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mMemoryBuffer.size() < size) { if (!mMemoryBuffer.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage"); + return gl::OutOfMemory() << "Failed to resize EmulatedIndexedStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::EmulatedIndexedStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size()); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::EmulatedIndexedStorage::unmap() @@ -1249,6 +1413,8 @@ void Buffer11::EmulatedIndexedStorage::unmap() // No-op } +// Buffer11::PackStorage implementation + Buffer11::PackStorage::PackStorage(Renderer11 *renderer) : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false) { @@ -1258,32 +1424,42 @@ Buffer11::PackStorage::~PackStorage() { } -bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult Buffer11::PackStorage::copyFromStorage(const gl::Context *context, + 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 - UNREACHABLE(); - return false; + ANGLE_TRY(flushQueuedPackCommand()); + + // For all use cases of pack buffers, we must copy through a readable buffer. + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); + ASSERT(destOffset + size <= mMemoryBuffer.size()); + memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); + source->unmap(); + return CopyResult::NOT_RECREATED; } -gl::Error Buffer11::PackStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::PackStorage::resize(const gl::Context *context, size_t size, bool preserveData) { if (size != mBufferSize) { if (!mMemoryBuffer.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); + return gl::OutOfMemory() << "Failed to resize internal buffer storage."; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::PackStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(offset + length <= getSize()); // TODO: fast path @@ -1291,15 +1467,12 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc // and if D3D packs the staging texture memory identically to how we would fill // the pack buffer according to the current pack state. - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return nullptr; - } + ANGLE_TRY(flushQueuedPackCommand()); mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::PackStorage::unmap() @@ -1307,42 +1480,29 @@ void Buffer11::PackStorage::unmap() // No-op } -gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::PackStorage::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(flushQueuedPackCommand()); RenderTarget11 *renderTarget = nullptr; - error = readAttachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - ID3D11Resource *renderTargetResource = renderTarget->getTexture(); - ASSERT(renderTargetResource); + ANGLE_TRY(readAttachment.getRenderTarget(context, &renderTarget)); + const TextureHelper11 &srcTexture = renderTarget->getTexture(); + ASSERT(srcTexture.valid()); 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() || + if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() || mStagingTexture.getExtents() != srcTextureSize) { - auto textureOrError = - CreateStagingTexture(srcTexture.getTextureType(), srcTexture.getFormat(), - srcTextureSize, mRenderer->getDevice()); - if (textureOrError.isError()) - { - return textureOrError.getError(); - } - mStagingTexture = std::move(textureOrError.getResult()); + ANGLE_TRY_RESULT( + mRenderer->createStagingTexture(srcTexture.getTextureType(), srcTexture.getFormatSet(), + srcTextureSize, StagingAccess::READ), + mStagingTexture); } // ReadPixels from multisampled FBOs isn't supported in current GL @@ -1357,17 +1517,17 @@ gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &rea // Select the correct layer from a 3D attachment srcBox.front = 0; - if (mStagingTexture.getTextureType() == GL_TEXTURE_3D) + if (mStagingTexture.is3D()) { srcBox.front = static_cast(readAttachment.layer()); } srcBox.back = srcBox.front + 1; // Asynchronous copy - immediateContext->CopySubresourceRegion(mStagingTexture.getResource(), 0, 0, 0, 0, - srcTexture.getResource(), srcSubresource, &srcBox); + immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(), + srcSubresource, &srcBox); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Buffer11::PackStorage::flushQueuedPackCommand() @@ -1376,58 +1536,65 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand() if (mQueuedPackCommand) { - gl::Error error = - mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + ANGLE_TRY( + mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data())); mQueuedPackCommand.reset(nullptr); - if (error.isError()) - { - return error; - } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } +// Buffer11::SystemMemoryStorage implementation + 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) +gl::ErrorOrResult Buffer11::SystemMemoryStorage::copyFromStorage( + const gl::Context *context, + 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(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mSystemCopy.size()); memcpy(mSystemCopy.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::SystemMemoryStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::SystemMemoryStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mSystemCopy.size() < size) { if (!mSystemCopy.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize SystemMemoryStorage"); + return gl::OutOfMemory() << "Failed to resize SystemMemoryStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::SystemMemoryStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::SystemMemoryStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); - return mSystemCopy.data() + offset; + *mapPointerOut = mSystemCopy.data() + offset; + return gl::NoError(); } void Buffer11::SystemMemoryStorage::unmap() { // No-op } -} +} // namespace rx 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 a748db57ae..ddbeeb90d2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h @@ -9,10 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#include #include #include "libANGLE/angletypes.h" #include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -21,69 +23,92 @@ class FramebufferAttachment; namespace rx { +struct PackPixelsParams; class Renderer11; struct SourceIndexData; struct TranslatedAttribute; +// The order of this enum governs priority of 'getLatestBufferStorage'. enum BufferUsage { + BUFFER_USAGE_SYSTEM_MEMORY, BUFFER_USAGE_STAGING, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, BUFFER_USAGE_INDEX, + // TODO: possibly share this buffer type with shader storage buffers. + BUFFER_USAGE_INDIRECT, BUFFER_USAGE_PIXEL_UNPACK, BUFFER_USAGE_PIXEL_PACK, BUFFER_USAGE_UNIFORM, - BUFFER_USAGE_SYSTEM_MEMORY, BUFFER_USAGE_EMULATED_INDEXED_VERTEX, BUFFER_USAGE_COUNT, }; -struct PackPixelsParams -{ - PackPixelsParams(); - PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, - const gl::PixelPackState &pack, ptrdiff_t offset); - - gl::Rectangle area; - GLenum format; - GLenum type; - GLuint outputPitch; - gl::Buffer *packBuffer; - gl::PixelPackState pack; - ptrdiff_t offset; -}; - typedef size_t DataRevision; class Buffer11 : public BufferD3D { public: - Buffer11(Renderer11 *renderer); - virtual ~Buffer11(); - - 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(const gl::FramebufferAttachment &readAttachment, + Buffer11(const gl::BufferState &state, Renderer11 *renderer); + ~Buffer11() override; + + gl::ErrorOrResult getBuffer(const gl::Context *context, BufferUsage usage); + gl::ErrorOrResult getEmulatedIndexedBuffer(const gl::Context *context, + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex); + gl::Error getConstantBufferRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + const d3d11::Buffer **bufferOut, + UINT *firstConstantOut, + UINT *numConstantsOut); + gl::ErrorOrResult getSRV(const gl::Context *context, + DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != nullptr; } + gl::Error packPixels(const gl::Context *context, + 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; + size_t getSize() const override; + bool supportsDirectBinding() const override; + gl::Error getData(const gl::Context *context, const uint8_t **outData) override; + void initializeStaticData(const gl::Context *context) override; + void invalidateStaticData(const gl::Context *context) override; // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - 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(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(); + gl::Error setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) override; + gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) override; + gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) override; + gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) override; + gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) override; + gl::Error unmap(const gl::Context *context, GLboolean *result) override; + gl::Error markTransformFeedbackUsage(const gl::Context *context) override; + + // We use two set of dirty events. Static buffers are marked dirty whenever + // data changes, because they must be re-translated. Direct buffers only need to be + // updated when the underlying ID3D11Buffer pointer changes - hopefully far less often. + OnBufferDataDirtyChannel *getStaticBroadcastChannel(); + OnBufferDataDirtyChannel *getDirectBroadcastChannel(); private: class BufferStorage; @@ -92,21 +117,61 @@ class Buffer11 : public BufferD3D class PackStorage; class SystemMemoryStorage; - Renderer11 *mRenderer; - size_t mSize; - - BufferStorage *mMappedStorage; - - std::vector mBufferStorages; - struct ConstantBufferCacheEntry { - ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) { } + ConstantBufferCacheEntry() : storage(nullptr), lruCount(0) {} BufferStorage *storage; unsigned int lruCount; }; + void markBufferUsage(BufferUsage usage); + gl::Error garbageCollection(const gl::Context *context, BufferUsage currentUsage); + gl::ErrorOrResult getStagingStorage(const gl::Context *context); + gl::ErrorOrResult getPackStorage(const gl::Context *context); + gl::ErrorOrResult getSystemMemoryStorage(const gl::Context *context); + + gl::Error updateBufferStorage(const gl::Context *context, + BufferStorage *storage, + size_t sourceOffset, + size_t storageSize); + gl::ErrorOrResult getBufferStorage(const gl::Context *context, + BufferUsage usage); + gl::ErrorOrResult getLatestBufferStorage(const gl::Context *context) const; + + gl::ErrorOrResult getConstantBufferRangeStorage(const gl::Context *context, + GLintptr offset, + GLsizeiptr size); + + BufferStorage *allocateStorage(BufferUsage usage); + void updateDeallocThreshold(BufferUsage usage); + + // Free the storage if we decide it isn't being used very often. + gl::Error checkForDeallocation(const gl::Context *context, BufferUsage usage); + + // For some cases of uniform buffer storage, we can't deallocate system memory storage. + bool canDeallocateSystemMemory() const; + + // Updates data revisions and latest storage. + void onCopyStorage(BufferStorage *dest, BufferStorage *source); + void onStorageUpdate(BufferStorage *updatedStorage); + + Renderer11 *mRenderer; + size_t mSize; + + BufferStorage *mMappedStorage; + + // Buffer storages are sorted by usage. It's important that the latest buffer storage picks + // the lowest usage in the case where two storages are tied on data revision - this ensures + // we never do anything dangerous like map a uniform buffer over a staging or system memory + // copy. + std::array mBufferStorages; + BufferStorage *mLatestBufferStorage; + + // These two arrays are used to track when to free unused storage. + std::array mDeallocThresholds; + std::array mIdleness; + // 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. @@ -115,25 +180,10 @@ class Buffer11 : public BufferD3D size_t mConstantBufferStorageAdditionalSize; unsigned int mMaxConstantBufferLruCount; - typedef std::pair BufferSRVPair; - std::map mBufferResourceViews; - - unsigned int mReadUsageCount; - - 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(); + OnBufferDataDirtyChannel mStaticBroadcastChannel; + OnBufferDataDirtyChannel mDirectBroadcastChannel; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ 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 cd95c65d1c..f9dda0aeb4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp @@ -1,4 +1,4 @@ -// + // 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. @@ -20,624 +20,814 @@ #include "third_party/trace_event/trace_event.h" // Precompiled shaders -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11_fl9vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewgs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11multiviewvs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clear11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/cleardepth11ps.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h" - -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11vs.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h" - -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11vs.h" -#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps8.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps8.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps1.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps2.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps3.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps4.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps5.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps6.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps7.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps8.h" namespace rx { +namespace +{ +constexpr uint32_t g_ConstantBufferSize = sizeof(RtvDsvClearInfo); +constexpr uint32_t g_VertexSize = sizeof(d3d11::PositionVertex); + +// Updates color, depth and alpha components of cached CB if necessary. +// Returns true if any constants are updated, false otherwise. template -static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color &color, float depth, void *buffer) +bool UpdateDataCache(RtvDsvClearInfo *dataCache, + const gl::Color &color, + const float *zValue, + const uint32_t numRtvs, + const uint8_t writeMask) { - d3d11::PositionDepthColorVertex *vertices = reinterpret_cast*>(buffer); + bool cacheDirty = false; + + if (numRtvs > 0) + { + const bool writeRGB = (writeMask & ~D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0; + if (writeRGB && memcmp(&dataCache->r, &color.red, sizeof(T) * 3) != 0) + { + dataCache->r = color.red; + dataCache->g = color.green; + dataCache->b = color.blue; + cacheDirty = true; + } - float depthClear = gl::clamp01(depth); - float left = -1.0f; - float right = 1.0f; - float top = -1.0f; - float bottom = 1.0f; + const bool writeAlpha = (writeMask & D3D11_COLOR_WRITE_ENABLE_ALPHA) != 0; + if (writeAlpha && (dataCache->a != color.alpha)) + { + dataCache->a = color.alpha; + cacheDirty = true; + } + } - // Clip the quad coordinates to the scissor if needed - if (scissor != nullptr) + if (zValue) { - 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); - top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); - bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); + const float clampedZValue = gl::clamp01(*zValue); + + if (clampedZValue != dataCache->z) + { + dataCache->z = clampedZValue; + cacheDirty = true; + } } - d3d11::SetPositionDepthColorVertex(vertices + 0, left, bottom, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 1, left, top, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 2, right, bottom, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 3, right, top, depthClear, color); + return cacheDirty; } -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) +bool AllOffsetsAreNonNegative(const std::vector &viewportOffsets) { - D3D11_INPUT_ELEMENT_DESC quadLayout[] = + for (size_t i = 0u; i < viewportOffsets.size(); ++i) { - { "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 }, - }; - - inputLayout = new d3d11::LazyInputLayout(quadLayout, 2, vsByteCode, vsSize, inputLayoutName); + const auto &offset = viewportOffsets[i]; + if (offset.x < 0 || offset.y < 0) + { + return false; + } + } + return true; } - -Clear11::ClearShader::~ClearShader() +} // anonymous namespace + +#define CLEARPS(Index) \ + d3d11::LazyShader(g_PS_Clear##Index, ArraySize(g_PS_Clear##Index), \ + "Clear11 PS " ANGLE_STRINGIFY(Index)) + +Clear11::ShaderManager::ShaderManager() + : mIl9(), + mVs9(g_VS_Clear_FL9, ArraySize(g_VS_Clear_FL9), "Clear11 VS FL9"), + mPsFloat9(g_PS_ClearFloat_FL9, ArraySize(g_PS_ClearFloat_FL9), "Clear11 PS FloatFL9"), + mVs(g_VS_Clear, ArraySize(g_VS_Clear), "Clear11 VS"), + mVsMultiview(g_VS_Multiview_Clear, ArraySize(g_VS_Multiview_Clear), "Clear11 VS Multiview"), + mGsMultiview(g_GS_Multiview_Clear, ArraySize(g_GS_Multiview_Clear), "Clear11 GS Multiview"), + mPsDepth(g_PS_ClearDepth, ArraySize(g_PS_ClearDepth), "Clear11 PS Depth"), + mPsFloat{{CLEARPS(Float1), CLEARPS(Float2), CLEARPS(Float3), CLEARPS(Float4), CLEARPS(Float5), + CLEARPS(Float6), CLEARPS(Float7), CLEARPS(Float8)}}, + mPsUInt{{CLEARPS(Uint1), CLEARPS(Uint2), CLEARPS(Uint3), CLEARPS(Uint4), CLEARPS(Uint5), + CLEARPS(Uint6), CLEARPS(Uint7), CLEARPS(Uint8)}}, + mPsSInt{{CLEARPS(Sint1), CLEARPS(Sint2), CLEARPS(Sint3), CLEARPS(Sint4), CLEARPS(Sint5), + CLEARPS(Sint6), CLEARPS(Sint7), CLEARPS(Sint8)}} { - SafeDelete(inputLayout); - vertexShader.release(); - pixelShader.release(); } -Clear11::Clear11(Renderer11 *renderer) - : mRenderer(renderer), - mClearBlendStates(StructLessThan), - mFloatClearShader(nullptr), - mUintClearShader(nullptr), - mIntClearShader(nullptr), - mClearDepthStencilStates(StructLessThan), - mVertexBuffer(nullptr), - mRasterizerState(nullptr) +#undef CLEARPS + +Clear11::ShaderManager::~ShaderManager() { - TRACE_EVENT0("gpu.angle", "Clear11::Clear11"); +} - HRESULT result; - ID3D11Device *device = renderer->getDevice(); +gl::Error Clear11::ShaderManager::getShadersAndLayout(Renderer11 *renderer, + const INT clearType, + const uint32_t numRTs, + const bool hasLayeredLayout, + const d3d11::InputLayout **il, + const d3d11::VertexShader **vs, + const d3d11::GeometryShader **gs, + const d3d11::PixelShader **ps) +{ + if (renderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + { + ASSERT(clearType == GL_FLOAT); - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; + ANGLE_TRY(mVs9.resolve(renderer)); + ANGLE_TRY(mPsFloat9.resolve(renderer)); - result = device->CreateBuffer(&vbDesc, nullptr, &mVertexBuffer); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + if (!mIl9.valid()) + { + const D3D11_INPUT_ELEMENT_DESC ilDesc[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; - D3D11_RASTERIZER_DESC rsDesc; - rsDesc.FillMode = D3D11_FILL_SOLID; - rsDesc.CullMode = D3D11_CULL_NONE; - rsDesc.FrontCounterClockwise = FALSE; - rsDesc.DepthBias = 0; - rsDesc.DepthBiasClamp = 0.0f; - rsDesc.SlopeScaledDepthBias = 0.0f; - rsDesc.DepthClipEnable = TRUE; - rsDesc.ScissorEnable = FALSE; - rsDesc.MultisampleEnable = FALSE; - rsDesc.AntialiasedLineEnable = FALSE; + InputElementArray ilDescArray(ilDesc); + ShaderData vertexShader(g_VS_Clear_FL9); - result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + ANGLE_TRY(renderer->allocateResource(ilDescArray, &vertexShader, &mIl9)); + } - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + *vs = &mVs9.getObj(); + *gs = nullptr; + *il = &mIl9; + *ps = &mPsFloat9.getObj(); + return gl::NoError(); + } + if (!hasLayeredLayout) { - 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"); + ANGLE_TRY(mVs.resolve(renderer)); + *vs = &mVs.getObj(); + *gs = nullptr; } else { - 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"); + // For layered framebuffers we have to use the multi-view versions of the VS and GS. + ANGLE_TRY(mVsMultiview.resolve(renderer)); + ANGLE_TRY(mGsMultiview.resolve(renderer)); + *vs = &mVsMultiview.getObj(); + *gs = &mGsMultiview.getObj(); + } + + *il = nullptr; + + if (numRTs == 0) + { + ANGLE_TRY(mPsDepth.resolve(renderer)); + *ps = &mPsDepth.getObj(); + return gl::NoError(); } - if (renderer->isES3Capable()) + switch (clearType) { - 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"); + case GL_FLOAT: + ANGLE_TRY(mPsFloat[numRTs - 1].resolve(renderer)); + *ps = &mPsFloat[numRTs - 1].getObj(); + break; + case GL_UNSIGNED_INT: + ANGLE_TRY(mPsUInt[numRTs - 1].resolve(renderer)); + *ps = &mPsUInt[numRTs - 1].getObj(); + break; + case GL_INT: + ANGLE_TRY(mPsSInt[numRTs - 1].resolve(renderer)); + *ps = &mPsSInt[numRTs - 1].getObj(); + break; + default: + UNREACHABLE(); + break; } + + return gl::NoError(); +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), + mResourcesInitialized(false), + mScissorEnabledRasterizerState(), + mScissorDisabledRasterizerState(), + mShaderManager(), + mConstantBuffer(), + mVertexBuffer(), + mShaderData({}) +{ } Clear11::~Clear11() { - for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) +} + +gl::Error Clear11::ensureResourcesInitialized() +{ + if (mResourcesInitialized) { - SafeRelease(i->second); + return gl::NoError(); } - mClearBlendStates.clear(); - SafeDelete(mFloatClearShader); - SafeDelete(mUintClearShader); - SafeDelete(mIntClearShader); + TRACE_EVENT0("gpu.angle", "Clear11::ensureResourcesInitialized"); + + static_assert((sizeof(RtvDsvClearInfo) == sizeof(RtvDsvClearInfo)), + "Size of rx::RtvDsvClearInfo is not equal to rx::RtvDsvClearInfo"); + + static_assert( + (sizeof(RtvDsvClearInfo) == sizeof(RtvDsvClearInfo)), + "Size of rx::RtvDsvClearInfo is not equal to rx::RtvDsvClearInfo"); - for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + static_assert((sizeof(RtvDsvClearInfo) % 16 == 0), + "The size of RtvDsvClearInfo should be a multiple of 16bytes."); + + // Create Rasterizer States + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_NONE; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.ScissorEnable = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.AntialiasedLineEnable = FALSE; + + ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorDisabledRasterizerState)); + mScissorDisabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor disabled"); + + rsDesc.ScissorEnable = TRUE; + ANGLE_TRY(mRenderer->allocateResource(rsDesc, &mScissorEnabledRasterizerState)); + mScissorEnabledRasterizerState.setDebugName("Clear11 Rasterizer State with scissor enabled"); + + // Initialize Depthstencil state with defaults + mDepthStencilStateKey.depthTest = false; + mDepthStencilStateKey.depthMask = false; + mDepthStencilStateKey.depthFunc = GL_ALWAYS; + mDepthStencilStateKey.stencilWritemask = static_cast(-1); + mDepthStencilStateKey.stencilBackWritemask = static_cast(-1); + mDepthStencilStateKey.stencilBackMask = 0; + mDepthStencilStateKey.stencilTest = false; + mDepthStencilStateKey.stencilMask = 0; + mDepthStencilStateKey.stencilFail = GL_REPLACE; + mDepthStencilStateKey.stencilPassDepthFail = GL_REPLACE; + mDepthStencilStateKey.stencilPassDepthPass = GL_REPLACE; + mDepthStencilStateKey.stencilFunc = GL_ALWAYS; + mDepthStencilStateKey.stencilBackFail = GL_REPLACE; + mDepthStencilStateKey.stencilBackPassDepthFail = GL_REPLACE; + mDepthStencilStateKey.stencilBackPassDepthPass = GL_REPLACE; + mDepthStencilStateKey.stencilBackFunc = GL_ALWAYS; + + // Initialize BlendStateKey with defaults + mBlendStateKey.blendState.blend = false; + mBlendStateKey.blendState.sourceBlendRGB = GL_ONE; + mBlendStateKey.blendState.sourceBlendAlpha = GL_ONE; + mBlendStateKey.blendState.destBlendRGB = GL_ZERO; + mBlendStateKey.blendState.destBlendAlpha = GL_ZERO; + mBlendStateKey.blendState.blendEquationRGB = GL_FUNC_ADD; + mBlendStateKey.blendState.blendEquationAlpha = GL_FUNC_ADD; + mBlendStateKey.blendState.sampleAlphaToCoverage = false; + mBlendStateKey.blendState.dither = true; + + mResourcesInitialized = true; + return gl::NoError(); +} + +bool Clear11::useVertexBuffer() const +{ + return (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3); +} + +gl::Error Clear11::ensureConstantBufferCreated() +{ + if (mConstantBuffer.valid()) { - SafeRelease(i->second); + return gl::NoError(); } - mClearDepthStencilStates.clear(); - SafeRelease(mVertexBuffer); - SafeRelease(mRasterizerState); + // Create constant buffer for color & depth data + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = g_ConstantBufferSize; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = &mShaderData; + initialData.SysMemPitch = g_ConstantBufferSize; + initialData.SysMemSlicePitch = g_ConstantBufferSize; + + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mConstantBuffer)); + mConstantBuffer.setDebugName("Clear11 Constant Buffer"); + return gl::NoError(); } -gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData) +gl::Error Clear11::ensureVertexBufferCreated() { - const auto &colorAttachments = fboData.getColorAttachments(); - const auto &drawBufferStates = fboData.getDrawBufferStates(); - const auto *depthAttachment = fboData.getDepthAttachment(); - const auto *stencilAttachment = fboData.getStencilAttachment(); + ASSERT(useVertexBuffer()); + + if (mVertexBuffer.valid()) + { + return gl::NoError(); + } + + // Create vertex buffer with vertices for a quad covering the entire surface + + static_assert((sizeof(d3d11::PositionVertex) % 16) == 0, + "d3d11::PositionVertex should be a multiple of 16 bytes"); + const d3d11::PositionVertex vbData[6] = {{-1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}, + {-1.0f, -1.0f, 0.0f, 1.0f}, {-1.0f, 1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f}}; + + const UINT vbSize = sizeof(vbData); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = vbSize; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA initialData; + initialData.pSysMem = vbData; + initialData.SysMemPitch = vbSize; + initialData.SysMemSlicePitch = initialData.SysMemPitch; + + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &initialData, &mVertexBuffer)); + mVertexBuffer.setDebugName("Clear11 Vertex Buffer"); + return gl::NoError(); +} - ASSERT(colorAttachments.size() == drawBufferStates.size()); +gl::Error Clear11::clearFramebuffer(const gl::Context *context, + const ClearParameters &clearParams, + const gl::FramebufferState &fboData) +{ + ANGLE_TRY(ensureResourcesInitialized()); // Iterate over the color buffers which require clearing and determine if they can be // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView. // This requires: - // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer - // render targets as expected but does not work the other way around) + // 1) The render target is being cleared to a float value (will be cast to integer when clearing + // integer render targets as expected but does not work the other way around) // 2) The format of the render target has no color channels that are currently masked out. - // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. + // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special + // work. // // If these conditions are met, and: // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView. // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available. - // Otherwise draw a quad. + // Otherwise perform a shader based clear. // - // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView - // by checking if the stencil write mask covers the entire stencil. + // Also determine if the DSV can be cleared withID3D11DeviceContext::ClearDepthStencilView by + // checking if the stencil write mask covers the entire stencil. // - // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color - // attribute. + // To clear the remaining buffers, a shader based clear is performed: + // - The appropriate ShaderManagers (VS & PS) for the clearType is set + // - A CB containing the clear color and Z values is bound + // - An IL and VB are bound (for FL93 and below) + // - ScissorRect/Raststate/Viewport set as required + // - Blendstate set containing appropriate colorMasks + // - DepthStencilState set with appropriate parameters for a z or stencil clear if required + // - Color and/or Z buffers to be cleared are bound + // - Primitive covering entire clear area is drawn gl::Extents framebufferSize; - const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment(); - if (colorAttachment != nullptr) - { - framebufferSize = colorAttachment->getSize(); - } - else if (depthAttachment != nullptr) - { - framebufferSize = depthAttachment->getSize(); - } - else if (stencilAttachment != nullptr) + const auto *depthStencilAttachment = fboData.getDepthOrStencilAttachment(); + if (depthStencilAttachment != nullptr) { - framebufferSize = stencilAttachment->getSize(); + framebufferSize = depthStencilAttachment->getSize(); } else { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + const gl::FramebufferAttachment *colorAttachment = fboData.getFirstColorAttachment(); + + if (!colorAttachment) + { + UNREACHABLE(); + return gl::InternalError(); + } + + framebufferSize = colorAttachment->getSize(); } - if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || - clearParams.scissor.y >= framebufferSize.height || - clearParams.scissor.x + clearParams.scissor.width <= 0 || - clearParams.scissor.y + clearParams.scissor.height <= 0)) + const bool isSideBySideFBO = + (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE); + bool needScissoredClear = false; + std::vector scissorRects; + if (clearParams.scissorEnabled) { - // Scissor is enabled and the scissor rectangle is outside the renderbuffer - return gl::Error(GL_NO_ERROR); - } + const std::vector *viewportOffsets = fboData.getViewportOffsets(); + ASSERT(viewportOffsets != nullptr); + ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets())); - bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || - clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || - clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); + if (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 || + clearParams.scissor.height == 0) + { + // The check assumes that the viewport offsets are not negative as according to the + // ANGLE_multiview spec. + // Scissor rect is outside the renderbuffer or is an empty rect. + return gl::NoError(); + } - std::vector maskedClearRenderTargets; - RenderTarget11* maskedClearDepthStencil = nullptr; + if (isSideBySideFBO) + { + // We always have to do a scissor clear for side-by-side framebuffers. + needScissoredClear = true; + } + else + { + // Because the viewport offsets can generate scissor rectangles within the framebuffer's + // bounds, we can do this check only for non-side-by-side framebuffers. + if (clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0) + { + // Scissor rect is outside the renderbuffer. + return gl::NoError(); + } + needScissoredClear = + clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height; + } - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); -#if defined(ANGLE_ENABLE_D3D11_1) + if (needScissoredClear) + { + // Apply viewport offsets to compute the final scissor rectangles. This is valid also + // for non-side-by-side framebuffers, because the default viewport offset is {0,0}. + const size_t numViews = viewportOffsets->size(); + scissorRects.reserve(numViews); + for (size_t i = 0u; i < numViews; ++i) + { + const gl::Offset &offset = (*viewportOffsets)[i]; + D3D11_RECT rect; + int x = clearParams.scissor.x + offset.x; + int y = clearParams.scissor.y + offset.y; + rect.left = x; + rect.right = x + clearParams.scissor.width; + rect.top = y; + rect.bottom = y + clearParams.scissor.height; + scissorRects.emplace_back(rect); + } + } + } + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); -#endif - ID3D11Device *device = mRenderer->getDevice(); - for (size_t colorAttachmentIndex = 0; colorAttachmentIndex < colorAttachments.size(); - colorAttachmentIndex++) + std::array rtvs; + std::array rtvMasks = {}; + + uint32_t numRtvs = 0; + const uint8_t colorMask = + gl_d3d11::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen, + clearParams.colorMaskBlue, clearParams.colorMaskAlpha); + + const auto &colorAttachments = fboData.getColorAttachments(); + for (auto colorAttachmentIndex : fboData.getEnabledDrawBuffers()) { const gl::FramebufferAttachment &attachment = colorAttachments[colorAttachmentIndex]; - if (clearParams.clearColor[colorAttachmentIndex] && attachment.isAttached() && - drawBufferStates[colorAttachmentIndex] != GL_NONE) + if (!clearParams.clearColor[colorAttachmentIndex]) { - RenderTarget11 *renderTarget = nullptr; - gl::Error error = attachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + continue; + } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment.getInternalFormat()); + RenderTarget11 *renderTarget = nullptr; + ANGLE_TRY(attachment.getRenderTarget(context, &renderTarget)); - 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).", - colorAttachmentIndex, attachment.getInternalFormat()); - } + const gl::InternalFormat &formatInfo = *attachment.getFormat().info; - if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && - (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && - (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && - (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) - { - // Every channel either does not exist in the render target or is masked out - continue; - } - 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) || - (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) - { - // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable - MaskedRenderTarget maskAndRt; - bool clearColor = clearParams.clearColor[colorAttachmentIndex]; - maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); - maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); - maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); - maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); - maskAndRt.renderTarget = renderTarget; - maskedClearRenderTargets.push_back(maskAndRt); - } - else - { - // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible + if (clearParams.colorType == 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 " + << colorAttachmentIndex << " has internal format " << attachment.getFormat() + << ")."; + } - ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); - if (!framebufferRTV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } + if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && + (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && + (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && + (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) + { + // Every channel either does not exist in the render target or is masked out + continue; + } - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + const auto &framebufferRTV = renderTarget->getRenderTargetView(); + ASSERT(framebufferRTV.valid()); - // Check if the actual format has a channel that the internal format does not and set them to the - // default values - 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), - ((formatInfo.blueBits == 0 && dxgiFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), - ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), - }; + if ((!(mRenderer->getRenderer11DeviceCaps().supportsClearView) && needScissoredClear) || + clearParams.colorType != GL_FLOAT || + (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + rtvs[numRtvs] = framebufferRTV.get(); + rtvMasks[numRtvs] = gl_d3d11::GetColorMask(formatInfo) & colorMask; + numRtvs++; + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is + // possible + + const auto &nativeFormat = renderTarget->getFormatSet().format(); + + // Check if the actual format has a channel that the internal format does not and + // set them to the default values + float clearValues[4] = { + ((formatInfo.redBits == 0 && nativeFormat.redBits > 0) ? 0.0f + : clearParams.colorF.red), + ((formatInfo.greenBits == 0 && nativeFormat.greenBits > 0) + ? 0.0f + : clearParams.colorF.green), + ((formatInfo.blueBits == 0 && nativeFormat.blueBits > 0) ? 0.0f + : clearParams.colorF.blue), + ((formatInfo.alphaBits == 0 && nativeFormat.alphaBits > 0) + ? 1.0f + : clearParams.colorF.alpha), + }; + + if (formatInfo.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.colorF.alpha >= 0.5f) ? 1.0f : 0.0f; + } - if (dxgiFormatInfo.alphaBits == 1) + if (needScissoredClear) + { + // We shouldn't reach here if deviceContext1 is unavailable. + ASSERT(deviceContext1); + // There must be at least one scissor rectangle. + ASSERT(!scissorRects.empty()); + deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(), + static_cast(scissorRects.size())); + if (mRenderer->getWorkarounds().callClearTwice) { - // 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; + deviceContext1->ClearView(framebufferRTV.get(), clearValues, + scissorRects.data(), + static_cast(scissorRects.size())); } - -#if defined(ANGLE_ENABLE_D3D11_1) - if (needScissoredClear) - { - // We shouldn't reach here if deviceContext1 is unavailable. - ASSERT(deviceContext1); - - D3D11_RECT rect; - rect.left = clearParams.scissor.x; - rect.right = clearParams.scissor.x + clearParams.scissor.width; - rect.top = clearParams.scissor.y; - rect.bottom = clearParams.scissor.y + clearParams.scissor.height; - - deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1); - } - else -#endif + } + else + { + deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues); + if (mRenderer->getWorkarounds().callClearTwice) { - deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + deviceContext->ClearRenderTargetView(framebufferRTV.get(), clearValues); } } } } + ID3D11DepthStencilView *dsv = nullptr; + if (clearParams.clearDepth || clearParams.clearStencil) { - const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment; - ASSERT(attachment != nullptr); + RenderTarget11 *depthStencilRenderTarget = nullptr; - RenderTarget11 *renderTarget = nullptr; - gl::Error error = attachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ASSERT(depthStencilAttachment != nullptr); + ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget)); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + dsv = depthStencilRenderTarget->getDepthStencilView().get(); + ASSERT(dsv != nullptr); - unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0; - bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + const auto &nativeFormat = depthStencilRenderTarget->getFormatSet().format(); + const auto *stencilAttachment = fboData.getStencilAttachment(); - if (needScissoredClear || needMaskedStencilClear) - { - maskedClearDepthStencil = renderTarget; - } - else + uint32_t stencilUnmasked = + (stencilAttachment != nullptr) ? (1 << nativeFormat.stencilBits) - 1 : 0; + bool needMaskedStencilClear = + clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (!needScissoredClear && !needMaskedStencilClear) { - ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); - if (!framebufferDSV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); - } + const UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + const FLOAT depthClear = gl::clamp01(clearParams.depthValue); + const UINT8 stencilClear = clearParams.stencilValue & 0xFF; - UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | - (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); - FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); - UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; + deviceContext->ClearDepthStencilView(dsv, clearFlags, depthClear, stencilClear); - deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + dsv = nullptr; } } - if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + if (numRtvs == 0 && dsv == nullptr) { - // To clear the render targets and depth stencil in one pass: - // - // Render a quad clipped to the scissor rectangle which draws the clear color and a blend - // state that will perform the required color masking. - // - // The quad's depth is equal to the depth clear value with a depth stencil state that - // will enable or disable depth test/writes if the depth buffer should be cleared or not. - // - // The rasterizer state's stencil is set to always pass or fail based on if the stencil - // should be cleared or not with a stencil write mask of the stencil clear value. - // - // ====================================================================================== - // - // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- - // buffer that is not normalized fixed point or floating point with floating point values - // are undefined so we can just write floats to them and D3D11 will bit cast them to - // integers. - // - // Also, we don't have to worry about attempting to clear a normalized fixed/floating point - // buffer with integer values because there is no gl API call which would allow it, - // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to - // be a compatible clear type. - - // Bind all the render targets which need clearing - ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); - std::vector rtvs(maskedClearRenderTargets.size()); - for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) - { - RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; - ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); - if (!rtv) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } + return gl::NoError(); + } - rtvs[i] = rtv; - } - ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : nullptr; + // Clear the remaining render targets and depth stencil in one pass by rendering a quad: + // + // IA/VS: Vertices containing position and color members are passed through to the next stage. + // The vertex position has XY coordinates equal to clip extents and a Z component equal to the + // Z clear value. The vertex color contains the clear color. + // + // Rasterizer: Viewport scales the VS output over the entire surface and depending on whether + // or not scissoring is enabled the appropriate scissor rect and rasterizerState with or without + // the scissor test enabled is set as well. + // + // DepthStencilTest: DepthTesting, DepthWrites, StencilMask and StencilWrites will be enabled or + // disabled or set depending on what the input depthStencil clear parameters are. Since the PS + // is not writing out depth or rejecting pixels, this should happen prior to the PS stage. + // + // PS: Will write out the color values passed through from the previous stage to all outputs. + // + // OM: BlendState will perform the required color masking and output to RTV(s). + + // + // ====================================================================================== + // + // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- + // buffer that is not normalized fixed point or floating point with floating point values + // are undefined so we can just write floats to them and D3D11 will bit cast them to + // integers. + // + // Also, we don't have to worry about attempting to clear a normalized fixed/floating point + // buffer with integer values because there is no gl API call which would allow it, + // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to + // be a compatible clear type. - ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); - const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - const UINT sampleMask = 0xFFFFFFFF; + ASSERT(numRtvs <= mRenderer->getNativeCaps().maxDrawBuffers); - ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); - const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + // Setup BlendStateKey parameters + mBlendStateKey.blendState.colorMaskRed = clearParams.colorMaskRed; + mBlendStateKey.blendState.colorMaskGreen = clearParams.colorMaskGreen; + mBlendStateKey.blendState.colorMaskBlue = clearParams.colorMaskBlue; + mBlendStateKey.blendState.colorMaskAlpha = clearParams.colorMaskAlpha; + mBlendStateKey.rtvMax = numRtvs; + memcpy(mBlendStateKey.rtvMasks, &rtvMasks[0], sizeof(mBlendStateKey.rtvMasks)); - // Set the vertices - UINT vertexStride = 0; - const UINT startIdx = 0; - ClearShader *shader = nullptr; - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result); - } + // Get BlendState + const d3d11::BlendState *blendState = nullptr; + ANGLE_TRY(mRenderer->getBlendState(mBlendStateKey, &blendState)); - 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; - break; + const d3d11::DepthStencilState *dsState = nullptr; + const float *zValue = nullptr; - case GL_UNSIGNED_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = mUintClearShader; - break; + if (dsv) + { + // Setup DepthStencilStateKey + mDepthStencilStateKey.depthTest = clearParams.clearDepth; + mDepthStencilStateKey.depthMask = clearParams.clearDepth; + mDepthStencilStateKey.stencilWritemask = clearParams.stencilWriteMask; + mDepthStencilStateKey.stencilTest = clearParams.clearStencil; + + // Get DepthStencilState + ANGLE_TRY(mRenderer->getDepthStencilState(mDepthStencilStateKey, &dsState)); + zValue = clearParams.clearDepth ? &clearParams.depthValue : nullptr; + } - case GL_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = mIntClearShader; - break; + bool dirtyCb = false; - default: + // Compare the input color/z values against the CB cache and update it if necessary + switch (clearParams.colorType) + { + case GL_FLOAT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorF, zValue, numRtvs, colorMask); + break; + case GL_UNSIGNED_INT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorUI, zValue, numRtvs, colorMask); + break; + case GL_INT: + dirtyCb = UpdateDataCache(reinterpret_cast *>(&mShaderData), + clearParams.colorI, zValue, numRtvs, colorMask); + break; + default: UNREACHABLE(); break; - } - - deviceContext->Unmap(mVertexBuffer, 0); - - // Set the viewport to be the same size as the framebuffer - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(framebufferSize.width); - viewport.Height = static_cast(framebufferSize.height); - viewport.MinDepth = 0; - viewport.MaxDepth = 1; - deviceContext->RSSetViewports(1, &viewport); - - // Apply state - deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); - deviceContext->OMSetDepthStencilState(dsState, stencilClear); - deviceContext->RSSetState(mRasterizerState); - - // Apply shaders - 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(static_cast(rtvs.size()), - (rtvs.empty() ? nullptr : &rtvs[0]), dsv); - - // Draw the clear quad - deviceContext->Draw(4, 0); - - // Clean up - mRenderer->markAllStateDirty(); } - return gl::Error(GL_NO_ERROR); -} + ANGLE_TRY(ensureConstantBufferCreated()); -ID3D11BlendState *Clear11::getBlendState(const std::vector& rts) -{ - ClearBlendInfo blendKey = {}; - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + if (dirtyCb) { - if (i < rts.size()) - { - RenderTarget11 *rt = rts[i].renderTarget; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat()); - - blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits > 0); - blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0); - blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits > 0); - blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0); - } - else + // Update the constant buffer with the updated cache contents + // TODO(Shahmeer): Consider using UpdateSubresource1 D3D11_COPY_DISCARD where possible. + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, + &mappedResource); + if (FAILED(result)) { - blendKey.maskChannels[i][0] = false; - blendKey.maskChannels[i][1] = false; - blendKey.maskChannels[i][2] = false; - blendKey.maskChannels[i][3] = false; + return gl::OutOfMemory() << "Clear11: Failed to map CB, " << gl::FmtHR(result); } - } - ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); - if (i != mClearBlendStates.end()) - { - return i->second; + memcpy(mappedResource.pData, &mShaderData, g_ConstantBufferSize); + deviceContext->Unmap(mConstantBuffer.get(), 0); } - else - { - D3D11_BLEND_DESC blendDesc = { 0 }; - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; - for (unsigned int j = 0; j < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; j++) - { - blendDesc.RenderTarget[j].BlendEnable = FALSE; - blendDesc.RenderTarget[j].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[j][0], - blendKey.maskChannels[j][1], - blendKey.maskChannels[j][2], - blendKey.maskChannels[j][3]); - } + auto *stateManager = mRenderer->getStateManager(); - ID3D11Device *device = mRenderer->getDevice(); - ID3D11BlendState* blendState = nullptr; - HRESULT result = device->CreateBlendState(&blendDesc, &blendState); - if (FAILED(result) || !blendState) - { - ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); - return nullptr; - } + // Set the viewport to be the same size as the framebuffer. + stateManager->setSimpleViewport(framebufferSize); - mClearBlendStates[blendKey] = blendState; + // Apply state + stateManager->setSimpleBlendState(blendState); - return blendState; - } -} + const UINT stencilValue = clearParams.stencilValue & 0xFF; + stateManager->setDepthStencilState(dsState, stencilValue); -ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &clearParams) -{ - ClearDepthStencilInfo dsKey = { 0 }; - dsKey.clearDepth = clearParams.clearDepth; - dsKey.clearStencil = clearParams.clearStencil; - dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + if (needScissoredClear) + { + stateManager->setRasterizerState(&mScissorEnabledRasterizerState); + } + else + { + stateManager->setRasterizerState(&mScissorDisabledRasterizerState); + } - ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); - if (i != mClearDepthStencilStates.end()) + // Get Shaders + const d3d11::VertexShader *vs = nullptr; + const d3d11::GeometryShader *gs = nullptr; + const d3d11::InputLayout *il = nullptr; + const d3d11::PixelShader *ps = nullptr; + const bool hasLayeredLayout = + (fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE); + ANGLE_TRY(mShaderManager.getShadersAndLayout(mRenderer, clearParams.colorType, numRtvs, + hasLayeredLayout, &il, &vs, &gs, &ps)); + + // Apply Shaders + stateManager->setDrawShaders(vs, gs, ps); + stateManager->setPixelConstantBuffer(0, &mConstantBuffer); + + // Bind IL & VB if needed + stateManager->setIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0); + stateManager->setInputLayout(il); + + if (useVertexBuffer()) { - return i->second; + ANGLE_TRY(ensureVertexBufferCreated()); + stateManager->setSingleVertexBuffer(&mVertexBuffer, g_VertexSize, 0); } else { - D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; - dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; - dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; - dsDesc.StencilReadMask = 0; - dsDesc.StencilWriteMask = dsKey.stencilWriteMask; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DepthStencilState* dsState = nullptr; - HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); - if (FAILED(result) || !dsState) - { - ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); - return nullptr; - } + stateManager->setSingleVertexBuffer(nullptr, 0, 0); + } - mClearDepthStencilStates[dsKey] = dsState; + stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - return dsState; + // Apply render targets + stateManager->setRenderTargets(&rtvs[0], numRtvs, dsv); + + // If scissors are necessary to be applied, then the number of clears is the number of scissor + // rects. If no scissors are necessary, then a single full-size clear is enough. + size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u; + for (size_t i = 0u; i < necessaryNumClears; ++i) + { + if (needScissoredClear) + { + ASSERT(i < scissorRects.size()); + stateManager->setScissorRectD3D(scissorRects[i]); + } + // Draw the fullscreen quad. + if (!hasLayeredLayout || isSideBySideFBO) + { + deviceContext->Draw(6, 0); + } + else + { + ASSERT(hasLayeredLayout); + deviceContext->DrawInstanced(6, static_cast(fboData.getNumViews()), 0, 0); + } } -} + return gl::NoError(); } + +} // namespace rx 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 3ff73c85d1..a09812c42b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h @@ -23,6 +23,14 @@ class Renderer11; class RenderTarget11; struct ClearParameters; +template +struct RtvDsvClearInfo +{ + T r, g, b, a; + float z; + float c1padding[3]; +}; + class Clear11 : angle::NonCopyable { public: @@ -30,68 +38,63 @@ class Clear11 : angle::NonCopyable ~Clear11(); // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. - gl::Error clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData); + gl::Error clearFramebuffer(const gl::Context *context, + const ClearParameters &clearParams, + const gl::FramebufferState &fboData); private: - struct MaskedRenderTarget - { - bool colorMask[4]; - RenderTarget11 *renderTarget; - }; - - ID3D11BlendState *getBlendState(const std::vector &rts); - ID3D11DepthStencilState *getDepthStencilState(const ClearParameters &clearParams); - - struct ClearShader final : public angle::NonCopyable + class ShaderManager final : angle::NonCopyable { - 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; + public: + ShaderManager(); + ~ShaderManager(); + gl::Error getShadersAndLayout(Renderer11 *renderer, + const INT clearType, + const uint32_t numRTs, + const bool hasLayeredLayout, + const d3d11::InputLayout **il, + const d3d11::VertexShader **vs, + const d3d11::GeometryShader **gs, + const d3d11::PixelShader **ps); + + private: + constexpr static size_t kNumShaders = D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + d3d11::InputLayout mIl9; + d3d11::LazyShader mVs9; + d3d11::LazyShader mPsFloat9; + d3d11::LazyShader mVs; + d3d11::LazyShader mVsMultiview; + d3d11::LazyShader mGsMultiview; + d3d11::LazyShader mPsDepth; + std::array, kNumShaders> mPsFloat; + std::array, kNumShaders> mPsUInt; + std::array, kNumShaders> mPsSInt; }; - template - static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE(&vsByteCode)[vsSize], const BYTE(&psByteCode)[psSize]); - - struct ClearBlendInfo - { - bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; - }; - typedef bool(*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); - typedef std::map ClearBlendStateMap; - - struct ClearDepthStencilInfo - { - bool clearDepth; - bool clearStencil; - UINT8 stencilWriteMask; - }; - typedef bool(*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); - typedef std::map ClearDepthStencilStateMap; + bool useVertexBuffer() const; + gl::Error ensureConstantBufferCreated(); + gl::Error ensureVertexBufferCreated(); + gl::Error ensureResourcesInitialized(); Renderer11 *mRenderer; + bool mResourcesInitialized; - ClearBlendStateMap mClearBlendStates; - - ClearShader *mFloatClearShader; - ClearShader *mUintClearShader; - ClearShader *mIntClearShader; + // States + d3d11::RasterizerState mScissorEnabledRasterizerState; + d3d11::RasterizerState mScissorDisabledRasterizerState; + gl::DepthStencilState mDepthStencilStateKey; + d3d11::BlendStateKey mBlendStateKey; - ClearDepthStencilStateMap mClearDepthStencilStates; + // Shaders and shader resources + ShaderManager mShaderManager; + d3d11::Buffer mConstantBuffer; + d3d11::Buffer mVertexBuffer; - ID3D11Buffer *mVertexBuffer; - ID3D11RasterizerState *mRasterizerState; + // Buffer data and draw parameters + RtvDsvClearInfo mShaderData; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp new file mode 100644 index 0000000000..b79dd3603a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp @@ -0,0 +1,405 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context11: +// D3D11-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/d3d/d3d11/Context11.h" + +#include "common/string_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/MemoryProgramCache.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/SamplerD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/StateManager11.h" +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" + +namespace rx +{ + +Context11::Context11(const gl::ContextState &state, Renderer11 *renderer) + : ContextImpl(state), mRenderer(renderer) +{ +} + +Context11::~Context11() +{ +} + +gl::Error Context11::initialize() +{ + return gl::NoError(); +} + +CompilerImpl *Context11::createCompiler() +{ + if (mRenderer->getRenderer11DeviceCaps().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); + } +} + +ShaderImpl *Context11::createShader(const gl::ShaderState &data) +{ + return new ShaderD3D(data, mRenderer->getWorkarounds(), mRenderer->getNativeExtensions()); +} + +ProgramImpl *Context11::createProgram(const gl::ProgramState &data) +{ + return new ProgramD3D(data, mRenderer); +} + +FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data) +{ + return new Framebuffer11(data, mRenderer); +} + +TextureImpl *Context11::createTexture(const gl::TextureState &state) +{ + switch (state.getTarget()) + { + case GL_TEXTURE_2D: + return new TextureD3D_2D(state, mRenderer); + case GL_TEXTURE_CUBE_MAP: + return new TextureD3D_Cube(state, mRenderer); + case GL_TEXTURE_3D: + return new TextureD3D_3D(state, mRenderer); + case GL_TEXTURE_2D_ARRAY: + return new TextureD3D_2DArray(state, mRenderer); + case GL_TEXTURE_EXTERNAL_OES: + return new TextureD3D_External(state, mRenderer); + case GL_TEXTURE_2D_MULTISAMPLE: + return new TextureD3D_2DMultisample(state, mRenderer); + break; + default: + UNREACHABLE(); + } + + return nullptr; +} + +RenderbufferImpl *Context11::createRenderbuffer() +{ + return new RenderbufferD3D(mRenderer); +} + +BufferImpl *Context11::createBuffer(const gl::BufferState &state) +{ + Buffer11 *buffer = new Buffer11(state, mRenderer); + mRenderer->onBufferCreate(buffer); + return buffer; +} + +VertexArrayImpl *Context11::createVertexArray(const gl::VertexArrayState &data) +{ + return new VertexArray11(data); +} + +QueryImpl *Context11::createQuery(GLenum type) +{ + return new Query11(mRenderer, type); +} + +FenceNVImpl *Context11::createFenceNV() +{ + return new FenceNV11(mRenderer); +} + +SyncImpl *Context11::createSync() +{ + return new Sync11(mRenderer); +} + +TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state) +{ + return new TransformFeedback11(state, mRenderer); +} + +SamplerImpl *Context11::createSampler(const gl::SamplerState &state) +{ + return new SamplerD3D(state); +} + +ProgramPipelineImpl *Context11::createProgramPipeline(const gl::ProgramPipelineState &data) +{ + return new ProgramPipeline11(data); +} + +std::vector Context11::createPaths(GLsizei) +{ + return std::vector(); +} + +gl::Error Context11::flush(const gl::Context *context) +{ + return mRenderer->flush(); +} + +gl::Error Context11::finish(const gl::Context *context) +{ + return mRenderer->finish(); +} + +gl::Error Context11::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArrays(context, mode, first, count, 0); +} + +gl::Error Context11::drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArrays(context, mode, first, count, instanceCount); +} + +gl::Error Context11::drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context11::drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, instances); +} + +gl::Error Context11::drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context11::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawArraysIndirect(context, mode, indirect); +} + +gl::Error Context11::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) +{ + ANGLE_TRY(prepareForDrawCall(context, mode)); + return mRenderer->drawElementsIndirect(context, mode, type, indirect); +} + +GLenum Context11::getResetStatus() +{ + return mRenderer->getResetStatus(); +} + +std::string Context11::getVendorString() const +{ + return mRenderer->getVendorString(); +} + +std::string Context11::getRendererDescription() const +{ + return mRenderer->getRendererDescription(); +} + +void Context11::insertEventMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->setMarker(optionalString.value().data()); + } +} + +void Context11::pushGroupMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->beginEvent(optionalString.value().data()); + } +} + +void Context11::popGroupMarker() +{ + mRenderer->getAnnotator()->endEvent(); +} + +void Context11::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +{ + // Fall through to the EXT_debug_marker functions + pushGroupMarker(length, message); +} + +void Context11::popDebugGroup() +{ + // Fall through to the EXT_debug_marker functions + popGroupMarker(); +} + +void Context11::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) +{ + mRenderer->getStateManager()->syncState(context, dirtyBits); +} + +GLint Context11::getGPUDisjoint() +{ + return mRenderer->getGPUDisjoint(); +} + +GLint64 Context11::getTimestamp() +{ + return mRenderer->getTimestamp(); +} + +void Context11::onMakeCurrent(const gl::Context *context) +{ + ANGLE_SWALLOW_ERR(mRenderer->getStateManager()->onMakeCurrent(context)); +} + +const gl::Caps &Context11::getNativeCaps() const +{ + return mRenderer->getNativeCaps(); +} + +const gl::TextureCapsMap &Context11::getNativeTextureCaps() const +{ + return mRenderer->getNativeTextureCaps(); +} + +const gl::Extensions &Context11::getNativeExtensions() const +{ + return mRenderer->getNativeExtensions(); +} + +const gl::Limitations &Context11::getNativeLimitations() const +{ + return mRenderer->getNativeLimitations(); +} + +gl::Error Context11::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + return mRenderer->dispatchCompute(context, numGroupsX, numGroupsY, numGroupsZ); +} + +gl::Error Context11::triggerDrawCallProgramRecompilation(const gl::Context *context, + GLenum drawMode) +{ + const auto &glState = context->getGLState(); + const auto *va11 = GetImplAs(glState.getVertexArray()); + const auto *drawFBO = glState.getDrawFramebuffer(); + gl::Program *program = glState.getProgram(); + ProgramD3D *programD3D = GetImplAs(program); + + programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState); + programD3D->updateCachedOutputLayout(context, drawFBO); + + bool recompileVS = !programD3D->hasVertexExecutableForCachedInputLayout(); + bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(drawMode); + bool recompilePS = !programD3D->hasPixelExecutableForCachedOutputLayout(); + + if (!recompileVS && !recompileGS && !recompilePS) + { + return gl::NoError(); + } + + // Load the compiler if necessary and recompile the programs. + ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); + + gl::InfoLog infoLog; + + if (recompileVS) + { + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, &infoLog)); + if (!programD3D->hasVertexExecutableForCachedInputLayout()) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic vertex executable:" << infoLog.str(); + } + } + + if (recompileGS) + { + ShaderExecutableD3D *geometryExe = nullptr; + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe, + &infoLog)); + if (!programD3D->hasGeometryExecutableForPrimitiveType(drawMode)) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic geometry executable:" << infoLog.str(); + } + } + + if (recompilePS) + { + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, &infoLog)); + if (!programD3D->hasPixelExecutableForCachedOutputLayout()) + { + ASSERT(infoLog.getLength() > 0); + ERR() << "Dynamic recompilation error log: " << infoLog.str(); + return gl::InternalError() + << "Error compiling dynamic pixel executable:" << infoLog.str(); + } + } + + // Refresh the program cache entry. + if (mMemoryProgramCache) + { + mMemoryProgramCache->updateProgram(context, program); + } + + return gl::NoError(); +} + +gl::Error Context11::prepareForDrawCall(const gl::Context *context, GLenum drawMode) +{ + ANGLE_TRY(mRenderer->getStateManager()->updateState(context, drawMode)); + return gl::NoError(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h new file mode 100644 index 0000000000..dd99111b19 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h @@ -0,0 +1,155 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context11: +// D3D11-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_H_ + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ +class Renderer11; + +class Context11 : public ContextImpl +{ + public: + Context11(const gl::ContextState &state, Renderer11 *renderer); + ~Context11() override; + + gl::Error initialize() override; + + // Shader creation + CompilerImpl *createCompiler() override; + ShaderImpl *createShader(const gl::ShaderState &data) override; + ProgramImpl *createProgram(const gl::ProgramState &data) override; + + // Framebuffer creation + FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override; + + // Texture creation + TextureImpl *createTexture(const gl::TextureState &state) override; + + // Renderbuffer creation + RenderbufferImpl *createRenderbuffer() override; + + // Buffer creation + BufferImpl *createBuffer(const gl::BufferState &state) override; + + // Vertex Array creation + VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override; + + // Query and Fence creation + QueryImpl *createQuery(GLenum type) override; + FenceNVImpl *createFenceNV() override; + SyncImpl *createSync() override; + + // Transform Feedback creation + TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) override; + + // Sampler object creation + SamplerImpl *createSampler(const gl::SamplerState &state) override; + + // Program Pipeline object creation + ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; + + // Path object creation. + std::vector createPaths(GLsizei) override; + + // Flush and finish. + gl::Error flush(const gl::Context *context) override; + gl::Error finish(const gl::Context *context) override; + + // Drawing methods. + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) override; + gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) override; + + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) override; + gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) override; + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) override; + + // Device loss + GLenum getResetStatus() override; + + // Vendor and description strings. + std::string getVendorString() const override; + std::string getRendererDescription() const override; + + // EXT_debug_marker + void insertEventMarker(GLsizei length, const char *marker) override; + void pushGroupMarker(GLsizei length, const char *marker) override; + void popGroupMarker() override; + + // KHR_debug + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void popDebugGroup() override; + + // State sync with dirty bits. + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) override; + + // Disjoint timer queries + GLint getGPUDisjoint() override; + GLint64 getTimestamp() override; + + // Context switching + void onMakeCurrent(const gl::Context *context) override; + + // Caps queries + const gl::Caps &getNativeCaps() const override; + const gl::TextureCapsMap &getNativeTextureCaps() const override; + const gl::Extensions &getNativeExtensions() const override; + const gl::Limitations &getNativeLimitations() const override; + + Renderer11 *getRenderer() const { return mRenderer; } + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) override; + + gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context, GLenum drawMode); + + private: + gl::Error prepareForDrawCall(const gl::Context *context, GLenum drawMode); + + Renderer11 *mRenderer; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_CONTEXT11_H_ 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 1c35ab45cc..1e70363e11 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp @@ -27,9 +27,7 @@ DebugAnnotator11::~DebugAnnotator11() { if (mInitialized) { -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(mUserDefinedAnnotation); -#endif #if !defined(ANGLE_ENABLE_WINDOWS_STORE) FreeLibrary(mD3d11Module); @@ -43,9 +41,7 @@ void DebugAnnotator11::beginEvent(const wchar_t *eventName) if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->BeginEvent(eventName); -#endif } } @@ -55,9 +51,7 @@ void DebugAnnotator11::endEvent() if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->EndEvent(); -#endif } } @@ -67,16 +61,14 @@ void DebugAnnotator11::setMarker(const wchar_t *markerName) if (mUserDefinedAnnotation != nullptr) { -#if defined(ANGLE_ENABLE_D3D11_1) mUserDefinedAnnotation->SetMarker(markerName); -#endif } } bool DebugAnnotator11::getStatus() { #if defined(ANGLE_ENABLE_WINDOWS_STORE) -#if (NTDDI_VERSION == NTDDI_WIN10) + static_assert(NTDDI_VERSION >= NTDDI_WIN10, "GetStatus only works on Win10 and above"); initializeDevice(); if (mUserDefinedAnnotation != nullptr) @@ -85,38 +77,6 @@ bool DebugAnnotator11::getStatus() } return true; // Default if initializeDevice() failed -#elif defined(_DEBUG) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) - static bool underCapture = true; - - // 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. - - // 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); - } - - 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; @@ -141,14 +101,13 @@ void DebugAnnotator11::initializeDevice() HRESULT hr = E_FAIL; // 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); + hr = D3D11CreateDevice(nullptr, 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); -#endif 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 d1a0f7fd2e..62662c49ae 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h @@ -9,14 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ -#include "common/debug.h" - -struct ID3DUserDefinedAnnotation; +#include "libANGLE/LoggingAnnotator.h" namespace rx { -class DebugAnnotator11 : public gl::DebugAnnotator +class DebugAnnotator11 : public angle::LoggingAnnotator { public: DebugAnnotator11(); 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 53fac65f2a..082f28d794 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp @@ -4,7 +4,8 @@ // found in the LICENSE file. // -// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. +// Fence11.cpp: Defines the rx::FenceNV11 and rx::Sync11 classes which implement +// rx::FenceNVImpl and rx::SyncImpl. #include "libANGLE/renderer/d3d/d3d11/Fence11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" @@ -14,28 +15,30 @@ namespace rx { +static const int kDeviceLostCheckPeriod = 64; + // // Template helpers for set and test operations. // -template +template gl::Error FenceSetHelper(FenceClass *fence) { if (!fence->mQuery) { D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.Query = D3D11_QUERY_EVENT; queryDesc.MiscFlags = 0; HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create event query, " << gl::FmtHR(result); } } fence->mRenderer->getDeviceContext()->End(fence->mQuery); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template @@ -44,30 +47,24 @@ gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean ASSERT(fence->mQuery); UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); - HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); + HRESULT result = + fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, nullptr, 0, getDataFlags); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); - } - else if (fence->mRenderer->isDeviceLost()) - { - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + return gl::OutOfMemory() << "Failed to get query data, " << gl::FmtHR(result); } ASSERT(result == S_OK || result == S_FALSE); *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // // FenceNV11 // -FenceNV11::FenceNV11(Renderer11 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) +FenceNV11::FenceNV11(Renderer11 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) { } @@ -89,22 +86,26 @@ gl::Error FenceNV11::test(GLboolean *outFinished) gl::Error FenceNV11::finish() { GLboolean finished = GL_FALSE; + + int loopCount = 0; while (finished != GL_TRUE) { - gl::Error error = FenceTestHelper(this, true, &finished); - if (error.isError()) + loopCount++; + ANGLE_TRY(FenceTestHelper(this, true, &finished)); + + if (loopCount % kDeviceLostCheckPeriod == 0 && mRenderer->testDeviceLost()) { - return error; + return gl::OutOfMemory() << "Device was lost while querying result of an event query."; } ScheduleYield(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // -// FenceSync11 +// Sync11 // // Important note on accurate timers in Windows: @@ -118,38 +119,34 @@ gl::Error FenceNV11::finish() // We still opt to use QPC. In the present and moving forward, most newer systems will not suffer // from buggy implementations. -FenceSync11::FenceSync11(Renderer11 *renderer) - : FenceSyncImpl(), - mRenderer(renderer), - mQuery(NULL) +Sync11::Sync11(Renderer11 *renderer) : SyncImpl(), mRenderer(renderer), mQuery(nullptr) { LARGE_INTEGER counterFreqency = {}; - BOOL success = QueryPerformanceFrequency(&counterFreqency); - UNUSED_ASSERTION_VARIABLE(success); + BOOL success = QueryPerformanceFrequency(&counterFreqency); ASSERT(success); mCounterFrequency = counterFreqency.QuadPart; } -FenceSync11::~FenceSync11() +Sync11::~Sync11() { SafeRelease(mQuery); } -gl::Error FenceSync11::set(GLenum condition, GLbitfield flags) +gl::Error Sync11::set(GLenum condition, GLbitfield flags) { ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0); return FenceSetHelper(this); } -gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +gl::Error Sync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) { ASSERT(outResult); bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); GLboolean result = GL_FALSE; - gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); if (error.isError()) { *outResult = GL_WAIT_FAILED; @@ -159,28 +156,34 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou if (result == GL_TRUE) { *outResult = GL_ALREADY_SIGNALED; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (timeout == 0) { *outResult = GL_TIMEOUT_EXPIRED; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } LARGE_INTEGER currentCounter = {}; - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); + BOOL success = QueryPerformanceCounter(¤tCounter); ASSERT(success); - LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); - LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + LONGLONG timeoutInSeconds = static_cast(timeout / 1000000000ull); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + // Extremely unlikely, but if mCounterFrequency is large enough, endCounter can wrap + if (endCounter < currentCounter.QuadPart) + { + endCounter = MAXLONGLONG; + } + + int loopCount = 0; while (currentCounter.QuadPart < endCounter && !result) { + loopCount++; ScheduleYield(); success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); ASSERT(success); error = FenceTestHelper(this, flushCommandBuffer, &result); @@ -189,6 +192,12 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou *outResult = GL_WAIT_FAILED; return error; } + + if ((loopCount % kDeviceLostCheckPeriod) == 0 && mRenderer->testDeviceLost()) + { + *outResult = GL_WAIT_FAILED; + return gl::OutOfMemory() << "Device was lost while querying result of an event query."; + } } if (currentCounter.QuadPart >= endCounter) @@ -200,32 +209,32 @@ gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *ou *outResult = GL_CONDITION_SATISFIED; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) +gl::Error Sync11::serverWait(GLbitfield flags, GLuint64 timeout) { // Because our API is currently designed to be called from a single thread, we don't need to do - // extra work for a server-side fence. GPU commands issued after the fence is created will always - // be processed after the fence is signaled. - return gl::Error(GL_NO_ERROR); + // extra work for a server-side fence. GPU commands issued after the fence is created will + // always be processed after the fence is signaled. + return gl::NoError(); } -gl::Error FenceSync11::getStatus(GLint *outResult) +gl::Error Sync11::getStatus(GLint *outResult) { GLboolean result = GL_FALSE; - gl::Error error = FenceTestHelper(this, false, &result); + gl::Error error = FenceTestHelper(this, false, &result); if (error.isError()) { - // The spec does not specify any way to report errors during the status test (e.g. device lost) - // so we report the fence is unblocked in case of error or signaled. + // The spec does not specify any way to report errors during the status test (e.g. device + // lost) so we report the fence is unblocked in case of error or signaled. *outResult = GL_SIGNALED; return error; } *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -} // namespace rx +} // namespace rx 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 595978885b..4168df5365 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h @@ -4,13 +4,14 @@ // found in the LICENSE file. // -// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. +// Fence11.h: Defines the rx::FenceNV11 and rx::Sync11 classes which implement rx::FenceNVImpl +// and rx::SyncImpl. #ifndef LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ #include "libANGLE/renderer/FenceNVImpl.h" -#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/SyncImpl.h" namespace rx { @@ -34,11 +35,11 @@ class FenceNV11 : public FenceNVImpl ID3D11Query *mQuery; }; -class FenceSync11 : public FenceSyncImpl +class Sync11 : public SyncImpl { public: - explicit FenceSync11(Renderer11 *renderer); - ~FenceSync11() override; + explicit Sync11(Renderer11 *renderer); + ~Sync11() override; gl::Error set(GLenum condition, GLbitfield flags) override; gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) override; 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 186a035902..02326d7b50 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp @@ -8,94 +8,119 @@ #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" +#include "common/bitset_utils.h" #include "common/debug.h" +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" #include "libANGLE/renderer/d3d/d3d11/Clear11.h" -#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.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/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/Framebuffer.h" -#include "libANGLE/FramebufferAttachment.h" -#include "libANGLE/Texture.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +using namespace angle; namespace rx { -Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer) - : FramebufferD3D(data, renderer), mRenderer(renderer) +namespace { - ASSERT(mRenderer != nullptr); -} - -Framebuffer11::~Framebuffer11() +gl::Error MarkAttachmentsDirty(const gl::Context *context, + const gl::FramebufferAttachment *attachment) { -} - -static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment) -{ - if (attachment && attachment->type() == GL_TEXTURE) + if (attachment->type() == GL_TEXTURE) { gl::Texture *texture = attachment->getTexture(); TextureD3D *textureD3D = GetImplAs(texture); TextureStorage *texStorage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&texStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage)); if (texStorage) { TextureStorage11 *texStorage11 = GetAs(texStorage); ASSERT(texStorage11); - texStorage11->invalidateSwizzleCacheLevel(attachment->mipLevel()); + texStorage11->markLevelDirty(attachment->mipLevel()); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidateSwizzles() const +void UpdateCachedRenderTarget(const gl::Context *context, + const gl::FramebufferAttachment *attachment, + RenderTarget11 *&cachedRenderTarget, + OnRenderTargetDirtyBinding *channelBinding) { - for (const auto &colorAttachment : mData.getColorAttachments()) + RenderTarget11 *newRenderTarget = nullptr; + if (attachment) { - if (colorAttachment.isAttached()) + // TODO(jmadill): Don't swallow this error. + gl::Error error = attachment->getRenderTarget(context, &newRenderTarget); + if (error.isError()) { - gl::Error error = InvalidateAttachmentSwizzles(&colorAttachment); - if (error.isError()) - { - return error; - } + ERR() << "Internal rendertarget error: " << error; } } + if (newRenderTarget != cachedRenderTarget) + { + OnRenderTargetDirtyChannel *channel = + (newRenderTarget ? newRenderTarget->getBroadcastChannel() : nullptr); + channelBinding->bind(channel); + cachedRenderTarget = newRenderTarget; + } +} +} // anonymous namespace + +Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer), + mCachedDepthStencilRenderTarget(nullptr), + mDepthStencilRenderTargetDirty(this, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) +{ + ASSERT(mRenderer != nullptr); + mCachedColorRenderTargets.fill(nullptr); + for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex) + { + mColorRenderTargetsDirty.emplace_back(this, colorIndex); + } +} - gl::Error error = InvalidateAttachmentSwizzles(mData.getDepthAttachment()); - if (error.isError()) +Framebuffer11::~Framebuffer11() +{ +} + +gl::Error Framebuffer11::markAttachmentsDirty(const gl::Context *context) const +{ + const auto &colorAttachments = mState.getColorAttachments(); + for (size_t drawBuffer : mState.getEnabledDrawBuffers()) { - return error; + const gl::FramebufferAttachment &colorAttachment = colorAttachments[drawBuffer]; + ASSERT(colorAttachment.isAttached()); + ANGLE_TRY(MarkAttachmentsDirty(context, &colorAttachment)); } - error = InvalidateAttachmentSwizzles(mData.getStencilAttachment()); - if (error.isError()) + const gl::FramebufferAttachment *dsAttachment = mState.getDepthOrStencilAttachment(); + if (dsAttachment) { - return error; + ANGLE_TRY(MarkAttachmentsDirty(context, dsAttachment)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clearParams) +gl::Error Framebuffer11::clearImpl(const gl::Context *context, const ClearParameters &clearParams) { Clear11 *clearer = mRenderer->getClearer(); - gl::Error error(GL_NO_ERROR); - const gl::FramebufferAttachment *colorAttachment = mData.getFirstColorAttachment(); + const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment(); if (clearParams.scissorEnabled == true && colorAttachment != nullptr && UsePresentPathFast(mRenderer, colorAttachment)) { @@ -107,46 +132,43 @@ gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clea presentPathFastClearParams.scissor.y = framebufferSize.height - presentPathFastClearParams.scissor.y - presentPathFastClearParams.scissor.height; - error = clearer->clearFramebuffer(presentPathFastClearParams, mData); + ANGLE_TRY(clearer->clearFramebuffer(context, presentPathFastClearParams, mState)); } else { - error = clearer->clearFramebuffer(clearParams, mData); + ANGLE_TRY(clearer->clearFramebuffer(context, clearParams, mState)); } - if (error.isError()) - { - return error; - } - - error = invalidateSwizzles(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(markAttachmentsDirty(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidate(size_t count, const GLenum *attachments) +gl::Error Framebuffer11::invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) { - return invalidateBase(count, attachments, false); + return invalidateBase(context, count, attachments, false); } -gl::Error Framebuffer11::discard(size_t count, const GLenum *attachments) +gl::Error Framebuffer11::discard(const gl::Context *context, + size_t count, + const GLenum *attachments) { - return invalidateBase(count, attachments, true); + return invalidateBase(context, count, attachments, true); } -gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, bool useEXTBehavior) const +gl::Error Framebuffer11::invalidateBase(const gl::Context *context, + size_t count, + const GLenum *attachments, + bool useEXTBehavior) const { -#if defined(ANGLE_ENABLE_D3D11_1) ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); if (!deviceContext1) { // DiscardView() is only supported on ID3D11DeviceContext1 - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool foundDepth = false; @@ -175,37 +197,14 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) || (attachments[i] == GL_COLOR)); - RenderTarget11 *renderTarget = nullptr; - ID3D11View *colorView = nullptr; - gl::Error error(GL_NO_ERROR); - size_t colorAttachmentID = 0; - - if (attachments[i] == GL_COLOR) - { - colorAttachmentID = 0; - } - else + size_t colorIndex = + (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0)); + const gl::FramebufferAttachment *colorAttachment = + mState.getColorAttachment(colorIndex); + if (colorAttachment) { - colorAttachmentID = attachments[i] - GL_COLOR_ATTACHMENT0; + ANGLE_TRY(invalidateAttachment(context, colorAttachment)); } - - 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); - } - } - break; } } @@ -222,7 +221,7 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, discardDepth = foundDepth; // Don't bother discarding the stencil buffer if the depth buffer will already do it - discardStencil = foundStencil && (!discardDepth || mData.getDepthAttachment() == nullptr); + discardStencil = foundStencil && (!discardDepth || mState.getDepthAttachment() == nullptr); } else { @@ -230,94 +229,86 @@ gl::Error Framebuffer11::invalidateBase(size_t count, const GLenum *attachments, // 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)); + discardDepth = (foundDepth && foundStencil) || + (foundDepth && (mState.getStencilAttachment() == nullptr)); + discardStencil = (foundStencil && (mState.getDepthAttachment() == nullptr)); } - if (discardDepth && mData.getDepthAttachment()) + if (discardDepth && mState.getDepthAttachment()) { - RenderTarget11 *renderTarget = nullptr; - ID3D11View *depthView = nullptr; - gl::Error error(GL_NO_ERROR); - - error = mData.getDepthAttachment()->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - depthView = renderTarget->getDepthStencilView(); - - if (depthView != nullptr) - { - deviceContext1->DiscardView(depthView); - } + ANGLE_TRY(invalidateAttachment(context, mState.getDepthAttachment())); } - if (discardStencil && mData.getStencilAttachment()) + if (discardStencil && mState.getStencilAttachment()) { - RenderTarget11 *renderTarget = nullptr; - ID3D11View *stencilView = nullptr; - gl::Error error(GL_NO_ERROR); - - error = mData.getStencilAttachment()->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - stencilView = renderTarget->getDepthStencilView(); - - if (stencilView != nullptr) - { - deviceContext1->DiscardView(stencilView); - } + ANGLE_TRY(invalidateAttachment(context, mState.getStencilAttachment())); } -#endif // ANGLE_ENABLE_D3D11_1 - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer11::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +gl::Error Framebuffer11::invalidateSub(const gl::Context *context, + 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); + return gl::NoError(); } -gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area, +gl::Error Framebuffer11::invalidateAttachment(const gl::Context *context, + const gl::FramebufferAttachment *attachment) const +{ + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + ASSERT(deviceContext1); + ASSERT(attachment && attachment->isAttached()); + + RenderTarget11 *renderTarget = nullptr; + ANGLE_TRY(attachment->getRenderTarget(context, &renderTarget)); + const auto &rtv = renderTarget->getRenderTargetView(); + + if (rtv.valid()) + { + deviceContext1->DiscardView(rtv.get()); + } + + return gl::NoError(); +} + +gl::Error Framebuffer11::readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const + uint8_t *pixels) { - const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + const gl::FramebufferAttachment *readAttachment = mState.getReadAttachment(); ASSERT(readAttachment); - gl::Buffer *packBuffer = pack.pixelBuffer.get(); + gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack); 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)); + packBuffer, reinterpret_cast(pixels)); - return packBufferStorage->packPixels(*readAttachment, packParams); + return packBufferStorage->packPixels(context, *readAttachment, packParams); } - return mRenderer->readFromAttachment(*readAttachment, area, format, type, + return mRenderer->readFromAttachment(context, *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) +gl::Error Framebuffer11::blitImpl(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + const gl::Rectangle *scissor, + bool blitRenderTarget, + bool blitDepth, + bool blitStencil, + GLenum filter, + const gl::Framebuffer *sourceFramebuffer) { if (blitRenderTarget) { @@ -325,15 +316,11 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang ASSERT(readBuffer); RenderTargetD3D *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget)); ASSERT(readRenderTarget); - const auto &colorAttachments = mData.getColorAttachments(); - const auto &drawBufferStates = mData.getDrawBufferStates(); + const auto &colorAttachments = mState.getColorAttachments(); + const auto &drawBufferStates = mState.getDrawBufferStates(); for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) { @@ -343,11 +330,7 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang drawBufferStates[colorAttachment] != GL_NONE) { RenderTargetD3D *drawRenderTarget = nullptr; - error = drawBuffer.getRenderTarget(&drawRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(drawBuffer.getRenderTarget(context, &drawRenderTarget)); ASSERT(drawRenderTarget); const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer); @@ -368,13 +351,9 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang actualDestArea.height = -destArea.height; } - error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea, - readRenderTarget, drawRenderTarget, filter, - scissor, blitRenderTarget, false, false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->blitRenderbufferRect( + context, actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget, + filter, scissor, blitRenderTarget, false, false)); } } } @@ -385,46 +364,144 @@ gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectang ASSERT(readBuffer); RenderTargetD3D *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(readBuffer->getRenderTarget(context, &readRenderTarget)); ASSERT(readRenderTarget); - const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); ASSERT(drawBuffer); RenderTargetD3D *drawRenderTarget = nullptr; - error = drawBuffer->getRenderTarget(&drawRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(drawBuffer->getRenderTarget(context, &drawRenderTarget)); ASSERT(drawRenderTarget); - error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor, - false, blitDepth, blitStencil); - if (error.isError()) + ANGLE_TRY(mRenderer->blitRenderbufferRect(context, sourceArea, destArea, readRenderTarget, + drawRenderTarget, filter, scissor, false, + blitDepth, blitStencil)); + } + + ANGLE_TRY(markAttachmentsDirty(context)); + return gl::NoError(); +} + +GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget11 *renderTarget11 = GetAs(renderTarget); + return renderTarget11->getFormatSet().format().fboImplementationInternalFormat; +} + +void Framebuffer11::updateColorRenderTarget(const gl::Context *context, size_t colorIndex) +{ + UpdateCachedRenderTarget(context, mState.getColorAttachment(colorIndex), + mCachedColorRenderTargets[colorIndex], + &mColorRenderTargetsDirty[colorIndex]); +} + +void Framebuffer11::updateDepthStencilRenderTarget(const gl::Context *context) +{ + UpdateCachedRenderTarget(context, mState.getDepthOrStencilAttachment(), + mCachedDepthStencilRenderTarget, &mDepthStencilRenderTargetDirty); +} + +void Framebuffer11::syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) +{ + const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits; + mInternalDirtyBits.reset(); + + for (auto dirtyBit : mergedDirtyBits) + { + switch (dirtyBit) { - return error; + case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: + case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: + updateDepthStencilRenderTarget(context); + break; + case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: + case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: + break; + case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES: + case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + default: + { + ASSERT(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0 && + dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); + size_t colorIndex = + static_cast(dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); + updateColorRenderTarget(context, colorIndex); + break; + } } } - gl::Error error = invalidateSwizzles(); - if (error.isError()) + // We should not have dirtied any additional state during our sync. + ASSERT(!mInternalDirtyBits.any()); + + FramebufferD3D::syncState(context, dirtyBits); + + // Call this last to allow the state manager to take advantage of the cached render targets. + mRenderer->getStateManager()->invalidateRenderTarget(); + + // Call this to syncViewport for framebuffer default parameters. + if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0) + { + mRenderer->getStateManager()->invalidateViewport(context); + } +} + +void Framebuffer11::signal(size_t channelID, const gl::Context *context) +{ + if (channelID == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) + { + // Stencil is redundant in this case. + mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT); + mCachedDepthStencilRenderTarget = nullptr; + } + else { - return error; + mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + channelID); + mCachedColorRenderTargets[channelID] = nullptr; } - return gl::Error(GL_NO_ERROR); + // Notify the context we need to re-validate the RenderTarget. + // TODO(jmadill): Check that we're the active draw framebuffer. + mRenderer->getStateManager()->invalidateRenderTarget(); } -GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const { - RenderTarget11 *renderTarget11 = GetAs(renderTarget); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget11->getDXGIFormat()); - return dxgiFormatInfo.internalFormat; + const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment(); + ASSERT(attachment); + GLsizei sampleCount = attachment->getSamples(); + + d3d11_gl::GetSamplePosition(sampleCount, index, xy); + return gl::NoError(); +} + +bool Framebuffer11::hasAnyInternalDirtyBit() const +{ + return mInternalDirtyBits.any(); +} + +void Framebuffer11::syncInternalState(const gl::Context *context) +{ + syncState(context, gl::Framebuffer::DirtyBits()); } +RenderTarget11 *Framebuffer11::getFirstRenderTarget() const +{ + ASSERT(mInternalDirtyBits.none()); + for (auto *renderTarget : mCachedColorRenderTargets) + { + if (renderTarget) + { + return renderTarget; + } + } + + return mCachedDepthStencilRenderTarget; } + +} // namespace rx 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 c8a33ec7e5..afdda299b9 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h @@ -10,43 +10,93 @@ #define LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ #include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/signal_utils.h" namespace rx { class Renderer11; -class Framebuffer11 : public FramebufferD3D +class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver { public: - Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer); - virtual ~Framebuffer11(); + Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer); + ~Framebuffer11() 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 discard(const gl::Context *context, size_t count, const GLenum *attachments) override; + gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) override; // Invalidate the cached swizzles of all bound texture attachments. - gl::Error invalidateSwizzles() const; + gl::Error markAttachmentsDirty(const gl::Context *context) const; + + void syncState(const gl::Context *context, + const gl::Framebuffer::DirtyBits &dirtyBits) override; + + const RenderTargetArray &getCachedColorRenderTargets() const + { + return mCachedColorRenderTargets; + } + const RenderTarget11 *getCachedDepthStencilRenderTarget() const + { + return mCachedDepthStencilRenderTarget; + } + + RenderTarget11 *getFirstRenderTarget() const; + + bool hasAnyInternalDirtyBit() const; + void syncInternalState(const gl::Context *context); + + void signal(size_t channelID, const gl::Context *context) override; + + gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; private: - gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override; + gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) override; - gl::Error readPixelsImpl(const gl::Rectangle &area, + gl::Error readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const override; + uint8_t *pixels) 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 blitImpl(const gl::Context *context, + 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; + gl::Error invalidateBase(const gl::Context *context, + size_t count, + const GLenum *attachments, + bool useEXTBehavior) const; + gl::Error invalidateAttachment(const gl::Context *context, + const gl::FramebufferAttachment *attachment) const; GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + void updateColorRenderTarget(const gl::Context *context, size_t colorIndex); + void updateDepthStencilRenderTarget(const gl::Context *context); + Renderer11 *const mRenderer; + RenderTargetArray mCachedColorRenderTargets; + RenderTarget11 *mCachedDepthStencilRenderTarget; + + std::vector mColorRenderTargetsDirty; + OnRenderTargetDirtyBinding mDepthStencilRenderTargetDirty; + + gl::Framebuffer::DirtyBits mInternalDirtyBits; }; } 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 c52092d81e..bd921f1935 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -26,10 +26,10 @@ namespace rx Image11::Image11(Renderer11 *renderer) : mRenderer(renderer), mDXGIFormat(DXGI_FORMAT_UNKNOWN), - mStagingTexture(NULL), + mStagingTexture(), mStagingSubresource(0), mRecoverFromStorage(false), - mAssociatedStorage(NULL), + mAssociatedStorage(nullptr), mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), mRecoveredFromStorageCount(0) { @@ -41,55 +41,106 @@ Image11::~Image11() releaseStagingTexture(); } -gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) +// static +gl::Error Image11::GenerateMipmap(const gl::Context *context, + Image11 *dest, + Image11 *src, + const Renderer11DeviceCaps &rendererCaps) { ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(src->getDXGIFormat()); - ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL); - D3D11_MAPPED_SUBRESOURCE destMapped; - gl::Error error = dest->map(D3D11_MAP_WRITE, &destMapped); + ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped)); + + D3D11_MAPPED_SUBRESOURCE srcMapped; + gl::Error error = src->map(context, D3D11_MAP_READ, &srcMapped); if (error.isError()) { + dest->unmap(); return error; } + const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); + uint8_t *destData = reinterpret_cast(destMapped.pData); + + auto mipGenerationFunction = + d3d11::Format::Get(src->getInternalFormat(), rendererCaps).format().mipGenerationFunction; + mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, + srcMapped.RowPitch, srcMapped.DepthPitch, destData, destMapped.RowPitch, + destMapped.DepthPitch); + + dest->unmap(); + src->unmap(); + + dest->markDirty(); + + return gl::NoError(); +} + +// static +gl::Error Image11::CopyImage(const gl::Context *context, + Image11 *dest, + Image11 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const Renderer11DeviceCaps &rendererCaps) +{ + D3D11_MAPPED_SUBRESOURCE destMapped; + ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped)); + D3D11_MAPPED_SUBRESOURCE srcMapped; - error = src->map(D3D11_MAP_READ, &srcMapped); + gl::Error error = source->map(context, D3D11_MAP_READ, &srcMapped); if (error.isError()) { dest->unmap(); return error; } - const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); - uint8_t *destData = reinterpret_cast(destMapped.pData); + const auto &sourceFormat = + d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format(); + GLuint sourcePixelBytes = + gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes; + + GLenum destUnsizedFormat = gl::GetUnsizedFormat(dest->getInternalFormat()); + const auto &destFormat = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format(); + const auto &destFormatInfo = + gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat); + GLuint destPixelBytes = destFormatInfo.pixelBytes; - dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), - sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, - destData, destMapped.RowPitch, destMapped.DepthPitch); + const uint8_t *sourceData = reinterpret_cast(srcMapped.pData) + + sourceRect.x * sourcePixelBytes + sourceRect.y * srcMapped.RowPitch; + uint8_t *destData = reinterpret_cast(destMapped.pData) + + destOffset.x * destPixelBytes + destOffset.y * destMapped.RowPitch; + + CopyImageCHROMIUM(sourceData, srcMapped.RowPitch, sourcePixelBytes, + sourceFormat.colorReadFunction, destData, destMapped.RowPitch, destPixelBytes, + destFormat.colorWriteFunction, destUnsizedFormat, + destFormatInfo.componentType, sourceRect.width, sourceRect.height, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); dest->unmap(); - src->unmap(); + source->unmap(); dest->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool Image11::isDirty() const { - // If mDirty is true - // 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) + // If mDirty is true 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) AND robust resource initialization is not enabled then isDirty should + // still return false. + if (mDirty && !mStagingTexture.valid() && !mRecoverFromStorage) { const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps(); - const d3d11::TextureFormat formatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, deviceCaps); + const auto &formatInfo = d3d11::Format::Get(mInternalFormat, deviceCaps); if (formatInfo.dataInitializerFunction == nullptr) { return false; @@ -99,92 +150,69 @@ bool Image11::isDirty() const return mDirty; } -gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error Image11::copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) { 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. - // We allow the Image11 to copy its data to/from TextureStorage once. - // This accounts for an app making a late call to glGenerateMipmap. + // 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. We allow the Image11 to copy its data to/from TextureStorage once. This + // accounts for an app making a late call to glGenerateMipmap. bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); if (attemptToReleaseStagingTexture) { - // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. - gl::Error error = storage11->releaseAssociatedImage(index, this); - if (error.isError()) - { - return error; - } + // If another image is relying on this Storage for its data, then we must let it recover its + // data before we overwrite it. + ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this)); } - ID3D11Resource *stagingTexture = NULL; + const TextureHelper11 *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; - gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); - if (error.isError()) - { - return error; - } - - error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); + ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex, + index, region)); // Once the image data has been copied into the Storage, we can release it locally. if (attemptToReleaseStagingTexture) { storage11->associateImage(this, index); releaseStagingTexture(); - mRecoverFromStorage = true; - mAssociatedStorage = storage11; + mRecoverFromStorage = true; + mAssociatedStorage = storage11; mAssociatedImageIndex = index; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const +void Image11::verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const { - return (mAssociatedStorage == textureStorage); + ASSERT(mAssociatedStorage == textureStorage); } -gl::Error Image11::recoverFromAssociatedStorage() +gl::Error Image11::recoverFromAssociatedStorage(const gl::Context *context) { if (mRecoverFromStorage) { - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } - - bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); + ANGLE_TRY(createStagingTexture()); - // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. - // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. - ASSERT(textureStorageCorrect); + mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this); - if (textureStorageCorrect) - { - // CopySubResource from the Storage to the Staging texture - gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); - error = mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); - if (error.isError()) - { - return error; - } - - mRecoveredFromStorageCount += 1; - } + // CopySubResource from the Storage to the Staging texture + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + ANGLE_TRY(mAssociatedStorage->copySubresourceLevel( + context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region)); + mRecoveredFromStorageCount += 1; // Reset all the recovery parameters, even if the texture storage association is broken. disassociateStorage(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::disassociateStorage() @@ -194,17 +222,18 @@ void Image11::disassociateStorage() // Make the texturestorage release the Image11 too mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); - mRecoverFromStorage = false; - mAssociatedStorage = NULL; + mRecoverFromStorage = false; + mAssociatedStorage = nullptr; mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); } } -bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +bool Image11::redefine(GLenum target, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { - if (mWidth != size.width || - mHeight != size.height || - mInternalFormat != internalformat || + if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat || forceRelease) { // End the association with the TextureStorage, since that data will be out of date. @@ -212,19 +241,20 @@ bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents & disassociateStorage(); mRecoveredFromStorageCount = 0; - mWidth = size.width; - mHeight = size.height; - mDepth = size.depth; + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; mInternalFormat = internalformat; - mTarget = target; + mTarget = target; // compute the d3d format that will be used - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &formatInfo = + d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps()); mDXGIFormat = formatInfo.texFormat; mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); releaseStagingTexture(); - mDirty = (formatInfo.dataInitializerFunction != NULL); + mDirty = (formatInfo.dataInitializerFunction != nullptr); return true; } @@ -241,119 +271,125 @@ DXGI_FORMAT Image11::getDXGIFormat() const return mDXGIFormat; } -// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as +// format/type at input // into the target pixel rectangle. -gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +gl::Error Image11::loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) { - 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, 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, mRenderer->getRenderer11DeviceCaps()); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type).loadFunction; + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), + inputRowPitch); + GLuint inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, unpack.imageHeight, inputRowPitch), + inputDepthPitch); + GLuint inputSkipBytes = 0; + ANGLE_TRY_RESULT( + formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages), + inputSkipBytes); + + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + + const d3d11::Format &d3dFormatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); - uint8_t *offsetMappedData = (reinterpret_cast(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); + 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) + inputSkipBytes, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input) +gl::Error Image11::loadCompressedData(const gl::Context *context, + 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0), inputRowPitch); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, 0, inputRowPitch), inputDepthPitch); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); - GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; - GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; - GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; + GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; ASSERT(area.x % outputBlockWidth == 0); ASSERT(area.y % outputBlockHeight == 0); - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE).loadFunction; + const d3d11::Format &d3dFormatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + LoadImageFunction loadFunction = + d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); - uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((area.y / outputBlockHeight) * mappedImage.RowPitch + - (area.x / outputBlockWidth) * outputPixelSize + - area.z * mappedImage.DepthPitch); + uint8_t *offsetMappedData = + reinterpret_cast(mappedImage.pData) + + ((area.y / outputBlockHeight) * mappedImage.RowPitch + + (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch); - loadFunction(area.width, area.height, area.depth, - reinterpret_cast(input), inputRowPitch, inputDepthPitch, - offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + loadFunction(area.width, area.height, area.depth, reinterpret_cast(input), + inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, + mappedImage.DepthPitch); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) +gl::Error Image11::copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) { TextureStorage11 *storage11 = GetAs(source); - ID3D11Resource *resource = nullptr; - gl::Error error = storage11->getResource(&resource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *textureHelper = nullptr; + ANGLE_TRY(storage11->getResource(context, &textureHelper)); - UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(resource); + UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex); gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth); - return copyWithoutConversion(gl::Offset(), sourceBox, textureHelper, subresourceIndex); + return copyWithoutConversion(gl::Offset(), sourceBox, *textureHelper, subresourceIndex); } -gl::Error Image11::copyFromFramebuffer(const gl::Offset &destOffset, +gl::Error Image11::copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *sourceFBO) { const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorbuffer(); ASSERT(srcAttachment); - const auto &d3d11Format = d3d11::GetTextureFormatInfo(srcAttachment->getInternalFormat(), - mRenderer->getRenderer11DeviceCaps()); + GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat; + const auto &d3d11Format = + d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps()); - if (d3d11Format.texFormat == mDXGIFormat) + if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat) { - RenderTargetD3D *renderTarget = nullptr; - gl::Error error = srcAttachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - RenderTarget11 *rt11 = GetAs(renderTarget); - ASSERT(rt11->getTexture()); + RenderTarget11 *rt11 = nullptr; + ANGLE_TRY(srcAttachment->getRenderTarget(context, &rt11)); + ASSERT(rt11->getTexture().get()); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture()); + TextureHelper11 textureHelper = rt11->getTexture(); unsigned int sourceSubResource = rt11->getSubresourceIndex(); gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1); @@ -363,25 +399,47 @@ gl::Error Image11::copyFromFramebuffer(const gl::Offset &destOffset, // 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; - } + ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); // determine the offset coordinate into the destination buffer - const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x; uint8_t *dataOffset = static_cast(mappedImage.pData) + mappedImage.RowPitch * destOffset.y + rowOffset + destOffset.z * mappedImage.DepthPitch; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + const auto &destD3D11Format = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); + + auto loadFunction = destD3D11Format.getLoadFunctions()(destFormatInfo.type); + gl::Error error = gl::NoError(); + if (loadFunction.requiresConversion) + { + size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height; + angle::MemoryBuffer *memoryBuffer = nullptr; + error = mRenderer->getScratchMemoryBuffer(bufferSize, &memoryBuffer); + + if (!error.isError()) + { + GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width; - error = mRenderer->readFromAttachment(*srcAttachment, sourceArea, formatInfo.format, - formatInfo.type, mappedImage.RowPitch, - gl::PixelPackState(), dataOffset); + error = mRenderer->readFromAttachment( + context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type, + memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data()); + + loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(), + memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch, + mappedImage.DepthPitch); + } + } + else + { + error = mRenderer->readFromAttachment( + context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type, + mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + } unmap(); mDirty = true; @@ -395,26 +453,23 @@ gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, UINT sourceSubResource) { // No conversion needed-- use copyback fastpath - ID3D11Resource *stagingTexture = nullptr; + const TextureHelper11 *stagingTexture = nullptr; unsigned int stagingSubresourceIndex = 0; - gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getStagingTexture(&stagingTexture, &stagingSubresourceIndex)); - ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - UINT subresourceAfterResolve = sourceSubResource; - - ID3D11Resource *srcTex = nullptr; const gl::Extents &extents = textureHelper.getExtents(); - bool needResolve = - (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1); + 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; - if (needResolve) + if (textureHelper.is2D() && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = extents.width; @@ -429,80 +484,57 @@ gl::Error Image11::copyWithoutConversion(const gl::Offset &destOffset, 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; + d3d11::Texture2D resolveTex; + ANGLE_TRY(mRenderer->allocateResource(resolveDesc, &resolveTex)); - deviceContext->ResolveSubresource(srcTex, 0, textureHelper.getTexture2D(), + deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(), sourceSubResource, textureHelper.getFormat()); - subresourceAfterResolve = 0; + + deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, + destOffset.x, destOffset.y, destOffset.z, + resolveTex.get(), 0, &srcBox); } else { - srcTex = textureHelper.getResource(); - } - - 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); + deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex, + destOffset.x, destOffset.y, destOffset.z, + textureHelper.get(), sourceSubResource, &srcBox); } mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) +gl::Error Image11::getStagingTexture(const TextureHelper11 **outStagingTexture, + unsigned int *outSubresourceIndex) { - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(createStagingTexture()); - *outStagingTexture = mStagingTexture; + *outStagingTexture = &mStagingTexture; *outSubresourceIndex = mStagingSubresource; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::releaseStagingTexture() { - SafeRelease(mStagingTexture); + mStagingTexture.reset(); } gl::Error Image11::createStagingTexture() { - if (mStagingTexture) + if (mStagingTexture.valid()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + const auto &formatInfo = + d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - int lodOffset = 1; - GLsizei width = mWidth; + int lodOffset = 1; + GLsizei width = mWidth; GLsizei height = mHeight; // adjust size if needed for compressed textures @@ -510,80 +542,69 @@ gl::Error Image11::createStagingTexture() if (mTarget == GL_TEXTURE_3D) { - ID3D11Texture3D *newTexture = NULL; - D3D11_TEXTURE3D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.Depth = mDepth; - desc.MipLevels = lodOffset + 1; - desc.Format = dxgiFormat; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; + desc.MiscFlags = 0; - if (d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { std::vector initialData; std::vector> textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, mDepth, - lodOffset + 1, &initialData, &textureData); + d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), + width, height, mDepth, lodOffset + 1, &initialData, + &textureData); - result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + ANGLE_TRY( + mRenderer->allocateTexture(desc, formatInfo, initialData.data(), &mStagingTexture)); } else { - result = device->CreateTexture3D(&desc, NULL, &newTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, formatInfo, &mStagingTexture)); } - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); - } - - mStagingTexture = newTexture; + mStagingTexture.setDebugName("Image11::StagingTexture3D"); mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); } - else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || + mTarget == GL_TEXTURE_CUBE_MAP) { - ID3D11Texture2D *newTexture = NULL; - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = lodOffset + 1; - desc.ArraySize = 1; - desc.Format = dxgiFormat; - desc.SampleDesc.Count = 1; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; - if (d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()).dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { std::vector initialData; std::vector> textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height, 1, - lodOffset + 1, &initialData, &textureData); + d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getRenderer11DeviceCaps(), + width, height, 1, lodOffset + 1, &initialData, + &textureData); - result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + ANGLE_TRY( + mRenderer->allocateTexture(desc, formatInfo, initialData.data(), &mStagingTexture)); } else { - result = device->CreateTexture2D(&desc, NULL, &newTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, formatInfo, &mStagingTexture)); } - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); - } - - mStagingTexture = newTexture; + mStagingTexture.setDebugName("Image11::StagingTexture2D"); mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); } else @@ -592,30 +613,22 @@ gl::Error Image11::createStagingTexture() } mDirty = false; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +gl::Error Image11::map(const gl::Context *context, D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. - gl::Error error = recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(recoverFromAssociatedStorage(context)); - ID3D11Resource *stagingTexture = NULL; - unsigned int subresourceIndex = 0; - error = getStagingTexture(&stagingTexture, &subresourceIndex); - if (error.isError()) - { - return error; - } + const TextureHelper11 *stagingTexture = nullptr; + unsigned int subresourceIndex = 0; + ANGLE_TRY(getStagingTexture(&stagingTexture, &subresourceIndex)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - ASSERT(mStagingTexture); - HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); + ASSERT(stagingTexture && stagingTexture->valid()); + HRESULT result = deviceContext->Map(stagingTexture->get(), subresourceIndex, mapType, 0, map); if (FAILED(result)) { @@ -624,20 +637,20 @@ gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { mRenderer->notifyDeviceLost(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to map staging texture, " << gl::FmtHR(result); } mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image11::unmap() { - if (mStagingTexture) + if (mStagingTexture.valid()) { ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - deviceContext->Unmap(mStagingTexture, mStagingSubresource); + deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource); } } 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 a5fcec84f8..584d231b37 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h @@ -10,10 +10,10 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ -#include "libANGLE/renderer/d3d/ImageD3D.h" -#include "libANGLE/ImageIndex.h" - #include "common/debug.h" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -25,37 +25,63 @@ namespace rx class Renderer11; class TextureHelper11; class TextureStorage11; +struct Renderer11DeviceCaps; class Image11 : public ImageD3D { public: Image11(Renderer11 *renderer); - virtual ~Image11(); - - static gl::Error generateMipmap(Image11 *dest, Image11 *src); - - virtual bool isDirty() const; - - virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + ~Image11() override; + + static gl::Error GenerateMipmap(const gl::Context *context, + Image11 *dest, + Image11 *src, + const Renderer11DeviceCaps &rendererCaps); + static gl::Error CopyImage(const gl::Context *context, + Image11 *dest, + Image11 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const Renderer11DeviceCaps &rendererCaps); + + bool isDirty() const override; + + gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) override; bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; DXGI_FORMAT getDXGIFormat() const; - 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); - - gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override; - gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) override; + gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) override; + + gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) override; + gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; - gl::Error recoverFromAssociatedStorage(); - bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; + gl::Error recoverFromAssociatedStorage(const gl::Context *context); + void verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const; void disassociateStorage(); protected: - gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + gl::Error map(const gl::Context *context, D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); void unmap(); private: @@ -64,14 +90,15 @@ class Image11 : public ImageD3D const TextureHelper11 &textureHelper, UINT sourceSubResource); - gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); + gl::Error getStagingTexture(const TextureHelper11 **outStagingTexture, + unsigned int *outSubresourceIndex); gl::Error createStagingTexture(); void releaseStagingTexture(); Renderer11 *mRenderer; DXGI_FORMAT mDXGIFormat; - ID3D11Resource *mStagingTexture; + TextureHelper11 mStagingTexture; unsigned int mStagingSubresource; bool mRecoverFromStorage; 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 a5e78a245d..a79fb71f71 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -14,28 +14,23 @@ namespace rx { -IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) + : mRenderer(renderer), mBuffer(), mBufferSize(0), mIndexType(GL_NONE), mDynamicUsage(false) { - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; } IndexBuffer11::~IndexBuffer11() { - SafeRelease(mBuffer); } gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { - SafeRelease(mBuffer); + mBuffer.reset(); updateSerial(); if (bufferSize > 0) { - ID3D11Device* dxDevice = mRenderer->getDevice(); - D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = bufferSize; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; @@ -44,19 +39,15 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; - HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); - } + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &mBuffer)); if (dynamic) { - d3d11::SetDebugName(mBuffer, "IndexBuffer11 (dynamic)"); + mBuffer.setDebugName("IndexBuffer11 (dynamic)"); } else { - d3d11::SetDebugName(mBuffer, "IndexBuffer11 (static)"); + mBuffer.setDebugName("IndexBuffer11 (static)"); } } @@ -64,45 +55,46 @@ gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, b mIndexType = indexType; mDynamicUsage = dynamic; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } // Check for integer overflows and out-out-bounds map requests if (offset + size < offset || offset + size > mBufferSize) { - return gl::Error(GL_OUT_OF_MEMORY, "Index buffer map range is not inside the buffer."); + return gl::OutOfMemory() << "Index buffer map range is not inside the buffer."; } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + HRESULT result = + dxContext->Map(mBuffer.get(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to map internal index buffer, " << gl::FmtHR(result); } *outMappedMemory = reinterpret_cast(mappedResource.pData) + offset; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer11::unmapBuffer() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - dxContext->Unmap(mBuffer, 0); - return gl::Error(GL_NO_ERROR); + dxContext->Unmap(mBuffer.get(), 0); + return gl::NoError(); } GLenum IndexBuffer11::getIndexType() const @@ -123,29 +115,29 @@ gl::Error IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } gl::Error IndexBuffer11::discard() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + HRESULT result = dxContext->Map(mBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to map internal index buffer, " << gl::FmtHR(result); } - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } DXGI_FORMAT IndexBuffer11::getIndexFormat() const @@ -159,9 +151,9 @@ DXGI_FORMAT IndexBuffer11::getIndexFormat() const } } -ID3D11Buffer *IndexBuffer11::getBuffer() const +const d3d11::Buffer &IndexBuffer11::getBuffer() const { return mBuffer; } -} +} // namespace rx 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 e730377e00..7b5d744c02 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h @@ -10,6 +10,7 @@ #define LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ #include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -19,31 +20,31 @@ class IndexBuffer11 : public IndexBuffer { public: explicit IndexBuffer11(Renderer11 *const renderer); - virtual ~IndexBuffer11(); + ~IndexBuffer11() override; - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) override; - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); + gl::Error mapBuffer(unsigned int offset, unsigned int size, void **outMappedMemory) override; + gl::Error unmapBuffer() override; - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + GLenum getIndexType() const override; + unsigned int getBufferSize() const override; + gl::Error setSize(unsigned int bufferSize, GLenum indexType) override; - virtual gl::Error discard(); + gl::Error discard() override; DXGI_FORMAT getIndexFormat() const; - ID3D11Buffer *getBuffer() const; + const d3d11::Buffer &getBuffer() const; private: Renderer11 *const mRenderer; - ID3D11Buffer *mBuffer; + d3d11::Buffer mBuffer; unsigned int mBufferSize; GLenum mIndexType; bool mDynamicUsage; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ 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 3a6d797ea6..a238f97b08 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -9,17 +9,22 @@ #include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "common/bitset_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" +#include "libANGLE/VertexArray.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/Context11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "third_party/murmurhash/MurmurHash3.h" namespace rx { @@ -32,24 +37,7 @@ size_t GetReservedBufferCount(bool usesPointSpriteEmulation) 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]; - - if (translatedAttribute->active) - { - inputLayout[attributeIndex] = gl::GetVertexFormatType( - *translatedAttribute->attribute, translatedAttribute->currentValueType); - } - } - return inputLayout; -} - -GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, int index) +GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, size_t index) { // Count matrices differently for (const sh::Attribute &attrib : shaderAttributes) @@ -61,8 +49,9 @@ GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, GLenum transposedType = gl::TransposeMatrixType(attrib.type); int rows = gl::VariableRowCount(transposedType); + int intIndex = static_cast(index); - if (index >= attrib.location && index < attrib.location + rows) + if (intIndex >= attrib.location && intIndex < attrib.location + rows) { return transposedType; } @@ -72,8 +61,6 @@ GLenum GetGLSLAttributeType(const std::vector &shaderAttributes, return GL_NONE; } -const unsigned int kDefaultCacheSize = 1024; - struct PackedAttribute { uint8_t attribType; @@ -82,26 +69,18 @@ struct PackedAttribute uint8_t divisor; }; -Optional FindFirstNonInstanced(const SortedAttribArray &sortedAttributes, size_t maxIndex) -{ - for (size_t index = 0; index < maxIndex; ++index) - { - if (sortedAttributes[index]->divisor == 0) - { - return Optional(index); - } - } +} // anonymous namespace - return Optional::Invalid(); +PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({}) +{ } -} // anonymous namespace +PackedAttributeLayout::PackedAttributeLayout(const PackedAttributeLayout &other) = default; -void InputLayoutCache::PackedAttributeLayout::addAttributeData( - GLenum glType, - UINT semanticIndex, - gl::VertexFormatType vertexFormatType, - unsigned int divisor) +void PackedAttributeLayout::addAttributeData(GLenum glType, + UINT semanticIndex, + gl::VertexFormatType vertexFormatType, + unsigned int divisor) { gl::AttributeType attribType = gl::GetAttributeType(glType); @@ -121,139 +100,58 @@ void InputLayoutCache::PackedAttributeLayout::addAttributeData( attributeData[numAttributes++] = gl::bitCast(packedAttrib); } -bool InputLayoutCache::PackedAttributeLayout::operator<(const PackedAttributeLayout &other) const +bool 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; + return (numAttributes == other.numAttributes) && (flags == other.flags) && + (attributeData == other.attributeData); } -InputLayoutCache::InputLayoutCache() : mUnsortedAttributesCount(0), mCacheSize(kDefaultCacheSize) +InputLayoutCache::InputLayoutCache() + : mLayoutCache(kDefaultCacheSize * 2), mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer() { - mCounter = 0; - mDevice = NULL; - mDeviceContext = NULL; - mCurrentIL = NULL; - - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mCurrentBuffers[i] = NULL; - mCurrentVertexStrides[i] = static_cast(-1); - mCurrentVertexOffsets[i] = static_cast(-1); - } - mPointSpriteVertexBuffer = NULL; - mPointSpriteIndexBuffer = NULL; } InputLayoutCache::~InputLayoutCache() { - clear(); -} - -void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context) -{ - clear(); - mDevice = device; - mDeviceContext = context; - mFeatureLevel = device->GetFeatureLevel(); } void InputLayoutCache::clear() { - for (auto &layout : mLayoutMap) - { - SafeRelease(layout.second); - } - mLayoutMap.clear(); - SafeRelease(mPointSpriteVertexBuffer); - SafeRelease(mPointSpriteIndexBuffer); - markDirty(); -} - -void InputLayoutCache::markDirty() -{ - mCurrentIL = NULL; - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mCurrentBuffers[i] = NULL; - mCurrentVertexStrides[i] = static_cast(-1); - mCurrentVertexOffsets[i] = static_cast(-1); - } - mUnsortedAttributesCount = 0; + mLayoutCache.Clear(); + mPointSpriteVertexBuffer.reset(); + mPointSpriteIndexBuffer.reset(); } gl::Error InputLayoutCache::applyVertexBuffers( - const std::vector &unsortedAttributes, + const gl::Context *context, + const std::vector ¤tAttributes, GLenum mode, - gl::Program *program, - TranslatedIndexData *indexInfo, - GLsizei numIndicesPerInstance) + GLint start, + bool isIndexedRendering) { - ASSERT(mDevice && mDeviceContext); - + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + const gl::State &state = context->getGLState(); + auto *stateManager = renderer->getStateManager(); + gl::Program *program = state.getProgram(); ProgramD3D *programD3D = GetImplAs(program); bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); - SortedIndexArray sortedSemanticIndices; - mSortedAttributes.fill(nullptr); - mUnsortedAttributesCount = unsortedAttributes.size(); - - programD3D->sortAttributesByLayout(unsortedAttributes, sortedSemanticIndices.data(), - mSortedAttributes.data()); - - // 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 (mSortedAttributes[0]->divisor > 0) - { - Optional firstNonInstancedIndex = - FindFirstNonInstanced(mSortedAttributes, unsortedAttributes.size()); - if (firstNonInstancedIndex.valid()) - { - size_t index = firstNonInstancedIndex.value(); - std::swap(mSortedAttributes[0], mSortedAttributes[index]); - std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]); - } - } - } - - gl::Error error = updateInputLayout(program, mode, mSortedAttributes, sortedSemanticIndices, - unsortedAttributes.size(), numIndicesPerInstance); - if (error.isError()) - { - return error; - } - - bool dirtyBuffers = false; - size_t minDiff = gl::MAX_VERTEX_ATTRIBS; - size_t maxDiff = 0; - // Note that if we use instance emulation, we reserve the first buffer slot. size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites); for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers); ++attribIndex) { - ID3D11Buffer *buffer = NULL; - UINT vertexStride = 0; - UINT vertexOffset = 0; + ID3D11Buffer *buffer = nullptr; + UINT vertexStride = 0; + UINT vertexOffset = 0; - const auto &attrib = *mSortedAttributes[attribIndex]; - - if (attribIndex < unsortedAttributes.size() && attrib.active) + if (attribIndex < currentAttributes.size()) { - VertexBuffer11 *vertexBuffer = GetAs(attrib.vertexBuffer); - Buffer11 *bufferStorage = attrib.storage ? GetAs(attrib.storage) : nullptr; + const auto &attrib = *currentAttributes[attribIndex]; + 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 @@ -261,18 +159,18 @@ gl::Error InputLayoutCache::applyVertexBuffers( // on the number of points indicated by the index list or how many duplicates are found on the index list. if (bufferStorage == nullptr) { - buffer = vertexBuffer->getBuffer(); + ASSERT(attrib.vertexBuffer.get()); + buffer = GetAs(attrib.vertexBuffer.get())->getBuffer().get(); } - else if (instancedPointSpritesActive && (indexInfo != nullptr)) + else if (instancedPointSpritesActive && isIndexedRendering) { + VertexArray11 *vao11 = GetImplAs(state.getVertexArray()); + ASSERT(vao11->isCachedIndexInfoValid()); + TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo(); if (indexInfo->srcIndexData.srcBuffer != nullptr) { const uint8_t *bufferData = nullptr; - error = indexInfo->srcIndexData.srcBuffer->getData(&bufferData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(indexInfo->srcIndexData.srcBuffer->getData(context, &bufferData)); ASSERT(bufferData != nullptr); ptrdiff_t offset = @@ -281,31 +179,24 @@ gl::Error InputLayoutCache::applyVertexBuffers( indexInfo->srcIndexData.srcIndices = bufferData + offset; } - buffer = bufferStorage->getEmulatedIndexedBuffer(&indexInfo->srcIndexData, &attrib); + ANGLE_TRY_RESULT(bufferStorage->getEmulatedIndexedBuffer( + context, &indexInfo->srcIndexData, attrib, start), + buffer); } else { - buffer = bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + ANGLE_TRY_RESULT( + bufferStorage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + buffer); } vertexStride = attrib.stride; - vertexOffset = attrib.offset; + ANGLE_TRY_RESULT(attrib.computeOffset(start), vertexOffset); } size_t bufferIndex = reservedBuffers + attribIndex; - if (buffer != mCurrentBuffers[bufferIndex] || - vertexStride != mCurrentVertexStrides[bufferIndex] || - vertexOffset != mCurrentVertexOffsets[bufferIndex]) - { - dirtyBuffers = true; - minDiff = std::min(minDiff, bufferIndex); - maxDiff = std::max(maxDiff, bufferIndex); - - mCurrentBuffers[bufferIndex] = buffer; - mCurrentVertexStrides[bufferIndex] = vertexStride; - mCurrentVertexOffsets[bufferIndex] = vertexOffset; - } + stateManager->queueVertexBufferChange(bufferIndex, buffer, vertexStride, vertexOffset); } // Instanced PointSprite emulation requires two additional ID3D11Buffers. A vertex buffer needs @@ -317,10 +208,9 @@ gl::Error InputLayoutCache::applyVertexBuffers( // handle missing vertex data and will TDR the system. if (programUsesInstancedPointSprites) { - HRESULT result = S_OK; const UINT pointSpriteVertexStride = sizeof(float) * 5; - if (!mPointSpriteVertexBuffer) + if (!mPointSpriteVertexBuffer.valid()) { static const float pointSpriteVertices[] = { @@ -342,25 +232,16 @@ gl::Error InputLayoutCache::applyVertexBuffers( vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; - result = mDevice->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &mPointSpriteVertexBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation vertex buffer, HRESULT: 0x%08x", result); - } + ANGLE_TRY(renderer->allocateResource(vertexBufferDesc, &vertexBufferData, + &mPointSpriteVertexBuffer)); } - 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)); + UINT stride = instancedPointSpritesActive ? pointSpriteVertexStride : 0; + stateManager->queueVertexBufferChange(0, mPointSpriteVertexBuffer.get(), stride, 0); - if (!mPointSpriteIndexBuffer) + if (!mPointSpriteIndexBuffer.valid()) { // Create an index buffer and set it for pointsprite rendering static const unsigned short pointSpriteIndices[] = @@ -377,12 +258,8 @@ gl::Error InputLayoutCache::applyVertexBuffers( indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; - result = mDevice->CreateBuffer(&indexBufferDesc, &indexBufferData, &mPointSpriteIndexBuffer); - if (FAILED(result)) - { - SafeRelease(mPointSpriteVertexBuffer); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation index buffer, HRESULT: 0x%08x", result); - } + ANGLE_TRY(renderer->allocateResource(indexBufferDesc, &indexBufferData, + &mPointSpriteIndexBuffer)); } if (instancedPointSpritesActive) @@ -391,51 +268,51 @@ gl::Error InputLayoutCache::applyVertexBuffers( // 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); + stateManager->setIndexBuffer(mPointSpriteIndexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); } } - if (dirtyBuffers) - { - ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); - mDeviceContext->IASetVertexBuffers( - static_cast(minDiff), static_cast(maxDiff - minDiff + 1), - mCurrentBuffers + minDiff, mCurrentVertexStrides + minDiff, - mCurrentVertexOffsets + minDiff); - } - - return gl::Error(GL_NO_ERROR); + stateManager->applyVertexBufferChanges(); + return gl::NoError(); } -gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId) +gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation( + Renderer11 *renderer, + const std::vector ¤tAttributes, + GLint startVertex, + GLsizei emulatedInstanceId) { + auto *stateManager = renderer->getStateManager(); + size_t reservedBuffers = GetReservedBufferCount(true); - for (size_t attribIndex = 0; attribIndex < mUnsortedAttributesCount; ++attribIndex) + for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex) { - const auto &attrib = *mSortedAttributes[attribIndex]; + const auto &attrib = *currentAttributes[attribIndex]; size_t bufferIndex = reservedBuffers + attribIndex; - if (attrib.active && attrib.divisor > 0) + if (attrib.divisor > 0) { - mCurrentVertexOffsets[bufferIndex] = - attrib.offset + (attrib.stride * (emulatedInstanceId / attrib.divisor)); + unsigned int offset = 0; + ANGLE_TRY_RESULT(attrib.computeOffset(startVertex), offset); + offset += (attrib.stride * (emulatedInstanceId / attrib.divisor)); + stateManager->queueVertexOffsetChange(bufferIndex, offset); } } - mDeviceContext->IASetVertexBuffers(0, gl::MAX_VERTEX_ATTRIBS, mCurrentBuffers, - mCurrentVertexStrides, mCurrentVertexOffsets); - - return gl::Error(GL_NO_ERROR); + stateManager->applyVertexBufferChanges(); + return gl::NoError(); } -gl::Error InputLayoutCache::updateInputLayout(gl::Program *program, - GLenum mode, - const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, - GLsizei numIndicesPerInstance) +gl::Error InputLayoutCache::updateInputLayout( + Renderer11 *renderer, + const gl::State &state, + const std::vector ¤tAttributes, + GLenum mode, + const AttribIndexArray &sortedSemanticIndices, + const DrawCallVertexParams &vertexParams) { - const std::vector &shaderAttributes = program->getAttributes(); + gl::Program *program = state.getProgram(); + const auto &shaderAttributes = program->getAttributes(); PackedAttributeLayout layout; ProgramD3D *programD3D = GetImplAs(program); @@ -453,90 +330,70 @@ gl::Error InputLayoutCache::updateInputLayout(gl::Program *program, layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE; } - if (numIndicesPerInstance > 0) + if (vertexParams.instances() > 0) { layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE; } - const auto &semanticToLocation = programD3D->getAttributesByLayout(); + const auto &attribs = state.getVertexArray()->getVertexAttributes(); + const auto &bindings = state.getVertexArray()->getVertexBindings(); + const auto &locationToSemantic = programD3D->getAttribLocationToD3DSemantics(); + int divisorMultiplier = program->usesMultiview() ? program->getNumViews() : 1; - for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex) + for (size_t attribIndex : program->getActiveAttribLocationsMask()) { - 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]); + GLenum glslElementType = GetGLSLAttributeType(shaderAttributes, attribIndex); - layout.addAttributeData(glslElementType, sortedIndex, vertexFormatType, attrib.divisor); + const auto &attrib = attribs[attribIndex]; + const auto &binding = bindings[attrib.bindingIndex]; + int d3dSemantic = locationToSemantic[attribIndex]; + + const auto ¤tValue = + state.getVertexAttribCurrentValue(static_cast(attribIndex)); + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValue.Type); + + layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatType, + binding.getDivisor() * divisorMultiplier); } - ID3D11InputLayout *inputLayout = nullptr; + const d3d11::InputLayout *inputLayout = nullptr; if (layout.numAttributes > 0 || layout.flags != 0) { - auto layoutMapIt = mLayoutMap.find(layout); - if (layoutMapIt != mLayoutMap.end()) + auto it = mLayoutCache.Get(layout); + if (it != mLayoutCache.end()) { - inputLayout = layoutMapIt->second; + inputLayout = &it->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); + angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache); - // 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); - } - } - } + d3d11::InputLayout newInputLayout; + ANGLE_TRY(createInputLayout(renderer, sortedSemanticIndices, currentAttributes, mode, + program, vertexParams, &newInputLayout)); - mLayoutMap[layout] = inputLayout; + auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout)); + inputLayout = &insertIt->second; } } - if (inputLayout != mCurrentIL) - { - mDeviceContext->IASetInputLayout(inputLayout); - mCurrentIL = inputLayout; - } - - return gl::Error(GL_NO_ERROR); + renderer->getStateManager()->setInputLayout(inputLayout); + return gl::NoError(); } -gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAttributes, - const SortedIndexArray &sortedSemanticIndices, - size_t attribCount, - GLenum mode, - gl::Program *program, - GLsizei numIndicesPerInstance, - ID3D11InputLayout **inputLayoutOut) +gl::Error InputLayoutCache::createInputLayout( + Renderer11 *renderer, + const AttribIndexArray &sortedSemanticIndices, + const std::vector ¤tAttributes, + GLenum mode, + gl::Program *program, + const DrawCallVertexParams &vertexParams, + d3d11::InputLayout *inputLayoutOut) { ProgramD3D *programD3D = GetImplAs(program); + auto featureLevel = renderer->getRenderer11DeviceCaps().featureLevel; bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); @@ -544,20 +401,17 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt unsigned int inputElementCount = 0; std::array inputElements; - for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex) + for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex) { - const auto &attrib = *sortedAttributes[attribIndex]; + const auto &attrib = *currentAttributes[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); + const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel); auto *inputElement = &inputElements[inputElementCount]; @@ -584,23 +438,28 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt // 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. + + GLsizei numIndicesPerInstance = 0; + if (vertexParams.instances() > 0) + { + // This may trigger an evaluation of the index range. + numIndicesPerInstance = vertexParams.vertexCount(); + } + 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) { - // 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 && currentAttributes[elementIndex]->divisor > 0) { - 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].InstanceDataStepRate = numIndicesPerInstance; } - inputElements[elementIndex].InputSlot++; } + inputElements[elementIndex].InputSlot++; } inputElements[inputElementCount].SemanticName = "SPRITEPOSITION"; @@ -622,28 +481,23 @@ gl::Error InputLayoutCache::createInputLayout(const SortedAttribArray &sortedAtt inputElementCount++; } - const gl::InputLayout &shaderInputLayout = GetInputLayout(sortedAttributes, attribCount); - ShaderExecutableD3D *shader = nullptr; - gl::Error error = - programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&shader, nullptr)); 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); - } + InputElementArray inputElementArray(inputElements.data(), inputElementCount); + ShaderData vertexShaderData(shader11->getFunction(), shader11->getLength()); - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(renderer->allocateResource(inputElementArray, &vertexShaderData, inputLayoutOut)); + return gl::NoError(); +} + +void InputLayoutCache::setCacheSize(size_t newCacheSize) +{ + // Forces a reset of the cache. + LayoutCache newCache(newCacheSize); + mLayoutCache.Swap(newCache); } } // 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 e208ae3c64..8d7c7dd0f0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h @@ -20,12 +20,55 @@ #include "common/angleutils.h" #include "libANGLE/Constants.h" #include "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + +namespace rx +{ +class DrawCallVertexParams; +struct PackedAttributeLayout +{ + PackedAttributeLayout(); + PackedAttributeLayout(const PackedAttributeLayout &other); + + void addAttributeData(GLenum glType, + UINT semanticIndex, + gl::VertexFormatType vertexFormatType, + unsigned int divisor); + + bool operator==(const PackedAttributeLayout &other) const; + + enum Flags + { + FLAG_USES_INSTANCED_SPRITES = 0x1, + FLAG_INSTANCED_SPRITES_ACTIVE = 0x2, + FLAG_INSTANCED_RENDERING_ACTIVE = 0x4, + }; + + uint32_t numAttributes; + uint32_t flags; + std::array attributeData; +}; +} // namespace rx + +namespace std +{ +template <> +struct hash +{ + size_t operator()(const rx::PackedAttributeLayout &value) const + { + return angle::ComputeGenericHash(value); + } +}; +} // namespace std namespace gl { class Program; -} +} // namespace gl namespace rx { @@ -33,91 +76,58 @@ struct TranslatedAttribute; struct TranslatedIndexData; struct SourceIndexData; class ProgramD3D; - -using SortedAttribArray = std::array; -using SortedIndexArray = std::array; +class Renderer11; class InputLayoutCache : angle::NonCopyable { public: InputLayoutCache(); - virtual ~InputLayoutCache(); + ~InputLayoutCache(); - void initialize(ID3D11Device *device, ID3D11DeviceContext *context); void clear(); - void markDirty(); - gl::Error applyVertexBuffers(const std::vector &attributes, + gl::Error applyVertexBuffers(const gl::Context *context, + const std::vector ¤tAttributes, GLenum mode, - gl::Program *program, - TranslatedIndexData *indexInfo, - GLsizei numIndicesPerInstance); + GLint start, + bool isIndexedRendering); - gl::Error updateVertexOffsetsForPointSpritesEmulation(GLsizei emulatedInstanceId); + gl::Error updateVertexOffsetsForPointSpritesEmulation( + Renderer11 *renderer, + const std::vector ¤tAttributes, + GLint startVertex, + GLsizei emulatedInstanceId); // Useful for testing - void setCacheSize(unsigned int cacheSize) { mCacheSize = cacheSize; } - - private: - struct PackedAttributeLayout - { - PackedAttributeLayout() - : numAttributes(0), - flags(0) - { - } - - void addAttributeData(GLenum glType, - UINT semanticIndex, - gl::VertexFormatType vertexFormatType, - unsigned int divisor); - - bool operator<(const PackedAttributeLayout &other) const; - - enum Flags - { - 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]; - }; + void setCacheSize(size_t newCacheSize); - gl::Error updateInputLayout(gl::Program *program, + gl::Error updateInputLayout(Renderer11 *renderer, + const gl::State &state, + const std::vector ¤tAttributes, 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, + const AttribIndexArray &sortedSemanticIndices, + const DrawCallVertexParams &vertexParams); + + private: + gl::Error createInputLayout(Renderer11 *renderer, + const AttribIndexArray &sortedSemanticIndices, + const std::vector ¤tAttributes, GLenum mode, gl::Program *program, - GLsizei numIndicesPerInstance, - ID3D11InputLayout **inputLayoutOut); - - std::map mLayoutMap; + const DrawCallVertexParams &vertexParams, + d3d11::InputLayout *inputLayoutOut); - 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; + // Starting cache size. + static constexpr size_t kDefaultCacheSize = 1024; - ID3D11Buffer *mPointSpriteVertexBuffer; - ID3D11Buffer *mPointSpriteIndexBuffer; + // The cache tries to clean up this many states at once. + static constexpr size_t kGCLimit = 128; - unsigned int mCacheSize; - unsigned long long mCounter; + using LayoutCache = angle::base::HashingMRUCache; + LayoutCache mLayoutCache; - ID3D11Device *mDevice; - ID3D11DeviceContext *mDeviceContext; - D3D_FEATURE_LEVEL mFeatureLevel; + d3d11::Buffer mPointSpriteVertexBuffer; + d3d11::Buffer mPointSpriteIndexBuffer; }; } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h deleted file mode 100644 index 612b06bb10..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// NativeWindow.h: Defines NativeWindow, a class for managing and -// performing operations on an EGLNativeWindowType. -// It is used for HWND (Desktop Windows) and IInspectable objects -//(Windows Store Applications). - -#ifndef LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ -#define LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ - -#include "common/debug.h" -#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 -// and IDXGIFactory and the Windows Store NativeWindow -// implementation requires IDXGISwapChain1 and IDXGIFactory2. -#if defined(ANGLE_ENABLE_WINDOWS_STORE) -typedef IDXGISwapChain1 DXGISwapChain; -typedef IDXGIFactory2 DXGIFactory; - -#include -#include -#include -#include - -namespace rx -{ -class InspectableNativeWindow; -} - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -#elif defined(ANGLE_ENABLE_D3D11) -typedef IDXGISwapChain DXGISwapChain; -typedef IDXGIFactory DXGIFactory; -#endif - -typedef interface IDCompositionDevice IDCompositionDevice; -typedef interface IDCompositionTarget IDCompositionTarget; -typedef interface IDCompositionVisual IDCompositionVisual; - -namespace rx -{ - -class NativeWindow -{ - public: - enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 }; - explicit NativeWindow(EGLNativeWindowType window, - const egl::Config *config, - bool directComposition); - - ~NativeWindow(); - bool initialize(); - bool getClientRect(LPRECT rect); - bool isIconic(); -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - RotationFlags rotationFlags() const; -#endif - static bool isValidNativeWindow(EGLNativeWindowType window); - -#if defined(ANGLE_ENABLE_D3D11) - HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, - DXGI_FORMAT format, UINT width, UINT height, - DXGISwapChain** swapChain); -#endif - - 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 - -}; - -} - -#endif // LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h new file mode 100644 index 0000000000..ab234d4450 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow11.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11.h: Defines NativeWindow11, a class for managing and performing operations on an +// EGLNativeWindowType for the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "libANGLE/Config.h" +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +class NativeWindow11 : public NativeWindowD3D +{ + public: + NativeWindow11(EGLNativeWindowType window) : NativeWindowD3D(window) {} + + virtual HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) = 0; + virtual void commitChange() = 0; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW11_H_ 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 dfc521f14f..7d7ecb0976 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -36,40 +36,25 @@ namespace rx PixelTransfer11::PixelTransfer11(Renderer11 *renderer) : mRenderer(renderer), mResourcesLoaded(false), - mBufferToTextureVS(NULL), - mBufferToTextureGS(NULL), - mParamsConstantBuffer(NULL), - mCopyRasterizerState(NULL), - mCopyDepthStencilState(NULL) + mBufferToTextureVS(), + mBufferToTextureGS(), + mParamsConstantBuffer(), + mCopyRasterizerState(), + mCopyDepthStencilState() { } PixelTransfer11::~PixelTransfer11() { - for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) - { - SafeRelease(shaderMapIt->second); - } - - mBufferToTexturePSMap.clear(); - - SafeRelease(mBufferToTextureVS); - SafeRelease(mBufferToTextureGS); - SafeRelease(mParamsConstantBuffer); - SafeRelease(mCopyRasterizerState); - SafeRelease(mCopyDepthStencilState); } gl::Error PixelTransfer11::loadResources() { if (mResourcesLoaded) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - HRESULT result = S_OK; - ID3D11Device *device = mRenderer->getDevice(); - D3D11_RASTERIZER_DESC rasterDesc; rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.CullMode = D3D11_CULL_NONE; @@ -82,12 +67,7 @@ gl::Error PixelTransfer11::loadResources() rasterDesc.MultisampleEnable = FALSE; rasterDesc.AntialiasedLineEnable = FALSE; - result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer rasterizer state, result: 0x%X.", result); - } + ANGLE_TRY(mRenderer->allocateResource(rasterDesc, &mCopyRasterizerState)); D3D11_DEPTH_STENCIL_DESC depthStencilDesc; depthStencilDesc.DepthEnable = true; @@ -105,12 +85,7 @@ gl::Error PixelTransfer11::loadResources() depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer depth stencil state, result: 0x%X.", result); - } + ANGLE_TRY(mRenderer->allocateResource(depthStencilDesc, &mCopyDepthStencilState)); D3D11_BUFFER_DESC constantBufferDesc = { 0 }; constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); @@ -120,38 +95,23 @@ gl::Error PixelTransfer11::loadResources() constantBufferDesc.MiscFlags = 0; constantBufferDesc.StructureByteStride = 0; - result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer constant buffer, result: 0x%X.", result); - } - d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDesc, &mParamsConstantBuffer)); + mParamsConstantBuffer.setDebugName("PixelTransfer11 constant buffer"); // init shaders - mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); - if (!mBufferToTextureVS) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); - } + ANGLE_TRY(mRenderer->allocateResource(ShaderData(g_VS_BufferToTexture), &mBufferToTextureVS)); + mBufferToTextureVS.setDebugName("BufferToTexture VS"); - mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); - if (!mBufferToTextureGS) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); - } + ANGLE_TRY(mRenderer->allocateResource(ShaderData(g_GS_BufferToTexture), &mBufferToTextureGS)); + mBufferToTextureGS.setDebugName("BufferToTexture GS"); - gl::Error error = buildShaderMap(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buildShaderMap()); StructZero(&mParamsData); mResourcesLoaded = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, @@ -162,7 +122,7 @@ void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, cons float texelCenterX = 0.5f / static_cast(destSize.width - 1); float texelCenterY = 0.5f / static_cast(destSize.height - 1); - unsigned int bytesPerPixel = gl::GetInternalFormatInfo(internalFormat).pixelBytes; + unsigned int bytesPerPixel = gl::GetSizedInternalFormatInfo(internalFormat).pixelBytes; unsigned int alignmentBytes = static_cast(unpack.alignment); unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); @@ -177,14 +137,15 @@ void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, cons parametersOut->FirstSlice = destArea.z; } -gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error PixelTransfer11::copyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) { - gl::Error error = loadResources(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(loadResources()); gl::Extents destSize = destRenderTarget->getExtents(); @@ -192,114 +153,106 @@ gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpac destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); - const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); + const gl::Buffer &sourceBuffer = + *context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); - ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + const d3d11::PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); ASSERT(pixelShader); // The SRV must be in the proper read format, which may be different from the destination format // EG: for half float data, we can load full precision floats with implicit conversion - GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format; - GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); + GLenum unsizedFormat = gl::GetUnsizedFormat(destinationFormat); + const gl::InternalFormat &sourceglFormatInfo = + gl::GetInternalFormatInfo(unsizedFormat, sourcePixelsType); - const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &sourceFormatInfo = d3d11::Format::Get( + sourceglFormatInfo.sizedInternalFormat, mRenderer->getRenderer11DeviceCaps()); DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); Buffer11 *bufferStorage11 = GetAs(sourceBuffer.getImplementation()); - ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); - ASSERT(bufferSRV != NULL); + const d3d11::ShaderResourceView *bufferSRV = nullptr; + ANGLE_TRY_RESULT(bufferStorage11->getSRV(context, srvFormat), bufferSRV); + ASSERT(bufferSRV != nullptr); - ID3D11RenderTargetView *textureRTV = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(textureRTV != NULL); + const d3d11::RenderTargetView &textureRTV = + GetAs(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV.valid()); CopyShaderParams shaderParams; - setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + setBufferToTextureCopyParams(destArea, destSize, sourceglFormatInfo.sizedInternalFormat, unpack, + offset, &shaderParams); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - ID3D11Buffer *nullBuffer = NULL; - UINT zero = 0; - // Are we doing a 2D or 3D copy? - ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); - auto stateManager = mRenderer->getStateManager(); + const auto *geometryShader = ((destSize.depth > 1) ? &mBufferToTextureGS : nullptr); + StateManager11 *stateManager = mRenderer->getStateManager(); - deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); - deviceContext->GSSetShader(geometryShader, NULL, 0); - deviceContext->PSSetShader(pixelShader, NULL, 0); + stateManager->setDrawShaders(&mBufferToTextureVS, geometryShader, pixelShader); stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); - deviceContext->IASetInputLayout(NULL); - deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + stateManager->setInputLayout(nullptr); + stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); - deviceContext->RSSetState(mCopyRasterizerState); + stateManager->setSingleVertexBuffer(nullptr, 0, 0); + stateManager->setSimpleBlendState(nullptr); + stateManager->setDepthStencilState(&mCopyDepthStencilState, 0xFFFFFFFF); + stateManager->setRasterizerState(&mCopyRasterizerState); - mRenderer->setOneTimeRenderTarget(textureRTV); + stateManager->setRenderTarget(textureRTV.get(), nullptr); if (!StructEquals(mParamsData, shaderParams)) { - d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer.get(), shaderParams); mParamsData = shaderParams; } - deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + stateManager->setVertexConstantBuffer(0, &mParamsConstantBuffer); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(destSize.width); - viewport.Height = static_cast(destSize.height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); + stateManager->setSimpleViewport(destSize); UINT numPixels = (destArea.width * destArea.height * destArea.depth); deviceContext->Draw(numPixels, 0); - // Unbind textures and render targets and vertex buffer - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error PixelTransfer11::buildShaderMap() { - ID3D11Device *device = mRenderer->getDevice(); - - mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); - mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); - mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); - - // Check that all the shaders were created successfully - for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) - { - if (shaderMapIt->second == NULL) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture pixel shader."); - } - } - - return gl::Error(GL_NO_ERROR); + d3d11::PixelShader bufferToTextureFloat; + d3d11::PixelShader bufferToTextureInt; + d3d11::PixelShader bufferToTextureUint; + + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4F), &bufferToTextureFloat)); + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4I), &bufferToTextureInt)); + ANGLE_TRY( + mRenderer->allocateResource(ShaderData(g_PS_BufferToTexture_4UI), &bufferToTextureUint)); + + bufferToTextureFloat.setDebugName("BufferToTexture RGBA ps"); + bufferToTextureInt.setDebugName("BufferToTexture RGBA-I ps"); + bufferToTextureUint.setDebugName("BufferToTexture RGBA-UI ps"); + + mBufferToTexturePSMap[GL_FLOAT] = std::move(bufferToTextureFloat); + mBufferToTexturePSMap[GL_INT] = std::move(bufferToTextureInt); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = std::move(bufferToTextureUint); + + return gl::NoError(); } -ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +const d3d11::PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const { - GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType; + GLenum componentType = gl::GetSizedInternalFormatInfo(internalFormat).componentType; if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) { componentType = GL_FLOAT; } auto shaderMapIt = mBufferToTexturePSMap.find(componentType); - return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); + return (shaderMapIt == mBufferToTexturePSMap.end() ? nullptr : &shaderMapIt->second); } -} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h index 1672121ec7..a93544247e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h @@ -11,14 +11,14 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ -#include "libANGLE/Error.h" - -#include "common/platform.h" - #include #include +#include "common/platform.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + namespace gl { @@ -45,8 +45,13 @@ class PixelTransfer11 // destRenderTarget: individual slice/layer of a target texture // destinationFormat/sourcePixelsType: determines shaders + shader parameters // destArea: the sub-section of destRenderTarget to copy to - gl::Error copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + gl::Error copyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea); private: @@ -68,22 +73,21 @@ class PixelTransfer11 gl::Error loadResources(); gl::Error buildShaderMap(); - ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + const d3d11::PixelShader *findBufferToTexturePS(GLenum internalFormat) const; Renderer11 *mRenderer; bool mResourcesLoaded; - std::map mBufferToTexturePSMap; - ID3D11VertexShader *mBufferToTextureVS; - ID3D11GeometryShader *mBufferToTextureGS; - ID3D11Buffer *mParamsConstantBuffer; + std::map mBufferToTexturePSMap; + d3d11::VertexShader mBufferToTextureVS; + d3d11::GeometryShader mBufferToTextureGS; + d3d11::Buffer mParamsConstantBuffer; CopyShaderParams mParamsData; - ID3D11RasterizerState *mCopyRasterizerState; - ID3D11DepthStencilState *mCopyDepthStencilState; - + d3d11::RasterizerState mCopyRasterizerState; + d3d11::DepthStencilState mCopyDepthStencilState; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp new file mode 100644 index 0000000000..c9554431e5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp @@ -0,0 +1,24 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ProgramPipelineNULL.cpp: +// Implements the class methods for ProgramPipeline11. +// + +#include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h" + +namespace rx +{ + +ProgramPipeline11::ProgramPipeline11(const gl::ProgramPipelineState &state) + : ProgramPipelineImpl(state) +{ +} + +ProgramPipeline11::~ProgramPipeline11() +{ +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h new file mode 100644 index 0000000000..cf838eec05 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h @@ -0,0 +1,27 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ProgramPipeline11.h: +// Defines the class interface for ProgramPipeline11, implementing ProgramPipelineImpl. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_H_ + +#include "libANGLE/renderer/ProgramPipelineImpl.h" + +namespace rx +{ + +class ProgramPipeline11 : public ProgramPipelineImpl +{ + public: + ProgramPipeline11(const gl::ProgramPipelineState &state); + ~ProgramPipeline11() override; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_PROGRAMPIPELINE11_H_ 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 0a79b26df0..66b9476e7f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -7,146 +7,96 @@ // Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. #include "libANGLE/renderer/d3d/d3d11/Query11.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -#include "common/utilities.h" #include -#if defined(ANGLE_MINGW32_COMPAT) -typedef struct D3D11_QUERY_DATA_SO_STATISTICS { - UINT64 NumPrimitivesWritten; - UINT64 PrimitivesStorageNeeded; -} D3D11_QUERY_DATA_SO_STATISTICS; -#endif // ANGLE_MINGW32_COMPAT - -#ifndef ANGLE_D3D11_QDTD_AVAILABLE -typedef struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT { - UINT64 Frequency; - BOOL Disjoint; -} D3D11_QUERY_DATA_TIMESTAMP_DISJOINT; -#endif // MINGW32 +#include "common/utilities.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -namespace rx +namespace { -Query11::Query11(Renderer11 *renderer, GLenum type) - : QueryImpl(type), - mResult(0), - mQueryFinished(false), - mRenderer(renderer), - mQuery(nullptr), - mTimestampBeginQuery(nullptr), - mTimestampEndQuery(nullptr) +GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult) { -} + switch (type) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE; -Query11::~Query11() -{ - SafeRelease(mQuery); - SafeRelease(mTimestampBeginQuery); - SafeRelease(mTimestampEndQuery); -} + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return currentResult + newResult; -gl::Error Query11::begin() -{ - if (mQuery == nullptr) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); - queryDesc.MiscFlags = 0; + case GL_TIME_ELAPSED_EXT: + return currentResult + newResult; - ID3D11Device *device = mRenderer->getDevice(); + case GL_TIMESTAMP_EXT: + return newResult; - HRESULT result = device->CreateQuery(&queryDesc, &mQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); - } + case GL_COMMANDS_COMPLETED_CHROMIUM: + return newResult; - // 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); - } - } + default: + UNREACHABLE(); + return 0; } +} - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); +} // anonymous namespace - context->Begin(mQuery); +namespace rx +{ - // 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); +Query11::QueryState::QueryState() : query(), beginTimestamp(), endTimestamp(), finished(false) +{ } -gl::Error Query11::end() +Query11::QueryState::~QueryState() { - ASSERT(mQuery); - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); +} - // If we are doing time elapsed query the end timestamp - if (getType() == GL_TIME_ELAPSED_EXT) - { - context->End(mTimestampEndQuery); - } +Query11::Query11(Renderer11 *renderer, GLenum type) + : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer) +{ + mActiveQuery = std::unique_ptr(new QueryState()); +} - context->End(mQuery); +Query11::~Query11() +{ + mRenderer->getStateManager()->onDeleteQueryObject(this); +} - mQueryFinished = false; - mResult = GL_FALSE; +gl::Error Query11::begin() +{ + mResultSum = 0; + mRenderer->getStateManager()->onBeginQuery(this); + return resume(); +} - return gl::Error(GL_NO_ERROR); +gl::Error Query11::end() +{ + return pause(); } 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); + mResultSum = 0; + mPendingQueries.push_back(std::unique_ptr(new QueryState())); + return gl::NoError(); } template gl::Error Query11::getResultBase(T *params) { - while (!mQueryFinished) - { - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - if (!mQueryFinished) - { - ScheduleYield(); - } - } + ASSERT(!mActiveQuery->query.valid()); + ANGLE_TRY(flush(true)); + ASSERT(mPendingQueries.empty()); + *params = static_cast(mResultSum); - ASSERT(mQueryFinished); - *params = static_cast(mResult); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query11::getResult(GLint *params) @@ -171,105 +121,197 @@ gl::Error Query11::getResult(GLuint64 *params) gl::Error Query11::isResultAvailable(bool *available) { - gl::Error error = testQuery(); - if (error.isError()) + ANGLE_TRY(flush(false)); + + *available = mPendingQueries.empty(); + return gl::NoError(); +} + +gl::Error Query11::pause() +{ + if (mActiveQuery->query.valid()) { - return error; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + GLenum queryType = getType(); + + // If we are doing time elapsed query the end timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + context->End(mActiveQuery->endTimestamp.get()); + } + + context->End(mActiveQuery->query.get()); + + mPendingQueries.push_back(std::move(mActiveQuery)); + mActiveQuery = std::unique_ptr(new QueryState()); } - *available = mQueryFinished; + return flush(false); +} + +gl::Error Query11::resume() +{ + if (!mActiveQuery->query.valid()) + { + ANGLE_TRY(flush(false)); + + GLenum queryType = getType(); + D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(queryType); - return gl::Error(GL_NO_ERROR); + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = d3dQueryType; + queryDesc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(queryDesc, &mActiveQuery->query)); + + // If we are doing time elapsed we also need a query to actually query the timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + D3D11_QUERY_DESC desc; + desc.Query = D3D11_QUERY_TIMESTAMP; + desc.MiscFlags = 0; + + ANGLE_TRY(mRenderer->allocateResource(desc, &mActiveQuery->beginTimestamp)); + ANGLE_TRY(mRenderer->allocateResource(desc, &mActiveQuery->endTimestamp)); + } + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + if (d3dQueryType != D3D11_QUERY_EVENT) + { + context->Begin(mActiveQuery->query.get()); + } + + // If we are doing time elapsed, query the begin timestamp + if (queryType == GL_TIME_ELAPSED_EXT) + { + context->End(mActiveQuery->beginTimestamp.get()); + } + } + + return gl::NoError(); } -gl::Error Query11::testQuery() +gl::Error Query11::flush(bool force) { - if (!mQueryFinished) + while (!mPendingQueries.empty()) { - ASSERT(mQuery); + QueryState *query = mPendingQueries.front().get(); + do + { + ANGLE_TRY(testQuery(query)); + if (!query->finished && !force) + { + return gl::NoError(); + } + } while (!query->finished); + + mResultSum = MergeQueryResults(getType(), mResultSum, mResult); + mPendingQueries.pop_front(); + } + + return gl::NoError(); +} + +gl::Error Query11::testQuery(QueryState *queryState) +{ + if (!queryState->finished) + { ID3D11DeviceContext *context = mRenderer->getDeviceContext(); switch (getType()) { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: { + ASSERT(queryState->query.valid()); UINT64 numPixels = 0; - HRESULT result = context->GetData(mQuery, &numPixels, sizeof(numPixels), 0); + HRESULT result = + context->GetData(queryState->query.get(), &numPixels, sizeof(numPixels), 0); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { - mQueryFinished = true; - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + queryState->finished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; } } break; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: { - D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; - HRESULT result = context->GetData(mQuery, &soStats, sizeof(soStats), 0); + ASSERT(queryState->query.valid()); + D3D11_QUERY_DATA_SO_STATISTICS soStats = {0}; + HRESULT result = + context->GetData(queryState->query.get(), &soStats, sizeof(soStats), 0); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { - mQueryFinished = true; - mResult = static_cast(soStats.NumPrimitivesWritten); + queryState->finished = true; + mResult = static_cast(soStats.NumPrimitivesWritten); } } break; case GL_TIME_ELAPSED_EXT: { + ASSERT(queryState->query.valid()); + ASSERT(queryState->beginTimestamp.valid()); + ASSERT(queryState->endTimestamp.valid()); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {0}; - HRESULT result = context->GetData(mQuery, &timeStats, sizeof(timeStats), 0); + HRESULT result = + context->GetData(queryState->query.get(), &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); + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); } if (result == S_OK) { UINT64 beginTime = 0; - HRESULT beginRes = - context->GetData(mTimestampBeginQuery, &beginTime, sizeof(UINT64), 0); + HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(), + &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); + return gl::OutOfMemory() << "Failed to get the data of an internal query, " + << gl::FmtHR(beginRes); } UINT64 endTime = 0; - HRESULT endRes = - context->GetData(mTimestampEndQuery, &endTime, sizeof(UINT64), 0); + HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &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); + return gl::OutOfMemory() << "Failed to get the data of an internal query, " + << gl::FmtHR(endRes); } if (beginRes == S_OK && endRes == S_OK) { - mQueryFinished = true; + queryState->finished = 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)) + + angle::CheckedNumeric checkedTime(endTime); + checkedTime -= beginTime; + checkedTime *= 1000000000ull; + checkedTime /= timeStats.Frequency; + if (checkedTime.IsValid()) { - mResult = ((endTime - beginTime) * 1000000000ull) / timeStats.Frequency; + mResult = checkedTime.ValueOrDie(); } else { @@ -288,23 +330,46 @@ gl::Error Query11::testQuery() // 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; + ASSERT(!queryState->query.valid()); + mResult = 0; + queryState->finished = true; } break; - default: - UNREACHABLE(); + case GL_COMMANDS_COMPLETED_CHROMIUM: + { + ASSERT(queryState->query.valid()); + BOOL completed = 0; + HRESULT result = + context->GetData(queryState->query.get(), &completed, sizeof(completed), 0); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to get the data of an internal query, " << gl::FmtHR(result); + } + + if (result == S_OK) + { + queryState->finished = true; + ASSERT(completed == TRUE); + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } + } break; + + default: + UNREACHABLE(); + break; } - if (!mQueryFinished && mRenderer->testDeviceLost()) + if (!queryState->finished && mRenderer->testDeviceLost()) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + return gl::OutOfMemory() << "Failed to test get query result, device is lost."; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -} +} // namespace rx 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 29a6e6f85d..a88a8892aa 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h @@ -9,7 +9,10 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ +#include + #include "libANGLE/renderer/QueryImpl.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -19,31 +22,45 @@ class Query11 : public QueryImpl { public: Query11(Renderer11 *renderer, GLenum type); - virtual ~Query11(); + ~Query11() override; + + gl::Error begin() override; + gl::Error end() override; + gl::Error queryCounter() override; + gl::Error getResult(GLint *params) override; + gl::Error getResult(GLuint *params) override; + gl::Error getResult(GLint64 *params) override; + gl::Error getResult(GLuint64 *params) override; + gl::Error isResultAvailable(bool *available) override; - 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 getResult(GLint64 *params); - virtual gl::Error getResult(GLuint64 *params); - virtual gl::Error isResultAvailable(bool *available); + gl::Error pause(); + gl::Error resume(); private: - gl::Error testQuery(); + struct QueryState final : private angle::NonCopyable + { + QueryState(); + ~QueryState(); + + d3d11::Query query; + d3d11::Query beginTimestamp; + d3d11::Query endTimestamp; + bool finished; + }; + + gl::Error flush(bool force); + gl::Error testQuery(QueryState *queryState); template gl::Error getResultBase(T *params); GLuint64 mResult; - - bool mQueryFinished; + GLuint64 mResultSum; Renderer11 *mRenderer; - ID3D11Query *mQuery; - ID3D11Query *mTimestampBeginQuery; - ID3D11Query *mTimestampEndQuery; + + std::unique_ptr mActiveQuery; + std::deque> mPendingQueries; }; } 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 2ee25cfb6c..5b85196c2e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp @@ -17,338 +17,180 @@ #include "libANGLE/renderer/d3d/FramebufferD3D.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" -#include "third_party/murmurhash/MurmurHash3.h" namespace rx { using namespace gl_d3d11; -template -static void ClearStateMap(mapType &map) -{ - for (typename mapType::iterator i = map.begin(); i != map.end(); i++) - { - SafeRelease(i->second.first); - } - map.clear(); -} - -// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, -// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum -// number of unique states of each type an application can create is 4096 -const unsigned int RenderStateCache::kMaxBlendStates = 4096; -const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; -const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; -const unsigned int RenderStateCache::kMaxSamplerStates = 4096; - -RenderStateCache::RenderStateCache(Renderer11 *renderer) - : mRenderer(renderer), - mCounter(0), - mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), - mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), - mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), - mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates), - mDevice(NULL) +RenderStateCache::RenderStateCache() + : mBlendStateCache(kMaxStates), + mRasterizerStateCache(kMaxStates), + mDepthStencilStateCache(kMaxStates), + mSamplerStateCache(kMaxStates) { } RenderStateCache::~RenderStateCache() { - clear(); -} - -void RenderStateCache::initialize(ID3D11Device *device) -{ - clear(); - mDevice = device; } void RenderStateCache::clear() { - ClearStateMap(mBlendStateCache); - ClearStateMap(mRasterizerStateCache); - ClearStateMap(mDepthStencilStateCache); - ClearStateMap(mSamplerStateCache); + mBlendStateCache.Clear(); + mRasterizerStateCache.Clear(); + mDepthStencilStateCache.Clear(); + mSamplerStateCache.Clear(); } -std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) +// static +d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState) { - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); - return hash; -} + d3d11::BlendStateKey key; + FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); + const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(context); + const UINT8 blendStateMask = + gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen, + blendState.colorMaskBlue, blendState.colorMaskAlpha); -bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) -{ - return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; -} - -gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, - ID3D11BlendState **outBlendState) -{ - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - bool mrt = false; - - const FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); - const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(); - - BlendStateKey key = {}; key.blendState = blendState; - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *attachment = colorbuffers[colorAttachment]; - auto rtChannels = key.rtChannels[colorAttachment]; + for (size_t i = 0; i < colorbuffers.size(); i++) + { + const gl::FramebufferAttachment *attachment = colorbuffers[i]; if (attachment) { - if (colorAttachment > 0) - { - mrt = true; - } - - rtChannels[0] = attachment->getRedSize() > 0; - rtChannels[1] = attachment->getGreenSize() > 0; - rtChannels[2] = attachment->getBlueSize() > 0; - rtChannels[3] = attachment->getAlphaSize() > 0; + key.rtvMax = static_cast(i) + 1; + key.rtvMasks[i] = + (gl_d3d11::GetColorMask(*attachment->getFormat().info)) & blendStateMask; } } - BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + return key; +} + +gl::Error RenderStateCache::getBlendState(Renderer11 *renderer, + const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState) +{ + auto keyIter = mBlendStateCache.Get(key); if (keyIter != mBlendStateCache.end()) { - BlendStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outBlendState = state.first; - return gl::Error(GL_NO_ERROR); + *outBlendState = &keyIter->second; + return gl::NoError(); } - else - { - if (mBlendStateCache.size() >= kMaxBlendStates) - { - TRACE("Overflowed the limit of %u blend states, removing the least recently used " - "to make room.", kMaxBlendStates); - - BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); - for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mBlendStateCache.erase(leastRecentlyUsed); - } - // Create a new blend state and insert it into the cache - D3D11_BLEND_DESC blendDesc = { 0 }; - blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; - blendDesc.IndependentBlendEnable = mrt ? TRUE : FALSE; + TrimCache(kMaxStates, kGCLimit, "blend state", &mBlendStateCache); - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) - { - D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; - - rtBlend.BlendEnable = blendState.blend; - if (blendState.blend) - { - rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); - rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); - rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); - - rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); - rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); - rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); - } - - rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(key.rtChannels[i][0] && blendState.colorMaskRed, - key.rtChannels[i][1] && blendState.colorMaskGreen, - key.rtChannels[i][2] && blendState.colorMaskBlue, - key.rtChannels[i][3] && blendState.colorMaskAlpha); - } + // Create a new blend state and insert it into the cache + D3D11_BLEND_DESC blendDesc; + D3D11_RENDER_TARGET_BLEND_DESC &rtDesc0 = blendDesc.RenderTarget[0]; + const gl::BlendState &blendState = key.blendState; - ID3D11BlendState *dx11BlendState = NULL; - HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); - if (FAILED(result) || !dx11BlendState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); - } + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; + blendDesc.IndependentBlendEnable = key.rtvMax > 1 ? TRUE : FALSE; - mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); + rtDesc0 = {}; - *outBlendState = dx11BlendState; - return gl::Error(GL_NO_ERROR); + if (blendState.blend) + { + rtDesc0.BlendEnable = true; + rtDesc0.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); + rtDesc0.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); + rtDesc0.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); + rtDesc0.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); + rtDesc0.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); + rtDesc0.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); } -} -std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) -{ - static const unsigned int seed = 0xABCDEF98; + rtDesc0.RenderTargetWriteMask = key.rtvMasks[0]; - std::size_t hash = 0; - MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); - return hash; -} + for (unsigned int i = 1; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + blendDesc.RenderTarget[i] = rtDesc0; + blendDesc.RenderTarget[i].RenderTargetWriteMask = key.rtvMasks[i]; + } -bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) -{ - return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; + d3d11::BlendState d3dBlendState; + ANGLE_TRY(renderer->allocateResource(blendDesc, &d3dBlendState)); + const auto &iter = mBlendStateCache.Put(key, std::move(d3dBlendState)); + + *outBlendState = &iter->second; + + return gl::NoError(); } -gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, +gl::Error RenderStateCache::getRasterizerState(Renderer11 *renderer, + const gl::RasterizerState &rasterState, + bool scissorEnabled, ID3D11RasterizerState **outRasterizerState) { - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - RasterizerStateKey key = {}; + d3d11::RasterizerStateKey key; key.rasterizerState = rasterState; - key.scissorEnabled = scissorEnabled; + key.scissorEnabled = scissorEnabled ? 1 : 0; - RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + auto keyIter = mRasterizerStateCache.Get(key); if (keyIter != mRasterizerStateCache.end()) { - RasterizerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outRasterizerState = state.first; - return gl::Error(GL_NO_ERROR); + *outRasterizerState = keyIter->second.get(); + return gl::NoError(); } - else - { - if (mRasterizerStateCache.size() >= kMaxRasterizerStates) - { - TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " - "to make room.", kMaxRasterizerStates); - - RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); - for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mRasterizerStateCache.erase(leastRecentlyUsed); - } - D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); + TrimCache(kMaxStates, kGCLimit, "rasterizer state", &mRasterizerStateCache); - // Disable culling if drawing points - if (rasterState.pointDrawMode) - { - cullMode = D3D11_CULL_NONE; - } + D3D11_CULL_MODE cullMode = + gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); - D3D11_RASTERIZER_DESC rasterDesc; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.CullMode = cullMode; - rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; - rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; - rasterDesc.MultisampleEnable = rasterState.multiSample; - rasterDesc.AntialiasedLineEnable = FALSE; - - if (rasterState.polygonOffsetFill) - { - rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; - rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; - } - else - { - rasterDesc.SlopeScaledDepthBias = 0.0f; - rasterDesc.DepthBias = 0; - } - - ID3D11RasterizerState *dx11RasterizerState = NULL; - HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); - if (FAILED(result) || !dx11RasterizerState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); - } - - mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); - - *outRasterizerState = dx11RasterizerState; - return gl::Error(GL_NO_ERROR); - } -} - -std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) -{ - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); - return hash; -} - -bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) -{ - return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; -} - -gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &originalState, - bool disableDepth, - bool disableStencil, - ID3D11DepthStencilState **outDSState) -{ - if (!mDevice) + // Disable culling if drawing points + if (rasterState.pointDrawMode) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + cullMode = D3D11_CULL_NONE; } - gl::DepthStencilState glState = originalState; - if (disableDepth) + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = cullMode; + rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE : TRUE; + rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of + // zero will preform no clamping, must be tested though. + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; + rasterDesc.MultisampleEnable = rasterState.multiSample; + rasterDesc.AntialiasedLineEnable = FALSE; + + if (rasterState.polygonOffsetFill) { - glState.depthTest = false; - glState.depthMask = false; + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; } - - if (disableStencil) + else { - glState.stencilWritemask = 0; - glState.stencilBackWritemask = 0; - glState.stencilTest = false; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; } - auto keyIter = mDepthStencilStateCache.find(glState); + d3d11::RasterizerState dx11RasterizerState; + ANGLE_TRY(renderer->allocateResource(rasterDesc, &dx11RasterizerState)); + *outRasterizerState = dx11RasterizerState.get(); + mRasterizerStateCache.Put(key, std::move(dx11RasterizerState)); + + return gl::NoError(); +} + +gl::Error RenderStateCache::getDepthStencilState(Renderer11 *renderer, + const gl::DepthStencilState &glState, + const d3d11::DepthStencilState **outDSState) +{ + auto keyIter = mDepthStencilStateCache.Get(glState); if (keyIter != mDepthStencilStateCache.end()) { - DepthStencilStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outDSState = state.first; - return gl::Error(GL_NO_ERROR); + *outDSState = &keyIter->second; + return gl::NoError(); } - if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) - { - TRACE( - "Overflowed the limit of %u depth stencil states, removing the least recently used " - "to make room.", - kMaxDepthStencilStates); - - auto leastRecentlyUsed = mDepthStencilStateCache.begin(); - for (auto i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mDepthStencilStateCache.erase(leastRecentlyUsed); - } + TrimCache(kMaxStates, kGCLimit, "depth stencil state", &mDepthStencilStateCache); D3D11_DEPTH_STENCIL_DESC dsDesc = {0}; dsDesc.DepthEnable = glState.depthTest ? TRUE : FALSE; @@ -366,107 +208,66 @@ gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &or 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); - } + d3d11::DepthStencilState dx11DepthStencilState; + ANGLE_TRY(renderer->allocateResource(dsDesc, &dx11DepthStencilState)); + const auto &iter = mDepthStencilStateCache.Put(glState, std::move(dx11DepthStencilState)); - mDepthStencilStateCache.insert( - std::make_pair(glState, std::make_pair(dx11DepthStencilState, mCounter++))); + *outDSState = &iter->second; - *outDSState = dx11DepthStencilState; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) +gl::Error RenderStateCache::getSamplerState(Renderer11 *renderer, + const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState) { - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); - return hash; -} - -bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) -{ - return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; -} - -gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState) -{ - if (!mDevice) + auto keyIter = mSamplerStateCache.Get(samplerState); + if (keyIter != mSamplerStateCache.end()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + *outSamplerState = keyIter->second.get(); + return gl::NoError(); } - SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); - if (keyIter != mSamplerStateCache.end()) + TrimCache(kMaxStates, kGCLimit, "sampler state", &mSamplerStateCache); + + const auto &featureLevel = renderer->getRenderer11DeviceCaps().featureLevel; + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = + gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, + samplerState.maxAnisotropy, samplerState.compareMode); + samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); + samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); + samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); + samplerDesc.MipLODBias = 0; + samplerDesc.MaxAnisotropy = + gl_d3d11::ConvertMaxAnisotropy(samplerState.maxAnisotropy, featureLevel); + samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = samplerState.minLod; + samplerDesc.MaxLOD = samplerState.maxLod; + + if (featureLevel <= D3D_FEATURE_LEVEL_9_3) { - SamplerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outSamplerState = state.first; - return gl::Error(GL_NO_ERROR); + // 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. + ASSERT(samplerState.maxLod >= 999.9f); + + // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD + // workaround) should take account of this. + samplerDesc.MaxLOD = FLT_MAX; } - else - { - if (mSamplerStateCache.size() >= kMaxSamplerStates) - { - TRACE("Overflowed the limit of %u sampler states, removing the least recently used " - "to make room.", kMaxSamplerStates); - - SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); - for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mSamplerStateCache.erase(leastRecentlyUsed); - } - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, - samplerState.maxAnisotropy, samplerState.compareMode); - samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); - samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); - samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); - samplerDesc.MipLODBias = 0; - samplerDesc.MaxAnisotropy = static_cast(samplerState.maxAnisotropy); - samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = samplerState.minLod; - samplerDesc.MaxLOD = samplerState.maxLod; - - 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. - ASSERT(samplerState.maxLod >= 999.9f); - - // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD workaround) should take account of this. - samplerDesc.MaxLOD = FLT_MAX; - } + d3d11::SamplerState dx11SamplerState; + ANGLE_TRY(renderer->allocateResource(samplerDesc, &dx11SamplerState)); + *outSamplerState = dx11SamplerState.get(); + mSamplerStateCache.Put(samplerState, std::move(dx11SamplerState)); - ID3D11SamplerState *dx11SamplerState = NULL; - HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); - if (FAILED(result) || !dx11SamplerState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11SamplerState, HRESULT: 0x%X.", result); - } - - mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); - - *outSamplerState = dx11SamplerState; - return gl::Error(GL_NO_ERROR); - } + return gl::NoError(); } -} +} // namespace rx 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 82cb13903c..7501e83fc4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h @@ -10,9 +10,11 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ #define LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ -#include "libANGLE/angletypes.h" -#include "libANGLE/Error.h" #include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/SizedMRUCache.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include @@ -21,6 +23,42 @@ namespace gl class Framebuffer; } +namespace std +{ +template <> +struct hash +{ + size_t operator()(const rx::d3d11::BlendStateKey &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const rx::d3d11::RasterizerStateKey &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const gl::DepthStencilState &key) const + { + return angle::ComputeGenericHash(key); + } +}; + +template <> +struct hash +{ + size_t operator()(const gl::SamplerState &key) const { return angle::ComputeGenericHash(key); } +}; +} // namespace std + namespace rx { class Renderer11; @@ -28,87 +66,58 @@ class Renderer11; class RenderStateCache : angle::NonCopyable { public: - RenderStateCache(Renderer11 *renderer); + RenderStateCache(); virtual ~RenderStateCache(); - void initialize(ID3D11Device *device); void clear(); - 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, - bool disableDepth, - bool disableStencil, - ID3D11DepthStencilState **outDSState); - gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState); + static d3d11::BlendStateKey GetBlendStateKey(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState); + gl::Error getBlendState(Renderer11 *renderer, + const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState); + gl::Error getRasterizerState(Renderer11 *renderer, + const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(Renderer11 *renderer, + const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState); + gl::Error getSamplerState(Renderer11 *renderer, + const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState); private: - Renderer11 *mRenderer; - unsigned long long mCounter; + // MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, + // ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum + // number of unique states of each type an application can create is 4096 + // TODO(ShahmeerEsmail): Revisit the cache sizes to make sure they are appropriate for most + // scenarios. + static constexpr unsigned int kMaxStates = 4096; + + // The cache tries to clean up this many states at once. + static constexpr unsigned int kGCLimit = 128; // Blend state cache - struct BlendStateKey - { - gl::BlendState blendState; - bool rtChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; - }; - static std::size_t hashBlendState(const BlendStateKey &blendState); - static bool compareBlendStates(const BlendStateKey &a, const BlendStateKey &b); - static const unsigned int kMaxBlendStates; - - typedef std::size_t (*BlendStateHashFunction)(const BlendStateKey &); - typedef bool (*BlendStateEqualityFunction)(const BlendStateKey &, const BlendStateKey &); - typedef std::pair BlendStateCounterPair; - typedef std::unordered_map BlendStateMap; + using BlendStateMap = angle::base::HashingMRUCache; BlendStateMap mBlendStateCache; // Rasterizer state cache - struct RasterizerStateKey - { - gl::RasterizerState rasterizerState; - bool scissorEnabled; - }; - static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); - static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); - static const unsigned int kMaxRasterizerStates; - - typedef std::size_t (*RasterizerStateHashFunction)(const RasterizerStateKey &); - typedef bool (*RasterizerStateEqualityFunction)(const RasterizerStateKey &, const RasterizerStateKey &); - typedef std::pair RasterizerStateCounterPair; - typedef std::unordered_map RasterizerStateMap; + using RasterizerStateMap = + angle::base::HashingMRUCache; RasterizerStateMap mRasterizerStateCache; // Depth stencil state cache - static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState); - static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b); - static const unsigned int kMaxDepthStencilStates; - - typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &); - typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &); - typedef std::pair DepthStencilStateCounterPair; - typedef std::unordered_map DepthStencilStateMap; + using DepthStencilStateMap = + angle::base::HashingMRUCache; DepthStencilStateMap mDepthStencilStateCache; // Sample state cache - static std::size_t hashSamplerState(const gl::SamplerState &samplerState); - static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b); - static const unsigned int kMaxSamplerStates; - - typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &); - typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &); - typedef std::pair SamplerStateCounterPair; - typedef std::unordered_map SamplerStateMap; + using SamplerStateMap = angle::base::HashingMRUCache; SamplerStateMap mSamplerStateCache; - - ID3D11Device *mDevice; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ 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 cdfcacc287..594a382a72 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp @@ -18,7 +18,9 @@ namespace rx { -static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +namespace +{ +bool GetTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) { ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject(resource); if (texture1D) @@ -62,7 +64,7 @@ static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLeve return false; } -static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) +unsigned int GetRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; view->GetDesc(&rtvDesc); @@ -72,58 +74,58 @@ static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11Rende switch (rtvDesc.ViewDimension) { - case D3D11_RTV_DIMENSION_TEXTURE1D: - mipSlice = rtvDesc.Texture1D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: - mipSlice = rtvDesc.Texture1DArray.MipSlice; - arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2D: - mipSlice = rtvDesc.Texture2D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: - mipSlice = rtvDesc.Texture2DArray.MipSlice; - arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DMS: - mipSlice = 0; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: - mipSlice = 0; - arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE3D: - mipSlice = rtvDesc.Texture3D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_UNKNOWN: - case D3D11_RTV_DIMENSION_BUFFER: - UNIMPLEMENTED(); - break; - - default: - UNREACHABLE(); - break; + case D3D11_RTV_DIMENSION_TEXTURE1D: + mipSlice = rtvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + mipSlice = rtvDesc.Texture1DArray.MipSlice; + arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + mipSlice = rtvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + mipSlice = rtvDesc.Texture2DArray.MipSlice; + arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + mipSlice = rtvDesc.Texture3D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + case D3D11_RTV_DIMENSION_BUFFER: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; } unsigned int mipLevels, samples; - getTextureProperties(resource, &mipLevels, &samples); + GetTextureProperties(resource, &mipLevels, &samples); return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) +unsigned int GetDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; view->GetDesc(&dsvDesc); @@ -133,157 +135,170 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth switch (dsvDesc.ViewDimension) { - case D3D11_DSV_DIMENSION_TEXTURE1D: - mipSlice = dsvDesc.Texture1D.MipSlice; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: - mipSlice = dsvDesc.Texture1DArray.MipSlice; - arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2D: - mipSlice = dsvDesc.Texture2D.MipSlice; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: - mipSlice = dsvDesc.Texture2DArray.MipSlice; - arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DMS: - mipSlice = 0; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: - mipSlice = 0; - arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_UNKNOWN: - UNIMPLEMENTED(); - break; - - default: - UNREACHABLE(); - break; + case D3D11_DSV_DIMENSION_TEXTURE1D: + mipSlice = dsvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + mipSlice = dsvDesc.Texture1DArray.MipSlice; + arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2D: + mipSlice = dsvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + mipSlice = dsvDesc.Texture2DArray.MipSlice; + arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_UNKNOWN: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; } unsigned int mipLevels, samples; - getTextureProperties(resource, &mipLevels, &samples); + GetTextureProperties(resource, &mipLevels, &samples); return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), +GLenum GetSurfaceRTFormat(bool depth, SwapChain11 *swapChain) +{ + return (depth ? swapChain->getDepthBufferInternalFormat() + : swapChain->getRenderTargetInternalFormat()); +} + +const d3d11::Format &GetSurfaceFormatSet(bool depth, SwapChain11 *swapChain, Renderer11 *renderer) +{ + return d3d11::Format::Get(GetSurfaceRTFormat(depth, swapChain), + renderer->getRenderer11DeviceCaps()); +} + +} // anonymous namespace + +RenderTarget11::RenderTarget11(const d3d11::Format &formatSet) : mFormatSet(formatSet) +{ +} + +RenderTarget11::~RenderTarget11() +{ + ASSERT(mBroadcastChannel.empty()); +} + +void RenderTarget11::signalDirty(const gl::Context *context) +{ + mBroadcastChannel.signal(context); + + // Clear the list. We can't do this in the receiver because it would mutate during iteration. + mBroadcastChannel.reset(); +} + +TextureRenderTarget11::TextureRenderTarget11(d3d11::RenderTargetView &&rtv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + const d3d11::SharedSRV &blitSRV, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples) + : RenderTarget11(formatSet), + mWidth(width), mHeight(height), mDepth(depth), mInternalFormat(internalFormat), - mDXGIFormat(DXGI_FORMAT_UNKNOWN), mSamples(samples), mSubresourceIndex(0), mTexture(resource), - mRenderTarget(rtv), - mDepthStencil(NULL), - mShaderResource(srv) + mRenderTarget(std::move(rtv)), + mDepthStencil(), + mShaderResource(srv.makeCopy()), + mBlitShaderResource(blitSRV.makeCopy()) { - if (mTexture) - { - mTexture->AddRef(); - } - - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - if (mRenderTarget && mTexture) + if (mRenderTarget.valid() && mTexture.valid()) { - mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); - - D3D11_RENDER_TARGET_VIEW_DESC desc; - mRenderTarget->GetDesc(&desc); - mDXGIFormat = desc.Format; + mSubresourceIndex = GetRTVSubresourceIndex(mTexture.get(), mRenderTarget.get()); } + ASSERT(mFormatSet.formatID != angle::Format::ID::NONE || mWidth == 0 || mHeight == 0); } -TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), +TextureRenderTarget11::TextureRenderTarget11(d3d11::DepthStencilView &&dsv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples) + : RenderTarget11(formatSet), + mWidth(width), mHeight(height), mDepth(depth), mInternalFormat(internalFormat), - mDXGIFormat(DXGI_FORMAT_UNKNOWN), mSamples(samples), mSubresourceIndex(0), mTexture(resource), - mRenderTarget(NULL), - mDepthStencil(dsv), - mShaderResource(srv) + mRenderTarget(), + mDepthStencil(std::move(dsv)), + mShaderResource(srv.makeCopy()), + mBlitShaderResource() { - if (mTexture) + if (mDepthStencil.valid() && mTexture.valid()) { - mTexture->AddRef(); - } - - if (mDepthStencil) - { - mDepthStencil->AddRef(); - } - - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - if (mDepthStencil && mTexture) - { - mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); - - D3D11_DEPTH_STENCIL_VIEW_DESC desc; - mDepthStencil->GetDesc(&desc); - mDXGIFormat = desc.Format; + mSubresourceIndex = GetDSVSubresourceIndex(mTexture.get(), mDepthStencil.get()); } + ASSERT(mFormatSet.formatID != angle::Format::ID::NONE || mWidth == 0 || mHeight == 0); } TextureRenderTarget11::~TextureRenderTarget11() { - SafeRelease(mTexture); - SafeRelease(mRenderTarget); - SafeRelease(mDepthStencil); - SafeRelease(mShaderResource); } -ID3D11Resource *TextureRenderTarget11::getTexture() const +const TextureHelper11 &TextureRenderTarget11::getTexture() const { return mTexture; } -ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const +const d3d11::RenderTargetView &TextureRenderTarget11::getRenderTargetView() const { return mRenderTarget; } -ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const +const d3d11::DepthStencilView &TextureRenderTarget11::getDepthStencilView() const { return mDepthStencil; } -ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const +const d3d11::SharedSRV &TextureRenderTarget11::getShaderResourceView() const { return mShaderResource; } +const d3d11::SharedSRV &TextureRenderTarget11::getBlitShaderResourceView() const +{ + return mBlitShaderResource; +} + GLsizei TextureRenderTarget11::getWidth() const { return mWidth; @@ -314,14 +329,11 @@ unsigned int TextureRenderTarget11::getSubresourceIndex() const return mSubresourceIndex; } -DXGI_FORMAT TextureRenderTarget11::getDXGIFormat() const -{ - return mDXGIFormat; -} - -SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth) - : mSwapChain(swapChain), - mRenderer(renderer), +SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, + Renderer11 *renderer, + bool depth) + : RenderTarget11(GetSurfaceFormatSet(depth, swapChain, renderer)), + mSwapChain(swapChain), mDepth(depth) { ASSERT(mSwapChain); @@ -348,43 +360,46 @@ GLsizei SurfaceRenderTarget11::getDepth() const GLenum SurfaceRenderTarget11::getInternalFormat() const { - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat()); + return GetSurfaceRTFormat(mDepth, mSwapChain); } GLsizei SurfaceRenderTarget11::getSamples() const { - // Our EGL surfaces do not support multisampling. - return 0; + return mSwapChain->getSamples(); } -ID3D11Resource *SurfaceRenderTarget11::getTexture() const +const TextureHelper11 &SurfaceRenderTarget11::getTexture() const { return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); } -ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const +const d3d11::RenderTargetView &SurfaceRenderTarget11::getRenderTargetView() const { - return (mDepth ? NULL : mSwapChain->getRenderTarget()); + ASSERT(!mDepth); + return mSwapChain->getRenderTarget(); } -ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const +const d3d11::DepthStencilView &SurfaceRenderTarget11::getDepthStencilView() const { - return (mDepth ? mSwapChain->getDepthStencil() : NULL); + ASSERT(mDepth); + return mSwapChain->getDepthStencil(); } -ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const +const d3d11::SharedSRV &SurfaceRenderTarget11::getShaderResourceView() const { - return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); + return (mDepth ? mSwapChain->getDepthStencilShaderResource() + : mSwapChain->getRenderTargetShaderResource()); } -unsigned int SurfaceRenderTarget11::getSubresourceIndex() const +const d3d11::SharedSRV &SurfaceRenderTarget11::getBlitShaderResourceView() const { - return 0; + // The SurfaceRenderTargetView format should always be such that the normal SRV works for blits. + return getShaderResourceView(); } -DXGI_FORMAT SurfaceRenderTarget11::getDXGIFormat() const +unsigned int SurfaceRenderTarget11::getSubresourceIndex() const { - return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getRenderer11DeviceCaps()).texFormat; + return 0; } -} +} // namespace rx 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 d47b237c09..db49cac9f5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h @@ -11,6 +11,9 @@ #define LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" namespace rx { @@ -20,28 +23,51 @@ class Renderer11; class RenderTarget11 : public RenderTargetD3D { public: - RenderTarget11() { } - virtual ~RenderTarget11() { } + RenderTarget11(const d3d11::Format &formatSet); + ~RenderTarget11() override; - virtual ID3D11Resource *getTexture() const = 0; - virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; - virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; - virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; + virtual const TextureHelper11 &getTexture() const = 0; + virtual const d3d11::RenderTargetView &getRenderTargetView() const = 0; + virtual const d3d11::DepthStencilView &getDepthStencilView() const = 0; + virtual const d3d11::SharedSRV &getShaderResourceView() const = 0; + virtual const d3d11::SharedSRV &getBlitShaderResourceView() const = 0; virtual unsigned int getSubresourceIndex() const = 0; - virtual DXGI_FORMAT getDXGIFormat() const = 0; + void signalDirty(const gl::Context *context) override; + OnRenderTargetDirtyChannel *getBroadcastChannel() { return &mBroadcastChannel; } + + const d3d11::Format &getFormatSet() const { return mFormatSet; } + + protected: + OnRenderTargetDirtyChannel mBroadcastChannel; + const d3d11::Format &mFormatSet; }; class TextureRenderTarget11 : public RenderTarget11 { public: // TextureRenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them - TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); - TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); - virtual ~TextureRenderTarget11(); + TextureRenderTarget11(d3d11::RenderTargetView &&rtv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + const d3d11::SharedSRV &blitSRV, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples); + TextureRenderTarget11(d3d11::DepthStencilView &&dsv, + const TextureHelper11 &resource, + const d3d11::SharedSRV &srv, + GLenum internalFormat, + const d3d11::Format &formatSet, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei samples); + ~TextureRenderTarget11() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -49,35 +75,37 @@ class TextureRenderTarget11 : public RenderTarget11 GLenum getInternalFormat() const override; GLsizei getSamples() const override; - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; + const TextureHelper11 &getTexture() const override; + const d3d11::RenderTargetView &getRenderTargetView() const override; + const d3d11::DepthStencilView &getDepthStencilView() const override; + const d3d11::SharedSRV &getShaderResourceView() const override; + const d3d11::SharedSRV &getBlitShaderResourceView() const override; unsigned int getSubresourceIndex() const override; - DXGI_FORMAT getDXGIFormat() const override; - private: GLsizei mWidth; GLsizei mHeight; GLsizei mDepth; GLenum mInternalFormat; - DXGI_FORMAT mDXGIFormat; GLsizei mSamples; unsigned int mSubresourceIndex; - ID3D11Resource *mTexture; - ID3D11RenderTargetView *mRenderTarget; - ID3D11DepthStencilView *mDepthStencil; - ID3D11ShaderResourceView *mShaderResource; + TextureHelper11 mTexture; + d3d11::RenderTargetView mRenderTarget; + d3d11::DepthStencilView mDepthStencil; + d3d11::SharedSRV mShaderResource; + + // Shader resource view to use with internal blit shaders. Not set for depth/stencil render + // targets. + d3d11::SharedSRV mBlitShaderResource; }; class SurfaceRenderTarget11 : public RenderTarget11 { public: SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth); - virtual ~SurfaceRenderTarget11(); + ~SurfaceRenderTarget11() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -85,21 +113,19 @@ class SurfaceRenderTarget11 : public RenderTarget11 GLenum getInternalFormat() const override; GLsizei getSamples() const override; - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; + const TextureHelper11 &getTexture() const override; + const d3d11::RenderTargetView &getRenderTargetView() const override; + const d3d11::DepthStencilView &getDepthStencilView() const override; + const d3d11::SharedSRV &getShaderResourceView() const override; + const d3d11::SharedSRV &getBlitShaderResourceView() const override; unsigned int getSubresourceIndex() const override; - DXGI_FORMAT getDXGIFormat() const override; - private: SwapChain11 *mSwapChain; - Renderer11 *mRenderer; bool mDepth; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ 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 5118bdbe9c..b0ef9abddc 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -9,56 +9,64 @@ #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include +#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/Context.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/histogram_macros.h" #include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/DeviceD3D.h" +#include "libANGLE/renderer/d3d/DisplayD3D.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/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/Context11.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/StreamProducerNV12.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/TransformFeedback11.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/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 "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include "libANGLE/renderer/renderer_utils.h" #include "third_party/trace_event/trace_event.h" +#ifdef ANGLE_ENABLE_WINDOWS_STORE +#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" +#else +#include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h" +#endif + // 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. @@ -72,12 +80,6 @@ #define ANGLE_SKIP_DXGI_1_2_CHECK 0 #endif -#ifdef _DEBUG -// this flag enables suppressing some spurious warnings that pop up in certain WebGL samples -// and conformance tests. to enable all warnings, remove this define. -#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 -#endif - namespace rx { @@ -89,25 +91,6 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 }; -#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 - enum ANGLEFeatureLevel { ANGLE_FEATURE_LEVEL_INVALID, @@ -123,14 +106,18 @@ ANGLEFeatureLevel GetANGLEFeatureLevel(D3D_FEATURE_LEVEL d3dFeatureLevel) { switch (d3dFeatureLevel) { - 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; + 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; + case D3D_FEATURE_LEVEL_11_1: + return ANGLE_FEATURE_LEVEL_11_1; + default: + return ANGLE_FEATURE_LEVEL_INVALID; } } @@ -144,7 +131,7 @@ void SetLineLoopIndices(GLuint *dest, size_t count) } template -void CopyLineLoopIndices(const GLvoid *indices, GLuint *dest, size_t count) +void CopyLineLoopIndices(const void *indices, GLuint *dest, size_t count) { const T *srcPtr = static_cast(indices); for (size_t i = 0; i < count; ++i) @@ -165,7 +152,7 @@ void SetTriangleFanIndices(GLuint *destPtr, size_t numTris) } template -void CopyLineLoopIndicesWithRestart(const GLvoid *indices, +void CopyLineLoopIndicesWithRestart(const void *indices, size_t count, GLenum indexType, std::vector *bufferOut) @@ -206,7 +193,7 @@ void CopyLineLoopIndicesWithRestart(const GLvoid *indices, } } -void GetLineLoopIndices(const GLvoid *indices, +void GetLineLoopIndices(const void *indices, GLenum indexType, GLuint count, bool usePrimitiveRestartFixedIndex, @@ -257,7 +244,7 @@ void GetLineLoopIndices(const GLvoid *indices, } template -void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris) +void CopyTriangleFanIndices(const void *indices, GLuint *destPtr, size_t numTris) { const T *srcPtr = static_cast(indices); @@ -270,7 +257,7 @@ void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTr } template -void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, +void CopyTriangleFanIndicesWithRestart(const void *indices, GLuint indexCount, GLenum indexType, std::vector *bufferOut) @@ -314,7 +301,7 @@ void CopyTriangleFanIndicesWithRestart(const GLvoid *indices, } } -void GetTriFanIndices(const GLvoid *indices, +void GetTriFanIndices(const void *indices, GLenum indexType, GLuint count, bool usePrimitiveRestartFixedIndex, @@ -365,60 +352,135 @@ void GetTriFanIndices(const GLvoid *indices, } } +bool DrawCallNeedsTranslation(const gl::Context *context, GLenum mode) +{ + const auto &glState = context->getGLState(); + const gl::VertexArray *vertexArray = glState.getVertexArray(); + VertexArray11 *vertexArray11 = GetImplAs(vertexArray); + // Direct drawing doesn't support dynamic attribute storage since it needs the first and count + // to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported + // either since we need to simulate them in D3D. + if (vertexArray11->hasActiveDynamicAttrib(context) || mode == GL_LINE_LOOP || + mode == GL_TRIANGLE_FAN) + { + return true; + } + + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + if (InstancedPointSpritesActive(programD3D, mode)) + { + return true; + } + + return false; +} + +bool IsArrayRTV(ID3D11RenderTargetView *rtv) +{ + D3D11_RENDER_TARGET_VIEW_DESC desc; + rtv->GetDesc(&desc); + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE1DARRAY && + desc.Texture1DArray.ArraySize > 1) + return true; + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DARRAY && + desc.Texture2DArray.ArraySize > 1) + return true; + if (desc.ViewDimension == D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY && + desc.Texture2DMSArray.ArraySize > 1) + return true; + return false; +} + +int GetAdjustedInstanceCount(const gl::Program *program, int instanceCount) +{ + if (!program->usesMultiview()) + { + return instanceCount; + } + if (instanceCount == 0) + { + return program->getNumViews(); + } + return program->getNumViews() * instanceCount; +} + +const uint32_t ScratchMemoryBufferLifetime = 1000; + +void PopulateFormatDeviceCaps(ID3D11Device *device, + DXGI_FORMAT format, + UINT *outSupport, + UINT *outMaxSamples) +{ + if (FAILED(device->CheckFormatSupport(format, outSupport))) + { + *outSupport = 0; + } + + *outMaxSamples = 0; + for (UINT sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount *= 2) + { + UINT qualityCount = 0; + if (FAILED(device->CheckMultisampleQualityLevels(format, sampleCount, &qualityCount)) || + qualityCount == 0) + { + break; + } + + *outMaxSamples = sampleCount; + } +} + +bool CullsEverything(const gl::State &glState) +{ + return (glState.getRasterizerState().cullFace && + glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack); +} + } // anonymous namespace +Renderer11DeviceCaps::Renderer11DeviceCaps() = default; + Renderer11::Renderer11(egl::Display *display) : RendererD3D(display), - mStateCache(this), + mCreateDebugDevice(false), + mStateCache(), mStateManager(this), - mLastHistogramUpdateTime(ANGLEPlatformCurrent()->monotonicallyIncreasingTime()) -#if !defined(ANGLE_MINGW32_COMPAT) - ,mDebug(nullptr) -#endif + mLastHistogramUpdateTime( + ANGLEPlatformCurrent()->monotonicallyIncreasingTime(ANGLEPlatformCurrent())), + mDebug(nullptr), + mScratchMemoryBuffer(ScratchMemoryBufferLifetime), + mAnnotator(nullptr) { - mVertexDataManager = NULL; - mIndexDataManager = NULL; - - mLineLoopIB = NULL; - mTriangleFanIB = NULL; - mAppliedIBChanged = false; + mLineLoopIB = nullptr; + mTriangleFanIB = nullptr; - mBlit = NULL; - mPixelTransfer = NULL; + mBlit = nullptr; + mPixelTransfer = nullptr; - mClear = NULL; + mClear = nullptr; - mTrim = NULL; + mTrim = nullptr; - mSyncQuery = NULL; - - mRenderer11DeviceCaps.supportsClearView = 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; + mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader = false; + mRenderer11DeviceCaps.supportsDXGI1_2 = false; + mRenderer11DeviceCaps.B5G6R5support = 0; + mRenderer11DeviceCaps.B4G4R4A4support = 0; + mRenderer11DeviceCaps.B5G5R5A1support = 0; + + mD3d11Module = nullptr; + mDxgiModule = nullptr; + mDCompModule = nullptr; mCreatedWithDeviceEXT = false; mEGLDevice = nullptr; - mDevice = NULL; - mDeviceContext = NULL; - mDeviceContext1 = NULL; - mDxgiAdapter = NULL; - mDxgiFactory = NULL; - - mDriverConstantBufferVS = NULL; - mDriverConstantBufferPS = NULL; - - mAppliedVertexShader = NULL; - mAppliedGeometryShader = NULL; - mAppliedPixelShader = NULL; - - mAppliedNumXFBBindings = static_cast(-1); + mDevice = nullptr; + mDeviceContext = nullptr; + mDeviceContext1 = nullptr; + mDeviceContext3 = nullptr; + mDxgiAdapter = nullptr; + mDxgiFactory = nullptr; ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription)); @@ -426,13 +488,21 @@ Renderer11::Renderer11(egl::Display *display) { 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); + EGLint requestedMajorVersion = static_cast( + attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)); + EGLint requestedMinorVersion = static_cast( + attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)); if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + // This could potentially lead to failed context creation if done on a system + // without the platform update which installs DXGI 1.2. Currently, for Chrome users + // D3D11 contexts are only created if the platform update is available, so this + // should not cause any issues. + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_1); + } if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) { mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); @@ -451,11 +521,7 @@ Renderer11::Renderer11(egl::Display *display) } } -#if defined(ANGLE_ENABLE_WINDOWS_STORE) - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) -#else if (requestedMajorVersion == 9 && requestedMinorVersion == 3) -#endif { if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) { @@ -473,8 +539,8 @@ Renderer11::Renderer11(egl::Display *display) #endif } - EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + EGLint requestedDeviceType = static_cast(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: @@ -497,9 +563,11 @@ Renderer11::Renderer11(egl::Display *display) UNREACHABLE(); } - const EGLenum presentPath = attributes.get(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, - EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE); + const EGLenum presentPath = static_cast(attributes.get( + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE)); mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE); + + mCreateDebugDevice = ShouldUseDebugLayers(attributes); } else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT) { @@ -509,11 +577,22 @@ Renderer11::Renderer11(egl::Display *display) // Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE // mAvailableFeatureLevels defaults to empty - mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN; + mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN; mPresentPathFastEnabled = false; } - initializeDebugAnnotator(); +// 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(mAnnotator); + gl::InitializeDebugAnnotations(mAnnotator); } Renderer11::~Renderer11() @@ -529,20 +608,17 @@ egl::Error Renderer11::initialize() { HRESULT result = S_OK; - egl::Error error = initializeD3DDevice(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initializeD3DDevice()); #if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if !ANGLE_SKIP_DXGI_1_2_CHECK { 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. + // 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()); + HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId()); if (hwnd) { DWORD currentProcessId = GetCurrentProcessId(); @@ -557,13 +633,12 @@ egl::Error Renderer11::initialize() if (requireDXGI1_2) { - IDXGIDevice2 *dxgiDevice2 = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + IDXGIDevice2 *dxgiDevice2 = nullptr; + 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."); + return egl::EglNotInitialized(D3D11_INIT_INCOMPATIBLE_DXGI) + << "DXGI 1.2 required to present to HWNDs owned by another process."; } SafeRelease(dxgiDevice2); } @@ -573,90 +648,83 @@ egl::Error Renderer11::initialize() { TRACE_EVENT0("gpu.angle", "Renderer11::initialize (ComQueries)"); - // Cast the DeviceContext to a DeviceContext1. + // Cast the DeviceContext to a DeviceContext1 and DeviceContext3. // 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) + // Don't error in this case- just don't use mDeviceContext1 or mDeviceContext3. mDeviceContext1 = d3d11::DynamicCastComObject(mDeviceContext); -#endif + mDeviceContext3 = d3d11::DynamicCastComObject(mDeviceContext); - IDXGIDevice *dxgiDevice = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); + IDXGIDevice *dxgiDevice = nullptr; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice); if (FAILED(result)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not query DXGI device."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) << "Could not query DXGI device."; } - result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&mDxgiAdapter); if (FAILED(result)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not retrieve DXGI adapter"); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) + << "Could not retrieve DXGI adapter"; } SafeRelease(dxgiDevice); -#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) + // 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 != nullptr) { DXGI_ADAPTER_DESC2 adapterDesc2 = {}; - result = dxgiAdapter2->GetDesc2(&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; + // 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; + mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory; + mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid; } } else -#endif { result = mDxgiAdapter->GetDesc(&mAdapterDescription); } -#if defined(ANGLE_ENABLE_D3D11_1) SafeRelease(dxgiAdapter2); -#endif if (FAILED(result)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not read DXGI adaptor description."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) + << "Could not read DXGI adaptor description."; } memset(mDescription, 0, sizeof(mDescription)); wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); - result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); + result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&mDxgiFactory); if (!mDxgiFactory || FAILED(result)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D11_INIT_OTHER_ERROR, - "Could not create DXGI factory."); + return egl::EglNotInitialized(D3D11_INIT_OTHER_ERROR) + << "Could not create DXGI factory."; } } -#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) + if (mCreateDebugDevice) { TRACE_EVENT0("gpu.angle", "Renderer11::initialize (HideWarnings)"); ID3D11InfoQueue *infoQueue; @@ -664,29 +732,33 @@ egl::Error Renderer11::initialize() if (SUCCEEDED(result)) { - D3D11_MESSAGE_ID hideMessages[] = - { - D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET - }; + D3D11_MESSAGE_ID hideMessages[] = { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET}; D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = static_cast(ArraySize(hideMessages)); - filter.DenyList.pIDList = hideMessages; + filter.DenyList.pIDList = hideMessages; infoQueue->AddStorageFilterEntries(&filter); SafeRelease(infoQueue); } } -#endif #if !defined(NDEBUG) mDebug = d3d11::DynamicCastComObject(mDevice); #endif -#endif // !ANGLE_MINGW32_COMPAT - initializeDevice(); + ANGLE_TRY(initializeDevice()); + + return egl::NoError(); +} - return egl::Error(EGL_SUCCESS); +HRESULT Renderer11::callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice, bool debug) +{ + return createDevice( + nullptr, mRequestedDriverType, nullptr, debug ? D3D11_CREATE_DEVICE_DEBUG : 0, + mAvailableFeatureLevels.data(), static_cast(mAvailableFeatureLevels.size()), + D3D11_SDK_VERSION, &mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext); } egl::Error Renderer11::initializeD3DDevice() @@ -706,8 +778,8 @@ egl::Error Renderer11::initializeD3DDevice() if (mD3d11Module == nullptr || mDxgiModule == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, - "Could not load D3D11 or DXGI library."); + return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP) + << "Could not load D3D11 or DXGI library."; } // create the D3D11 device @@ -717,68 +789,76 @@ egl::Error Renderer11::initializeD3DDevice() if (D3D11CreateDevice == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP, - "Could not retrieve D3D11CreateDevice address."); + return egl::EglNotInitialized(D3D11_INIT_MISSING_DEP) + << "Could not retrieve D3D11CreateDevice address."; } } #endif -#ifdef _DEBUG + if (mCreateDebugDevice) { 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); - } + result = callD3D11CreateDevice(D3D11CreateDevice, true); - if (!mDevice || FAILED(result)) - { - ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); + if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u && + mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1) + { + // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG. + // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature + // levels to fall back on. + mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin()); + result = callD3D11CreateDevice(D3D11CreateDevice, true); + } + + if (!mDevice || FAILED(result)) + { + WARN() << "Failed creating Debug D3D11 device - falling back to release runtime."; + } } 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); + result = callD3D11CreateDevice(D3D11CreateDevice, false); + + if (result == E_INVALIDARG && mAvailableFeatureLevels.size() > 1u && + mAvailableFeatureLevels[0] == D3D_FEATURE_LEVEL_11_1) + { + // On older Windows platforms, D3D11.1 is not supported which returns E_INVALIDARG. + // Try again without passing D3D_FEATURE_LEVEL_11_1 in case we have other feature + // levels to fall back on. + mAvailableFeatureLevels.erase(mAvailableFeatureLevels.begin()); + result = callD3D11CreateDevice(D3D11CreateDevice, false); + } // 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."); + return egl::EglNotInitialized(D3D11_INIT_CREATEDEVICE_ERROR) + << "Could not create D3D11 device."; } } } else { // We should use the inputted D3D11 device instead - void *device = nullptr; - egl::Error error = mEGLDevice->getDevice(&device); - if (error.isError()) - { - return error; - } + void *device = nullptr; + ANGLE_TRY(mEGLDevice->getDevice(&device)); ID3D11Device *d3dDevice = reinterpret_cast(device); if (FAILED(d3dDevice->GetDeviceRemovedReason())) { - return egl::Error(EGL_NOT_INITIALIZED, "Inputted D3D11 device has been lost."); + return egl::EglNotInitialized() << "Inputted D3D11 device has been lost."; } 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."); + return egl::EglNotInitialized() + << "Inputted D3D11 device must be Feature Level 9_3 or greater."; } // The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does. @@ -788,27 +868,24 @@ egl::Error Renderer11::initializeD3DDevice() mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel(); } + mResourceManager11.setAllocationsInitialized(mCreateDebugDevice); + d3d11::SetDebugName(mDeviceContext, "DeviceContext"); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } // do any one-time device initialization // NOTE: this is also needed after a device lost/reset // to reset the scene status and ensure the default states are reset. -void Renderer11::initializeDevice() +egl::Error Renderer11::initializeDevice() { SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDeviceMS"); TRACE_EVENT0("gpu.angle", "Renderer11::initializeDevice"); populateRenderer11DeviceCaps(); - mStateCache.initialize(mDevice); - mInputLayoutCache.initialize(mDevice, mDeviceContext); - - ASSERT(!mVertexDataManager && !mIndexDataManager); - mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this, getRendererClass()); + mStateCache.clear(); ASSERT(!mBlit); mBlit = new Blit11(this); @@ -820,7 +897,8 @@ void Renderer11::initializeDevice() // If automatic trim is enabled, DXGIDevice3::Trim( ) is called for the application // automatically when an application is suspended by the OS. This feature is currently // only supported for Windows Store applications. - EGLint enableAutoTrim = attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE); + EGLint enableAutoTrim = static_cast( + attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE)); if (enableAutoTrim == EGL_TRUE) { @@ -831,19 +909,12 @@ void Renderer11::initializeDevice() ASSERT(!mPixelTransfer); mPixelTransfer = new PixelTransfer11(this); - const gl::Caps &rendererCaps = getRendererCaps(); - - mStateManager.initialize(rendererCaps); - - mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - - mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + const gl::Caps &rendererCaps = getNativeCaps(); - mStateManager.initialize(rendererCaps); - - markAllStateDirty(); + if (mStateManager.initialize(rendererCaps, getNativeExtensions()).isError()) + { + return egl::EglBadAlloc() << "Error initializing state manager."; + } // Gather stats on DXGI and D3D feature level ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.SupportsDXGI1_2", mRenderer11DeviceCaps.supportsDXGI1_2); @@ -859,57 +930,117 @@ void Renderer11::initializeDevice() angleFeatureLevel = ANGLE_FEATURE_LEVEL_11_1; } - ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11FeatureLevel", - angleFeatureLevel, + 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); + return egl::NoError(); } void Renderer11::populateRenderer11DeviceCaps() { HRESULT hr = S_OK; -#if defined(ANGLE_ENABLE_D3D11_1) + LARGE_INTEGER version; + hr = mDxgiAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version); + if (FAILED(hr)) + { + mRenderer11DeviceCaps.driverVersion.reset(); + ERR() << "Error querying driver version from DXGI Adapter."; + } + else + { + mRenderer11DeviceCaps.driverVersion = version; + } + if (mDeviceContext1) { D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; - HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + 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); + mRenderer11DeviceCaps.supportsConstantBufferOffsets = + (d3d11Options.ConstantBufferOffsetting != FALSE); } } -#endif - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G6R5_UNORM, &(mRenderer11DeviceCaps.B5G6R5support)); - if (FAILED(hr)) + if (mDeviceContext3) { - mRenderer11DeviceCaps.B5G6R5support = 0; + D3D11_FEATURE_DATA_D3D11_OPTIONS3 d3d11Options3; + HRESULT result = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &d3d11Options3, + sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS3)); + if (SUCCEEDED(result)) + { + mRenderer11DeviceCaps.supportsVpRtIndexWriteFromVertexShader = + (d3d11Options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer == TRUE); + } } - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B4G4R4A4_UNORM, &(mRenderer11DeviceCaps.B4G4R4A4support)); - if (FAILED(hr)) + mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs = + mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_10_0; + + if (getWorkarounds().disableB5G6R5Support) { - mRenderer11DeviceCaps.B4G4R4A4support = 0; + mRenderer11DeviceCaps.B5G6R5support = 0; + mRenderer11DeviceCaps.B5G6R5maxSamples = 0; } - - hr = mDevice->CheckFormatSupport(DXGI_FORMAT_B5G5R5A1_UNORM, &(mRenderer11DeviceCaps.B5G5R5A1support)); - if (FAILED(hr)) + else { - mRenderer11DeviceCaps.B5G5R5A1support = 0; + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G6R5_UNORM, + &mRenderer11DeviceCaps.B5G6R5support, + &mRenderer11DeviceCaps.B5G6R5maxSamples); } -#if defined(ANGLE_ENABLE_D3D11_1) + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B4G4R4A4_UNORM, + &mRenderer11DeviceCaps.B4G4R4A4support, + &mRenderer11DeviceCaps.B4G4R4A4maxSamples); + PopulateFormatDeviceCaps(mDevice, DXGI_FORMAT_B5G5R5A1_UNORM, + &mRenderer11DeviceCaps.B5G5R5A1support, + &mRenderer11DeviceCaps.B5G5R5A1maxSamples); + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject(mDxgiAdapter); mRenderer11DeviceCaps.supportsDXGI1_2 = (dxgiAdapter2 != nullptr); SafeRelease(dxgiAdapter2); +} + +gl::SupportedSampleSet Renderer11::generateSampleSetForEGLConfig( + const gl::TextureCaps &colorBufferFormatCaps, + const gl::TextureCaps &depthStencilBufferFormatCaps) const +{ + gl::SupportedSampleSet sampleCounts; + +#if 0 // Disabling support for multisampling with Qt5 as it's causing a crash in the D3D11 shaders. + + // Generate a new set from the set intersection of sample counts between the color and depth + // format caps. + std::set_intersection(colorBufferFormatCaps.sampleCounts.begin(), + colorBufferFormatCaps.sampleCounts.end(), + depthStencilBufferFormatCaps.sampleCounts.begin(), + depthStencilBufferFormatCaps.sampleCounts.end(), + std::inserter(sampleCounts, sampleCounts.begin())); + + // Format of GL_NONE results in no supported sample counts. + // Add back the color sample counts to the supported sample set. + if (depthStencilBufferFormatCaps.sampleCounts.empty()) + { + sampleCounts = colorBufferFormatCaps.sampleCounts; + } + else if (colorBufferFormatCaps.sampleCounts.empty()) + { + // Likewise, add back the depth sample counts to the supported sample set. + sampleCounts = depthStencilBufferFormatCaps.sampleCounts; + } + #endif + + // Always support 0 samples + sampleCounts.insert(0); + + return sampleCounts; } -egl::ConfigSet Renderer11::generateConfigs() const +egl::ConfigSet Renderer11::generateConfigs() { std::vector colorBufferFormats; @@ -920,6 +1051,14 @@ egl::ConfigSet Renderer11::generateConfigs() const // 24-bit supported formats colorBufferFormats.push_back(GL_RGB8_OES); + if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + { + // Additional high bit depth formats added in D3D 10.0 + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb173064.aspx + colorBufferFormats.push_back(GL_RGBA16F); + colorBufferFormats.push_back(GL_RGB10_A2); + } + if (!mPresentPathFastEnabled) { // 16-bit supported formats @@ -930,15 +1069,13 @@ egl::ConfigSet Renderer11::generateConfigs() const colorBufferFormats.push_back(GL_RGB565); } - static const GLenum depthStencilBufferFormats[] = - { - GL_NONE, - GL_DEPTH24_STENCIL8_OES, - GL_DEPTH_COMPONENT16, + static const GLenum depthStencilBufferFormats[] = { + GL_NONE, GL_DEPTH24_STENCIL8_OES, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, + GL_STENCIL_INDEX8, }; - const gl::Caps &rendererCaps = getRendererCaps(); - const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps(); const EGLint optimalSurfaceOrientation = mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE; @@ -946,7 +1083,8 @@ egl::ConfigSet Renderer11::generateConfigs() const egl::ConfigSet configs; for (GLenum colorBufferInternalFormat : colorBufferFormats) { - const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + const gl::TextureCaps &colorBufferFormatCaps = + rendererTextureCaps.get(colorBufferInternalFormat); if (!colorBufferFormatCaps.renderable) { continue; @@ -963,64 +1101,87 @@ egl::ConfigSet Renderer11::generateConfigs() const } const gl::InternalFormat &colorBufferFormatInfo = - gl::GetInternalFormatInfo(colorBufferInternalFormat); + gl::GetSizedInternalFormatInfo(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) + gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat); + const gl::Version &maxVersion = getMaxSupportedESVersion(); + + const gl::SupportedSampleSet sampleCounts = + generateSampleSetForEGLConfig(colorBufferFormatCaps, depthStencilBufferFormatCaps); + + for (GLuint sampleCount : sampleCounts) { + 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) && (sampleCount <= 1)); + config.bindToTextureRGBA = (((colorBufferFormatInfo.format == GL_RGBA) || + (colorBufferFormatInfo.format == GL_BGRA_EXT)) && + (sampleCount <= 1)); + config.colorBufferType = EGL_RGB_BUFFER; + config.configCaveat = EGL_NONE; + config.configID = static_cast(configs.size() + 1); + + // PresentPathFast may not be conformant config.conformant = 0; - } + if (!mPresentPathFastEnabled) + { + // Can only support a conformant ES2 with feature level greater than 10.0. + if (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) + { + config.conformant |= EGL_OPENGL_ES2_BIT; + } + + // We can only support conformant ES3 on FL 10.1+ + if (maxVersion.major >= 3) + { + config.conformant |= EGL_OPENGL_ES3_BIT_KHR; + } + } + + 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.1 + config.renderableType = EGL_OPENGL_ES2_BIT; + if (maxVersion.major >= 3) + { + config.renderableType |= EGL_OPENGL_ES3_BIT_KHR; + } - 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); + config.sampleBuffers = (sampleCount == 0) ? 0 : 1; + config.samples = sampleCount; + 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; + config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType( + colorBufferFormatInfo.componentType); + + configs.add(config); + } } } @@ -1037,8 +1198,9 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions outExtensions->d3dShareHandleClientBuffer = true; outExtensions->surfaceD3DTexture2DShareHandle = true; } + outExtensions->d3dTextureClientBuffer = true; - outExtensions->keyedMutex = true; + outExtensions->keyedMutex = true; outExtensions->querySurfacePointer = true; outExtensions->windowFixedSize = true; @@ -1048,624 +1210,350 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions // 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->stream = true; + outExtensions->streamConsumerGLTexture = true; + outExtensions->streamConsumerGLTextureYUV = true; + // Not all D3D11 devices support NV12 textures + if (getNV12TextureSupport()) + { + outExtensions->streamProducerD3DTextureNV12 = true; + } + outExtensions->flexibleSurfaceCompatibility = true; outExtensions->directComposition = !!mDCompModule; + + // Contexts are virtualized so textures can be shared globally + outExtensions->displayTextureShareGroup = true; + + // getSyncValues requires direct composition. + outExtensions->getSyncValues = outExtensions->directComposition; + + // D3D11 can be used without a swap chain + outExtensions->surfacelessContext = true; + + // All D3D feature levels support robust resource init + outExtensions->robustResourceInitialization = true; } gl::Error Renderer11::flush() { mDeviceContext->Flush(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::finish() { - HRESULT result; - - if (!mSyncQuery) + if (!mSyncQuery.valid()) { D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.Query = D3D11_QUERY_EVENT; queryDesc.MiscFlags = 0; - result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); - } + ANGLE_TRY(allocateResource(queryDesc, &mSyncQuery)); } - mDeviceContext->End(mSyncQuery); - mDeviceContext->Flush(); + mDeviceContext->End(mSyncQuery.get()); + HRESULT result = S_OK; + unsigned int attempt = 0; do { - result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + unsigned int flushFrequency = 100; + UINT flags = (attempt % flushFrequency == 0) ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH; + attempt++; + + result = mDeviceContext->GetData(mSyncQuery.get(), nullptr, 0, flags); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - // Keep polling, but allow other threads to do something useful first - ScheduleYield(); + if (result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + ScheduleYield(); + } if (testDeviceLost()) { mDisplay->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while waiting for sync."); + return gl::OutOfMemory() << "Device was lost while waiting for sync."; } - } - while (result == S_FALSE); + } while (result == S_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, - HANDLE shareHandle, - GLenum backBufferFormat, - GLenum depthBufferFormat, - EGLint orientation) +bool Renderer11::isValidNativeWindow(EGLNativeWindowType window) const +{ +#ifdef ANGLE_ENABLE_WINDOWS_STORE + return NativeWindow11WinRT::IsValidNativeWindow(window); +#else + return NativeWindow11Win32::IsValidNativeWindow(window); +#endif +} + +NativeWindowD3D *Renderer11::createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const { - return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat, - orientation); +#ifdef ANGLE_ENABLE_WINDOWS_STORE + UNUSED_VARIABLE(attribs); + return new NativeWindow11WinRT(window, config->alphaSize > 0); +#else + return new NativeWindow11Win32( + window, config->alphaSize > 0, + attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); +#endif } -CompilerImpl *Renderer11::createCompiler() +egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const { - if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) + ID3D11Texture2D *texture = d3d11::DynamicCastComObject(d3dTexture); + if (texture == nullptr) { - return new CompilerD3D(SH_HLSL_4_0_FL9_3_OUTPUT); + return egl::EglBadParameter() << "client buffer is not a ID3D11Texture2D"; } - else + + ID3D11Device *textureDevice = nullptr; + texture->GetDevice(&textureDevice); + if (textureDevice != mDevice) { - return new CompilerD3D(SH_HLSL_4_1_OUTPUT); + SafeRelease(texture); + return egl::EglBadParameter() << "Texture's device does not match."; } -} + SafeRelease(textureDevice); -void *Renderer11::getD3DDevice() -{ - return reinterpret_cast(mDevice); -} + D3D11_TEXTURE2D_DESC desc = {0}; + texture->GetDesc(&desc); + SafeRelease(texture); -gl::Error Renderer11::generateSwizzle(gl::Texture *texture) -{ - if (texture) + if (width) { - TextureD3D *textureD3D = GetImplAs(texture); - ASSERT(textureD3D); - - TextureStorage *texStorage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&texStorage); - if (error.isError()) + *width = static_cast(desc.Width); + } + if (height) + { + *height = static_cast(desc.Height); + } + if (static_cast(desc.SampleDesc.Count) != configuration->samples) + { + // Both the texture and EGL config sample count may not be the same when multi-sampling + // is disabled. The EGL sample count can be 0 but a D3D texture is always 1. Therefore, + // we must only check for a invalid match when the EGL config is non-zero or the texture is + // not one. + if (configuration->samples != 0 || desc.SampleDesc.Count != 1) { - return error; + return egl::EglBadParameter() << "Texture's sample count does not match."; } + } + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (desc.Format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + break; - if (texStorage) - { - 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; - } - } + default: + return egl::EglBadParameter() + << "Unknown client buffer texture format: " << desc.Format; + } + + if (fboFormat) + { + const angle::Format &angleFormat = d3d11_angle::GetFormat(desc.Format); + *fboFormat = angleFormat.fboImplementationInternalFormat; } - return gl::Error(GL_NO_ERROR); + return egl::NoError(); } -gl::Error Renderer11::setSamplerState(gl::SamplerType type, - int index, - gl::Texture *texture, - const gl::SamplerState &samplerState) +egl::Error Renderer11::validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const { - // Make sure to add the level offset for our tiny compressed texture workaround - TextureD3D *textureD3D = GetImplAs(texture); + if (shareHandle == nullptr) + { + return egl::EglBadParameter() << "NULL share handle."; + } - TextureStorage *storage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&storage); - if (error.isError()) + ID3D11Resource *tempResource11 = nullptr; + HRESULT result = mDevice->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource), + (void **)&tempResource11); + if (FAILED(result)) { - return error; + return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); } - // Storage should exist, texture should be complete - ASSERT(storage); + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject(tempResource11); + SafeRelease(tempResource11); - if (type == gl::SAMPLER_PIXEL) + if (texture2D == nullptr) { - ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); + return egl::EglBadParameter() + << "Failed to query ID3D11Texture2D object from share handle."; + } - if (mForceSetPixelSamplerStates[index] || - memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerState, &dxSamplerState); - if (error.isError()) - { - return error; - } + D3D11_TEXTURE2D_DESC desc = {0}; + texture2D->GetDesc(&desc); + SafeRelease(texture2D); - ASSERT(dxSamplerState != NULL); - mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); + EGLint width = attribs.getAsInt(EGL_WIDTH, 0); + EGLint height = attribs.getAsInt(EGL_HEIGHT, 0); + ASSERT(width != 0 && height != 0); - mCurPixelSamplerStates[index] = samplerState; - } + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(config->renderTargetFormat, getRenderer11DeviceCaps()); - mForceSetPixelSamplerStates[index] = false; - } - else if (type == gl::SAMPLER_VERTEX) + if (desc.Width != static_cast(width) || desc.Height != static_cast(height) || + desc.Format != backbufferFormatInfo.texFormat || desc.MipLevels != 1 || desc.ArraySize != 1) { - ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); - - if (mForceSetVertexSamplerStates[index] || - memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - error = mStateCache.getSamplerState(samplerState, &dxSamplerState); - if (error.isError()) - { - return error; - } - - ASSERT(dxSamplerState != NULL); - mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); - - mCurVertexSamplerStates[index] = samplerState; - } - - mForceSetVertexSamplerStates[index] = false; + return egl::EglBadParameter() << "Invalid texture parameters in share handle texture."; } - else UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return egl::NoError(); } -gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +SwapChainD3D *Renderer11::createSwapChain(NativeWindowD3D *nativeWindow, + HANDLE shareHandle, + IUnknown *d3dTexture, + GLenum backBufferFormat, + GLenum depthBufferFormat, + EGLint orientation, + EGLint samples) { - ID3D11ShaderResourceView *textureSRV = NULL; - - if (texture) - { - TextureD3D *textureImpl = GetImplAs(texture); - - TextureStorage *texStorage = nullptr; - gl::Error error = textureImpl->getNativeTexture(&texStorage); - if (error.isError()) - { - return error; - } - - // Texture should be complete and have a storage - ASSERT(texStorage); - - TextureStorage11 *storage11 = GetAs(texStorage); - - // Make sure to add the level offset for our tiny compressed texture workaround - gl::TextureState textureState = texture->getTextureState(); - textureState.baseLevel += storage11->getTopLevel(); - - error = storage11->getSRV(textureState, &textureSRV); - if (error.isError()) - { - return error; - } - - // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly - // missing the shader resource view - ASSERT(textureSRV != NULL); - - textureImpl->resetDirty(); - } - - ASSERT((type == gl::SAMPLER_PIXEL && static_cast(index) < getRendererCaps().maxTextureImageUnits) || - (type == gl::SAMPLER_VERTEX && static_cast(index) < getRendererCaps().maxVertexTextureImageUnits)); - - mStateManager.setShaderResource(type, index, textureSRV); - - return gl::Error(GL_NO_ERROR); + return new SwapChain11(this, GetAs(nativeWindow), shareHandle, d3dTexture, + backBufferFormat, depthBufferFormat, orientation, samples); } -gl::Error Renderer11::setUniformBuffers(const gl::Data &data, - const std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) +void *Renderer11::getD3DDevice() { - for (size_t uniformBufferIndex = 0; uniformBufferIndex < vertexUniformBuffers.size(); uniformBufferIndex++) - { - GLint binding = vertexUniformBuffers[uniformBufferIndex]; - - if (binding == -1) - { - continue; - } - - const OffsetBindingPointer &uniformBuffer = - data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = uniformBuffer.getOffset(); - GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - - if (uniformBuffer.get() != nullptr) - { - Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); - ID3D11Buffer *constantBuffer; - - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) - { - constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - } - else - { - constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); - } - - if (!constantBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY); - } + return reinterpret_cast(mDevice); +} - if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial() || - mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset || - mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) - { -#if defined(ANGLE_ENABLE_D3D11_1) - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) - { - UINT firstConstant = 0, numConstants = 0; - CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->VSSetConstantBuffers1( - getReservedVertexUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer, &firstConstant, &numConstants); - } - else -#endif - { - mDeviceContext->VSSetConstantBuffers( - getReservedVertexUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer); - } +bool Renderer11::applyPrimitiveType(const gl::State &glState, GLenum mode, GLsizei count) +{ + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); - mCurrentConstantBufferVSOffset[uniformBufferIndex] = uniformBufferOffset; - mCurrentConstantBufferVSSize[uniformBufferIndex] = uniformBufferSize; - } - } - } + GLsizei minCount = 0; - for (size_t uniformBufferIndex = 0; uniformBufferIndex < fragmentUniformBuffers.size(); uniformBufferIndex++) + switch (mode) { - GLint binding = fragmentUniformBuffers[uniformBufferIndex]; - - if (binding == -1) + case GL_POINTS: { - continue; - } + bool usesPointSize = GetImplAs(glState.getProgram())->usesPointSize(); - const OffsetBindingPointer &uniformBuffer = - data.state->getIndexedUniformBuffer(binding); - GLintptr uniformBufferOffset = uniformBuffer.getOffset(); - GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); - - if (uniformBuffer.get() != nullptr) - { - Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); - ID3D11Buffer *constantBuffer; - - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets) + // 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 (!usesPointSize && !glState.isTransformFeedbackActiveUnpaused()) { - constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - } - else - { - constantBuffer = bufferStorage->getConstantBufferRange(uniformBufferOffset, uniformBufferSize); + // Notify developers of risking undefined behavior. + WARN() << "Point rendering without writing to gl_PointSize."; + return false; } - if (!constantBuffer) + // If instanced pointsprites are enabled and the shader uses gl_PointSize, the topology + // must be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST. + if (usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation) { - return gl::Error(GL_OUT_OF_MEMORY); + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } - - if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial() || - mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset || - mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) + else { -#if defined(ANGLE_ENABLE_D3D11_1) - if (mRenderer11DeviceCaps.supportsConstantBufferOffsets && uniformBufferSize != 0) - { - UINT firstConstant = 0, numConstants = 0; - CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); - mDeviceContext1->PSSetConstantBuffers1( - getReservedFragmentUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer, &firstConstant, &numConstants); - } - else -#endif - { - mDeviceContext->PSSetConstantBuffers( - getReservedFragmentUniformBuffers() + - static_cast(uniformBufferIndex), - 1, &constantBuffer); - } - - mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); - mCurrentConstantBufferPSOffset[uniformBufferIndex] = uniformBufferOffset; - mCurrentConstantBufferPSSize[uniformBufferIndex] = uniformBufferSize; + primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; } + minCount = 1; + break; } + case GL_LINES: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; + minCount = 2; + break; + case GL_LINE_LOOP: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + minCount = 2; + break; + case GL_LINE_STRIP: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + minCount = 2; + break; + case GL_TRIANGLES: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + minCount = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + case GL_TRIANGLE_STRIP: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + minCount = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + // emulate fans via rewriting index buffer + case GL_TRIANGLE_FAN: + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + minCount = CullsEverything(glState) ? std::numeric_limits::max() : 3; + break; + default: + UNREACHABLE(); + return false; } - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::updateState(const gl::Data &data, GLenum drawMode) -{ - // 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()) - { - return error; - } - - // Set the present path state - const bool presentPathFastActive = - UsePresentPathFast(this, framebufferObject->getFirstColorbuffer()); - mStateManager.updatePresentPath(presentPathFastActive, - framebufferObject->getFirstColorbuffer()); - - // Setting viewport state - mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), - data.state->getFarPlane()); - - // Setting scissor state - mStateManager.setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); - - // 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); - - error = mStateManager.setRasterizerState(rasterizer); - if (error.isError()) - { - return error; - } - - // Setting blend state - unsigned int mask = GetBlendSampleMask(data, samples); - error = mStateManager.setBlendState(framebufferObject, data.state->getBlendState(), - data.state->getBlendColor(), mask); - if (error.isError()) - { - return error; - } - - // Setting depth stencil state - error = mStateManager.setDepthStencilState(*data.state); - return error; -} - -void Renderer11::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) -{ - mStateManager.syncState(state, bitmask); -} - -bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) -{ - D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - - GLsizei minCount = 0; - - switch (mode) - { - case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; - case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; - case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; - case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; - case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; - case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; - // emulate fans via rewriting index buffer - case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; - default: - UNREACHABLE(); - return false; - } - - // If instanced pointsprite emulation is being used and If gl_PointSize is used in the shader, - // GL_POINTS mode is expected to render pointsprites. - // Instanced PointSprite emulation requires that the topology to be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST. - if (mode == GL_POINTS && usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation) - { - primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - } - - if (primitiveTopology != mCurrentPrimitiveTopology) - { - mDeviceContext->IASetPrimitiveTopology(primitiveTopology); - mCurrentPrimitiveTopology = primitiveTopology; - } + mStateManager.setPrimitiveTopology(primitiveTopology); return count >= minCount; } -gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) +gl::Error Renderer11::drawArrays(const gl::Context *context, + GLenum mode, + GLint startVertex, + GLsizei count, + GLsizei instances) { - return mStateManager.syncFramebuffer(framebuffer); -} + const auto &glState = context->getGLState(); -gl::Error Renderer11::applyVertexBuffer(const gl::State &state, - GLenum mode, - GLint first, - GLsizei count, - GLsizei instances, - TranslatedIndexData *indexInfo) -{ - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, count)) { - return error; + return gl::NoError(); } - // If index information is passed, mark it with the current changed status. - if (indexInfo) - { - indexInfo->srcIndexData.srcIndicesChanged = mAppliedIBChanged; - } + DrawCallVertexParams vertexParams(startVertex, count, instances); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); - GLsizei numIndicesPerInstance = 0; - if (instances > 0) + if (glState.isTransformFeedbackActiveUnpaused()) { - numIndicesPerInstance = count; + ANGLE_TRY(markTransformFeedbackUsage(context)); } - return mInputLayoutCache.applyVertexBuffers(mTranslatedAttribCache, mode, state.getProgram(), - indexInfo, numIndicesPerInstance); -} -gl::Error Renderer11::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, - data.state->isPrimitiveRestartEnabled()); - if (error.isError()) - { - return error; - } + gl::Program *program = glState.getProgram(); + ASSERT(program != nullptr); + GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances); + ProgramD3D *programD3D = GetImplAs(program); - ID3D11Buffer *buffer = NULL; - DXGI_FORMAT bufferFormat = (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; - - if (indexInfo->storage) - { - Buffer11 *storage = GetAs(indexInfo->storage); - buffer = storage->getBuffer(BUFFER_USAGE_INDEX); - } - else - { - IndexBuffer11* indexBuffer = GetAs(indexInfo->indexBuffer); - buffer = indexBuffer->getBuffer(); - } - - mAppliedIBChanged = false; - if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) - { - mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); - - mAppliedIB = buffer; - mAppliedIBFormat = bufferFormat; - mAppliedIBOffset = indexInfo->startOffset; - mAppliedIBChanged = true; - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) -{ - size_t numXFBBindings = 0; - bool requiresUpdate = false; - - if (state.isTransformFeedbackActiveUnpaused()) - { - 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++) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - - ID3D11Buffer *d3dBuffer = NULL; - if (binding.get() != nullptr) - { - 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] || binding.getOffset() != mAppliedTFOffsets[i]) - { - requiresUpdate = true; - } - } - } - - if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings) - { - const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback(); - for (size_t i = 0; i < numXFBBindings; ++i) - { - const OffsetBindingPointer &binding = transformFeedback->getIndexedBuffer(i); - if (binding.get() != nullptr) - { - Buffer11 *storage = GetImplAs(binding.get()); - ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ? - static_cast(binding.getOffset()) : -1; - mAppliedTFBuffers[i] = d3dBuffer; - } - else - { - mAppliedTFBuffers[i] = NULL; - mCurrentD3DOffsets[i] = 0; - } - mAppliedTFOffsets[i] = binding.getOffset(); - } - - mAppliedNumXFBBindings = numXFBBindings; - - mDeviceContext->SOSetTargets(static_cast(numXFBBindings), mAppliedTFBuffers, - mCurrentD3DOffsets); - } -} - -gl::Error Renderer11::drawArraysImpl(const gl::Data &data, - GLenum mode, - GLsizei count, - GLsizei instances) -{ - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - - if (programD3D->usesGeometryShader(mode) && data.state->isTransformFeedbackActiveUnpaused()) + if (programD3D->usesGeometryShader(mode) && glState.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); + mStateManager.setPixelShader(nullptr); - if (instances > 0) + if (adjustedInstanceCount > 0) { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } else { @@ -1673,709 +1561,481 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data, } rx::ShaderExecutableD3D *pixelExe = nullptr; - gl::Error error = programD3D->getPixelExecutableForFramebuffer(data.state->getDrawFramebuffer(), &pixelExe); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); // Skip the draw call if rasterizer discard is enabled (or no fragment shader). - if (!pixelExe || data.state->getRasterizerState().rasterizerDiscard) + if (!pixelExe || glState.getRasterizerState().rasterizerDiscard) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - ID3D11PixelShader *pixelShader = GetAs(pixelExe)->getPixelShader(); - ASSERT(reinterpret_cast(pixelShader) == mAppliedPixelShader); - mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mStateManager.setPixelShader(&GetAs(pixelExe)->getPixelShader()); // Retrieve the geometry shader. rx::ShaderExecutableD3D *geometryExe = nullptr; - error = - programD3D->getGeometryExecutableForPrimitiveType(data, mode, &geometryExe, nullptr); - if (error.isError()) - { - return error; - } + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, mode, &geometryExe, + nullptr)); - ID3D11GeometryShader *geometryShader = - (geometryExe ? GetAs(geometryExe)->getGeometryShader() : NULL); - mAppliedGeometryShader = reinterpret_cast(geometryShader); - ASSERT(geometryShader); - mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mStateManager.setGeometryShader( + &GetAs(geometryExe)->getGeometryShader()); - if (instances > 0) + if (adjustedInstanceCount > 0) { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } else { mDeviceContext->Draw(count, 0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } if (mode == GL_LINE_LOOP) { - return drawLineLoop(data, count, GL_NONE, nullptr, nullptr, instances); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount); } if (mode == GL_TRIANGLE_FAN) { - return drawTriangleFan(data, count, GL_NONE, nullptr, 0, instances); + return drawTriangleFan(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount); } bool useInstancedPointSpriteEmulation = programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation; - if (instances > 0) + if (mode != GL_POINTS || !useInstancedPointSpriteEmulation) { - if (mode == GL_POINTS && useInstancedPointSpriteEmulation) + if (adjustedInstanceCount == 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); - } + mDeviceContext->Draw(count, 0); } else { - mDeviceContext->DrawInstanced(count, instances, 0, 0); + mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } + // This code should not be reachable by multi-view programs. + ASSERT(program->usesMultiview() == false); + // 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) + if (adjustedInstanceCount == 0) { mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + return gl::NoError(); } - else - { - mDeviceContext->Draw(count, 0); - } - return gl::Error(GL_NO_ERROR); -} -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(data, count, type, indices, &indexInfo, instances); - } - - if (mode == GL_TRIANGLE_FAN) - { - return drawTriangleFan(data, count, type, indices, minIndex, instances); - } - - const ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - if (instances > 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++) { - 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. + ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i)); mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); } - else - { - mDeviceContext->DrawIndexed(count, 0, -minIndex); - } - return gl::Error(GL_NO_ERROR); + + // This required by updateVertexOffsets... above but is outside of the loop for speed. + mStateManager.invalidateVertexBuffer(); + return gl::NoError(); } -gl::Error Renderer11::drawLineLoop(const gl::Data &data, +gl::Error Renderer11::drawElements(const gl::Context *context, + GLenum mode, GLsizei count, GLenum type, - const GLvoid *indexPointer, - const TranslatedIndexData *indexInfo, - int instances) + const void *indices, + GLsizei instances) { - gl::VertexArray *vao = data.state->getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + const auto &glState = context->getGLState(); - const GLvoid *indices = indexPointer; - - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) + if (!applyPrimitiveType(glState, mode, count)) { - BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - - indices = bufferData + offset; + return gl::NoError(); } - if (!mLineLoopIB) - { - mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); - if (error.isError()) - { - SafeDelete(mLineLoopIB); - return error; - } - } + // Transform feedback is not allowed for DrawElements, this error should have been caught at the + // API validation layer. + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 0); + const auto &lazyIndexRange = context->getParams(); - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); - } + bool usePrimitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); + DrawCallVertexParams vertexParams(!usePrimitiveRestartWorkaround, lazyIndexRange, 0, instances); - GetLineLoopIndices(indices, type, static_cast(count), - data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); + ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, + usePrimitiveRestartWorkaround)); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); - unsigned int spaceNeeded = - static_cast(sizeof(GLuint) * mScratchIndexDataBuffer.size()); - gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) - { - return error; - } + int startVertex = static_cast(vertexParams.firstVertex()); + int baseVertex = -startVertex; - void* mappedMemory = NULL; - unsigned int offset; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } + const gl::Program *program = glState.getProgram(); + GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances); - // Copy over the converted index data. - memcpy(mappedMemory, &mScratchIndexDataBuffer[0], - sizeof(GLuint) * mScratchIndexDataBuffer.size()); - - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - - IndexBuffer11 *indexBuffer = GetAs(mLineLoopIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || - mAppliedIBOffset != offset) + if (mode == GL_LINE_LOOP) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = offset; + return drawLineLoop(context, count, type, indices, baseVertex, adjustedInstanceCount); } - 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 + if (mode == GL_TRIANGLE_FAN) { - mDeviceContext->DrawIndexed(indexCount, 0, baseVertexLocation); + return drawTriangleFan(context, count, type, indices, baseVertex, adjustedInstanceCount); } - return gl::Error(GL_NO_ERROR); -} + const ProgramD3D *programD3D = GetImplAs(glState.getProgram()); -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) + if (mode != GL_POINTS || !programD3D->usesInstancedPointSpriteEmulation()) { - BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) + if (adjustedInstanceCount == 0) { - return error; + mDeviceContext->DrawIndexed(count, 0, baseVertex); } - - indexPointer = bufferData + offset; - } - - if (!mTriangleFanIB) - { - mTriangleFanIB = new StreamingIndexBufferInterface(this); - gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); - if (error.isError()) + else { - SafeDelete(mTriangleFanIB); - return error; + mDeviceContext->DrawIndexedInstanced(count, adjustedInstanceCount, 0, baseVertex, 0); } + return gl::NoError(); } - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 3); - - const GLuint numTris = count - 2; + // This code should not be reachable by multi-view programs. + ASSERT(program->usesMultiview() == false); - if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) + // 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. + // + // 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. + if (instances == 0) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + return gl::NoError(); } - GetTriFanIndices(indexPointer, type, count, data.state->isPrimitiveRestartEnabled(), - &mScratchIndexDataBuffer); + // 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 = vertexParams.vertexCount(); - const unsigned int spaceNeeded = - static_cast(mScratchIndexDataBuffer.size() * sizeof(unsigned int)); - gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) + // Each instance being rendered requires the inputlayout cache to reapply buffers and offsets. + for (GLsizei i = 0; i < instances; i++) { - return error; - } - - void *mappedMemory = nullptr; - unsigned int offset; - error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; + ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i)); + mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0); } + mStateManager.invalidateVertexBuffer(); + return gl::NoError(); +} - memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded); +gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + const auto &glState = context->getGLState(); + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - error = mTriangleFanIB->unmapBuffer(); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, std::numeric_limits::max() - 1)) { - return error; + return gl::NoError(); } - IndexBuffer11 *indexBuffer = GetAs(mTriangleFanIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect); + ASSERT(drawIndirectBuffer); + Buffer11 *storage = GetImplAs(drawIndirectBuffer); + uintptr_t offset = reinterpret_cast(indirect); - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || - mAppliedIBOffset != offset) + if (!DrawCallNeedsTranslation(context, mode)) { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = offset; + DrawCallVertexParams vertexParams(0, 0, 0); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); + ID3D11Buffer *buffer = nullptr; + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); + mDeviceContext->DrawInstancedIndirect(buffer, static_cast(offset)); + return gl::NoError(); } - UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + ASSERT(bufferData); + const gl::DrawArraysIndirectCommand *args = + reinterpret_cast(bufferData + offset); + GLuint count = args->count; + GLuint instances = args->instanceCount; + GLuint first = args->first; - if (instances > 0) + DrawCallVertexParams vertexParams(first, count, instances); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, false)); + + if (mode == GL_LINE_LOOP) { - mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, -minIndex, 0); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, instances); } - else + if (mode == GL_TRIANGLE_FAN) { - mDeviceContext->DrawIndexed(indexCount, 0, -minIndex); + return drawTriangleFan(context, count, GL_NONE, nullptr, 0, instances); } - return gl::Error(GL_NO_ERROR); + mDeviceContext->DrawInstanced(count, instances, 0, 0); + return gl::NoError(); } -gl::Error Renderer11::applyShadersImpl(const gl::Data &data, GLenum drawMode) +gl::Error Renderer11::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) { - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - const auto &inputLayout = programD3D->getCachedInputLayout(); + const auto &glState = context->getGLState(); + ASSERT(!glState.isTransformFeedbackActiveUnpaused()); - ShaderExecutableD3D *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); - if (error.isError()) + if (!applyPrimitiveType(glState, mode, std::numeric_limits::max() - 1)) { - return error; + return gl::NoError(); } - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - ShaderExecutableD3D *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe); - if (error.isError()) - { - return error; - } + gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect); + ASSERT(drawIndirectBuffer); + Buffer11 *storage = GetImplAs(drawIndirectBuffer); + uintptr_t offset = reinterpret_cast(indirect); - ShaderExecutableD3D *geometryExe = nullptr; - error = - programD3D->getGeometryExecutableForPrimitiveType(data, drawMode, &geometryExe, nullptr); - if (error.isError()) + // TODO(jmadill): Remove the if statement and compute indirect parameters lazily. + bool usePrimitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type); + + if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type)) { - return error; + ANGLE_TRY(mStateManager.applyIndexBuffer(context, nullptr, 0, type, gl::HasIndexRange(), + usePrimitiveRestartWorkaround)); + DrawCallVertexParams vertexParams(0, 0, 0); + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); + ID3D11Buffer *buffer = nullptr; + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer); + mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast(offset)); + return gl::NoError(); } - ID3D11VertexShader *vertexShader = (vertexExe ? GetAs(vertexExe)->getVertexShader() : NULL); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + ASSERT(bufferData); - ID3D11PixelShader *pixelShader = NULL; - // Skip pixel shader if we're doing rasterizer discard. - bool rasterizerDiscard = data.state->getRasterizerState().rasterizerDiscard; - if (!rasterizerDiscard) - { - pixelShader = (pixelExe ? GetAs(pixelExe)->getPixelShader() : NULL); - } + const gl::DrawElementsIndirectCommand *cmd = + reinterpret_cast(bufferData + offset); + GLsizei count = cmd->count; + GLuint instances = cmd->primCount; + GLuint firstIndex = cmd->firstIndex; + GLint baseVertex = cmd->baseVertex; - ID3D11GeometryShader *geometryShader = NULL; - bool transformFeedbackActive = data.state->isTransformFeedbackActiveUnpaused(); - if (transformFeedbackActive) - { - geometryShader = (vertexExe ? GetAs(vertexExe)->getStreamOutShader() : NULL); - } - else - { - geometryShader = (geometryExe ? GetAs(geometryExe)->getGeometryShader() : NULL); - } + // TODO(jmadill): Fix const cast. + const gl::Type &typeInfo = gl::GetTypeInfo(type); + const void *indices = + reinterpret_cast(static_cast(firstIndex * typeInfo.bytes)); + gl::HasIndexRange lazyIndexRange(const_cast(context), count, type, indices); - bool dirtyUniforms = false; + ANGLE_TRY(mStateManager.applyIndexBuffer(context, indices, count, type, lazyIndexRange, + usePrimitiveRestartWorkaround)); - if (reinterpret_cast(vertexShader) != mAppliedVertexShader) - { - mDeviceContext->VSSetShader(vertexShader, NULL, 0); - mAppliedVertexShader = reinterpret_cast(vertexShader); - dirtyUniforms = true; - } + DrawCallVertexParams vertexParams(false, lazyIndexRange, baseVertex, instances); - if (reinterpret_cast(geometryShader) != mAppliedGeometryShader) - { - mDeviceContext->GSSetShader(geometryShader, NULL, 0); - mAppliedGeometryShader = reinterpret_cast(geometryShader); - dirtyUniforms = true; - } + ANGLE_TRY(mStateManager.applyVertexBuffer(context, mode, vertexParams, true)); - if (reinterpret_cast(pixelShader) != mAppliedPixelShader) + int baseVertexLocation = -static_cast(lazyIndexRange.getIndexRange().value().start); + + if (mode == GL_LINE_LOOP) { - mDeviceContext->PSSetShader(pixelShader, NULL, 0); - mAppliedPixelShader = reinterpret_cast(pixelShader); - dirtyUniforms = true; + return drawLineLoop(context, count, type, indices, baseVertexLocation, instances); } - if (dirtyUniforms) + if (mode == GL_TRIANGLE_FAN) { - programD3D->dirtyAllUniforms(); + return drawTriangleFan(context, count, type, indices, baseVertexLocation, instances); } - return gl::Error(GL_NO_ERROR); + mDeviceContext->DrawIndexedInstanced(count, instances, 0, baseVertexLocation, 0); + return gl::NoError(); } -gl::Error Renderer11::applyUniforms(const ProgramD3D &programD3D, - GLenum drawMode, - const std::vector &uniformArray) +gl::Error Renderer11::drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indexPointer, + int baseVertex, + int instances) { - unsigned int totalRegisterCountVS = 0; - unsigned int totalRegisterCountPS = 0; + const gl::State &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - bool vertexUniformsDirty = false; - bool pixelUniformsDirty = false; + const void *indices = indexPointer; - for (const D3DUniform *uniform : uniformArray) + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) { - if (uniform->isReferencedByVertexShader() && !uniform->isSampler()) - { - totalRegisterCountVS += uniform->registerCount; - vertexUniformsDirty = (vertexUniformsDirty || uniform->dirty); - } - - if (uniform->isReferencedByFragmentShader() && !uniform->isSampler()) - { - totalRegisterCountPS += uniform->registerCount; - pixelUniformsDirty = (pixelUniformsDirty || uniform->dirty); - } - } - - const UniformStorage11 *vertexUniformStorage = - GetAs(&programD3D.getVertexUniformStorage()); - const UniformStorage11 *fragmentUniformStorage = - GetAs(&programD3D.getFragmentUniformStorage()); - ASSERT(vertexUniformStorage); - ASSERT(fragmentUniformStorage); + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); - ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); - ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); - float (*mapVS)[4] = NULL; - float (*mapPS)[4] = NULL; + indices = bufferData + offset; + } - if (totalRegisterCountVS > 0 && vertexUniformsDirty) + if (!mLineLoopIB) { - D3D11_MAPPED_SUBRESOURCE map = {0}; - HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - mapVS = (float(*)[4])map.pData; + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } } - if (totalRegisterCountPS > 0 && pixelUniformsDirty) + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > + (std::numeric_limits::max() / sizeof(unsigned int))) { - D3D11_MAPPED_SUBRESOURCE map = {0}; - HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - mapPS = (float(*)[4])map.pData; + return gl::OutOfMemory() << "Failed to create a 32-bit looping index buffer for " + "GL_LINE_LOOP, too many indices required."; } - for (const D3DUniform *uniform : uniformArray) - { - if (uniform->isSampler()) - continue; + GetLineLoopIndices(indices, type, static_cast(count), + glState.isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer); - unsigned int componentCount = (4 - uniform->registerElement); + unsigned int spaceNeeded = + static_cast(sizeof(GLuint) * mScratchIndexDataBuffer.size()); + ANGLE_TRY(mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - // we assume that uniforms from structs are arranged in struct order in our uniforms list. - // otherwise we would overwrite previously written regions of memory. + void *mappedMemory = nullptr; + unsigned int offset; + ANGLE_TRY(mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)); - if (uniform->isReferencedByVertexShader() && mapVS) - { - memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, - uniform->registerCount * sizeof(float) * componentCount); - } + // Copy over the converted index data. + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], + sizeof(GLuint) * mScratchIndexDataBuffer.size()); - if (uniform->isReferencedByFragmentShader() && mapPS) - { - memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, - uniform->registerCount * sizeof(float) * componentCount); - } - } + ANGLE_TRY(mLineLoopIB->unmapBuffer()); - if (mapVS) - { - mDeviceContext->Unmap(vertexConstantBuffer, 0); - } + IndexBuffer11 *indexBuffer = GetAs(mLineLoopIB->getIndexBuffer()); + const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - if (mapPS) - { - mDeviceContext->Unmap(pixelConstantBuffer, 0); - } + mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset); - if (mCurrentVertexConstantBuffer != vertexConstantBuffer) - { - mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); - mCurrentVertexConstantBuffer = vertexConstantBuffer; - } + UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); - if (mCurrentPixelConstantBuffer != pixelConstantBuffer) + if (instances > 0) { - mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); - mCurrentPixelConstantBuffer = pixelConstantBuffer; + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0); } - - // Driver uniforms - if (!mDriverConstantBufferVS) + else { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants11); - constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = 0; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; - - HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); - 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); + mDeviceContext->DrawIndexed(indexCount, 0, baseVertex); } - if (!mDriverConstantBufferPS) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants11); - constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = 0; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; + return gl::NoError(); +} - HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); - 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); - } +gl::Error Renderer11::drawTriangleFan(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int baseVertex, + int instances) +{ + const gl::State &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - const dx_VertexConstants11 &vertexConstants = mStateManager.getVertexConstants(); - if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants11)) != 0) - { - ASSERT(mDriverConstantBufferVS != nullptr); - if (mDriverConstantBufferVS) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &vertexConstants, - 16, 0); - memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants11)); - } - } + const void *indexPointer = indices; - const dx_PixelConstants11 &pixelConstants = mStateManager.getPixelConstants(); - if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants11)) != 0) + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) { - ASSERT(mDriverConstantBufferPS != nullptr); - if (mDriverConstantBufferPS) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &pixelConstants, 16, - 0); - memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants11)); - } + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = nullptr; + ANGLE_TRY(storage->getData(context, &bufferData)); + + indexPointer = bufferData + offset; } - // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary - if (programD3D.usesGeometryShader(drawMode)) + if (!mTriangleFanIB) { - // needed for the point sprite geometry shader - if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) + mTriangleFanIB = new StreamingIndexBufferInterface(this); + gl::Error error = + mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) { - ASSERT(mDriverConstantBufferPS != nullptr); - if (mDriverConstantBufferPS) - { - mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); - mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; - } + SafeDelete(mTriangleFanIB); + return error; } } - return gl::Error(GL_NO_ERROR); -} + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 3); -void Renderer11::markAllStateDirty() -{ - TRACE_EVENT0("gpu.angle", "Renderer11::markAllStateDirty"); + const GLuint numTris = count - 2; - for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) + if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) { - mForceSetVertexSamplerStates[vsamplerId] = true; + return gl::OutOfMemory() << "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, " + "too many indices required."; } - for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) - { - mForceSetPixelSamplerStates[fsamplerId] = true; - } + GetTriFanIndices(indexPointer, type, count, glState.isPrimitiveRestartEnabled(), + &mScratchIndexDataBuffer); - mStateManager.invalidateEverything(); + const unsigned int spaceNeeded = + static_cast(mScratchIndexDataBuffer.size() * sizeof(unsigned int)); + ANGLE_TRY(mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - mAppliedIB = NULL; - mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; - mAppliedIBOffset = 0; + void *mappedMemory = nullptr; + unsigned int offset; + ANGLE_TRY(mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)); - mAppliedVertexShader = angle::DirtyPointer; - mAppliedGeometryShader = angle::DirtyPointer; - mAppliedPixelShader = angle::DirtyPointer; + memcpy(mappedMemory, &mScratchIndexDataBuffer[0], spaceNeeded); - mAppliedNumXFBBindings = static_cast(-1); + ANGLE_TRY(mTriangleFanIB->unmapBuffer()); - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - mAppliedTFBuffers[i] = NULL; - mAppliedTFOffsets[i] = 0; - } + IndexBuffer11 *indexBuffer = GetAs(mTriangleFanIB->getIndexBuffer()); + const d3d11::Buffer &d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11)); - memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11)); + mStateManager.setIndexBuffer(d3dIndexBuffer.get(), indexFormat, offset); - mInputLayoutCache.markDirty(); + UINT indexCount = static_cast(mScratchIndexDataBuffer.size()); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + if (instances > 0) { - mCurrentConstantBufferVS[i] = static_cast(-1); - mCurrentConstantBufferVSOffset[i] = 0; - mCurrentConstantBufferVSSize[i] = 0; - mCurrentConstantBufferPS[i] = static_cast(-1); - mCurrentConstantBufferPSOffset[i] = 0; - mCurrentConstantBufferPSSize[i] = 0; + mDeviceContext->DrawIndexedInstanced(indexCount, instances, 0, baseVertex, 0); + } + else + { + mDeviceContext->DrawIndexed(indexCount, 0, baseVertex); } - mCurrentVertexConstantBuffer = NULL; - mCurrentPixelConstantBuffer = NULL; - mCurrentGeometryConstantBuffer = NULL; - - mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + return gl::NoError(); } void Renderer11::releaseDeviceResources() { + mStateManager.deinitialize(); mStateCache.clear(); - mInputLayoutCache.clear(); - SafeDelete(mVertexDataManager); - SafeDelete(mIndexDataManager); SafeDelete(mLineLoopIB); SafeDelete(mTriangleFanIB); SafeDelete(mBlit); @@ -2383,9 +2043,9 @@ void Renderer11::releaseDeviceResources() SafeDelete(mTrim); SafeDelete(mPixelTransfer); - SafeRelease(mDriverConstantBufferVS); - SafeRelease(mDriverConstantBufferPS); - SafeRelease(mSyncQuery); + mSyncQuery.reset(); + + mCachedResolveTexture.reset(); } // set notify to true to broadcast a message to all contexts of the device loss @@ -2393,24 +2053,18 @@ bool Renderer11::testDeviceLost() { bool isLost = false; + if (!mDevice) + { + return true; + } + // GetRemovedReason is used to test if the device is removed HRESULT result = mDevice->GetDeviceRemovedReason(); - isLost = d3d11::isDeviceLostError(result); + isLost = d3d11::isDeviceLostError(result); if (isLost) { - // Log error if this is a new device lost event - if (mDeviceLost == false) - { - ERR("The D3D11 device was removed: 0x%08X", result); - } - - // ensure we note the device loss -- - // we'll probably get this done again by notifyDeviceLost - // but best to remember it! - // Note that we don't want to clear the device loss status here - // -- this needs to be done by resetDevice - mDeviceLost = true; + ERR() << "The D3D11 device was removed, " << gl::FmtHR(result); } return isLost; @@ -2419,27 +2073,24 @@ bool Renderer11::testDeviceLost() bool Renderer11::testDeviceResettable() { // determine if the device is resettable by creating a dummy device - PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = + (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); - if (D3D11CreateDevice == NULL) + if (D3D11CreateDevice == nullptr) { return false; } - ID3D11Device* dummyDevice; + ID3D11Device *dummyDevice; D3D_FEATURE_LEVEL dummyFeatureLevel; - ID3D11DeviceContext* dummyContext; + ID3D11DeviceContext *dummyContext; + UINT flags = (mCreateDebugDevice ? D3D11_CREATE_DEVICE_DEBUG : 0); ASSERT(mRequestedDriverType != D3D_DRIVER_TYPE_UNKNOWN); HRESULT result = D3D11CreateDevice( - NULL, mRequestedDriverType, NULL, - #if defined(_DEBUG) - D3D11_CREATE_DEVICE_DEBUG, - #else - 0, - #endif - mAvailableFeatureLevels.data(), static_cast(mAvailableFeatureLevels.size()), - D3D11_SDK_VERSION, &dummyDevice, &dummyFeatureLevel, &dummyContext); + nullptr, mRequestedDriverType, nullptr, flags, mAvailableFeatureLevels.data(), + static_cast(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, &dummyDevice, + &dummyFeatureLevel, &dummyContext); if (!mDevice || FAILED(result)) { @@ -2456,6 +2107,14 @@ void Renderer11::release() { RendererD3D::cleanup(); + mScratchMemoryBuffer.clear(); + + if (mAnnotator != nullptr) + { + gl::UninitializeDebugAnnotations(); + SafeDelete(mAnnotator); + } + releaseDeviceResources(); if (!mCreatedWithDeviceEXT) @@ -2468,9 +2127,8 @@ void Renderer11::release() SafeRelease(mDxgiFactory); SafeRelease(mDxgiAdapter); -#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mDeviceContext3); SafeRelease(mDeviceContext1); -#endif if (mDeviceContext) { @@ -2480,26 +2138,24 @@ void Renderer11::release() } SafeRelease(mDevice); -#if !defined(ANGLE_MINGW32_COMPAT) SafeRelease(mDebug); -#endif if (mD3d11Module) { FreeLibrary(mD3d11Module); - mD3d11Module = NULL; + mD3d11Module = nullptr; } if (mDxgiModule) { FreeLibrary(mDxgiModule); - mDxgiModule = NULL; + mDxgiModule = nullptr; } if (mDCompModule) { FreeLibrary(mDCompModule); - mDCompModule = NULL; + mDCompModule = nullptr; } mCompiler.release(); @@ -2515,12 +2171,10 @@ bool Renderer11::resetDevice() if (result.isError()) { - ERR("Could not reinitialize D3D11 device: %08X", result.getCode()); + ERR() << "Could not reinitialize D3D11 device: " << result; return false; } - mDeviceLost = false; - return true; } @@ -2531,8 +2185,10 @@ std::string Renderer11::getRendererDescription() const rendererString << mDescription; rendererString << " Direct3D11"; - rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); - rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); + rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); return rendererString.str(); } @@ -2540,12 +2196,12 @@ std::string Renderer11::getRendererDescription() const DeviceIdentifier Renderer11::getAdapterIdentifier() const { // 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); + 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; } @@ -2605,7 +2261,7 @@ bool Renderer11::getShareHandleSupport() const // 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) + if (!getNativeExtensions().textureFormatBGRA8888) { mSupportsShareHandles = false; return false; @@ -2620,7 +2276,8 @@ bool Renderer11::getShareHandleSupport() const // Qt: we don't care about the 9_3 limitation #if 0 - // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains. + // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on + // RGBA8 textures/swapchains. if (mRenderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3) { mSupportsShareHandles = false; @@ -2668,15 +2325,34 @@ bool Renderer11::getShareHandleSupport() const return true; } +bool Renderer11::getNV12TextureSupport() const +{ + HRESULT result; + UINT formatSupport; + result = mDevice->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport); + if (result == E_FAIL) + { + return false; + } + return (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; +} + int Renderer11::getMajorShaderModel() const { 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 - case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 - case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MAJOR_VERSION; // 4 - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + 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 + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_9_3: + return D3D10_SHADER_MAJOR_VERSION; // 4 + default: + UNREACHABLE(); + return 0; } } @@ -2684,11 +2360,18 @@ int Renderer11::getMinorShaderModel() const { 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 - case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 - case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MINOR_VERSION; // 0 - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + 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 + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_9_3: + return D3D10_SHADER_MINOR_VERSION; // 0 + default: + UNREACHABLE(); + return 0; } } @@ -2696,15 +2379,22 @@ std::string Renderer11::getShaderModelSuffix() const { switch (mRenderer11DeviceCaps.featureLevel) { - case D3D_FEATURE_LEVEL_11_0: return ""; - case D3D_FEATURE_LEVEL_10_1: return ""; - case D3D_FEATURE_LEVEL_10_0: return ""; - case D3D_FEATURE_LEVEL_9_3: return "_level_9_3"; - default: UNREACHABLE(); return ""; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return ""; + case D3D_FEATURE_LEVEL_10_1: + return ""; + case D3D_FEATURE_LEVEL_10_0: + return ""; + case D3D_FEATURE_LEVEL_9_3: + return "_level_9_3"; + default: + UNREACHABLE(); + return ""; } } -const WorkaroundsD3D &RendererD3D::getWorkarounds() const +const angle::WorkaroundsD3D &RendererD3D::getWorkarounds() const { if (!mWorkaroundsInitialized) { @@ -2715,42 +2405,31 @@ const WorkaroundsD3D &RendererD3D::getWorkarounds() const 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::Error Renderer11::copyImageInternal(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + RenderTargetD3D *destRenderTarget) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + const gl::FramebufferAttachment *colorAttachment = framebuffer->getReadColorbuffer(); + ASSERT(colorAttachment); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } + RenderTarget11 *sourceRenderTarget = nullptr; + ANGLE_TRY(colorAttachment->getRenderTarget(context, &sourceRenderTarget)); ASSERT(sourceRenderTarget); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_2D *storage11 = GetAs(storage); - ASSERT(storage11); - - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); + const d3d11::SharedSRV &source = sourceRenderTarget->getBlitShaderResourceView(); + ASSERT(source.valid()); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + const d3d11::RenderTargetView &dest = + GetAs(destRenderTarget)->getRenderTargetView(); + ASSERT(dest.valid()); 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); + const bool invertSource = UsePresentPathFast(this, colorAttachment); if (invertSource) { sourceArea.y = sourceSize.height - sourceRect.y; @@ -2760,226 +2439,267 @@ gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl:: 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, false); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); + // Use nearest filtering because source and destination are the same size for the direct copy. + // Convert to the unsized format before calling copyTexture. + GLenum sourceFormat = colorAttachment->getFormat().info->format; + ANGLE_TRY(mBlit->copyTexture(context, source, sourceArea, sourceSize, sourceFormat, dest, + destArea, destSize, nullptr, gl::GetUnsizedFormat(destFormat), + GL_NEAREST, false, false, false)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -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::Error Renderer11::copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + TextureStorage11_2D *storage11 = GetAs(storage); + ASSERT(storage11); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); + + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); + + storage11->markLevelDirty(level); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + return gl::NoError(); +} +gl::Error Renderer11::copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) +{ TextureStorage11_Cube *storage11 = GetAs(storage); ASSERT(storage11); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + storage11->markLevelDirty(level); - const bool invertSource = UsePresentPathFast(this, colorbuffer); - if (invertSource) - { - sourceArea.y = sourceSize.height - sourceRect.y; - sourceArea.height = -sourceArea.height; - } + return gl::NoError(); +} - gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); +gl::Error Renderer11::copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) +{ + TextureStorage11_3D *storage11 = GetAs(storage); + ASSERT(storage11); - // 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, false); - if (error.isError()) - { - return error; - } + gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); - storage11->invalidateSwizzleCacheLevel(level); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); - return gl::Error(GL_NO_ERROR); + storage11->markLevelDirty(level); + + return gl::NoError(); } -gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer11::copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + TextureStorage11_2DArray *storage11 = GetAs(storage); + ASSERT(storage11); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); + ASSERT(destRenderTarget); - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + ANGLE_TRY(copyImageInternal(context, framebuffer, sourceRect, destFormat, destOffset, + destRenderTarget)); + storage11->markLevelDirty(level); - TextureStorage11_3D *storage11 = GetAs(storage); - ASSERT(storage11); + return gl::NoError(); +} - gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); +gl::Error Renderer11::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + TextureD3D *sourceD3D = GetImplAs(source); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage)); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + TextureStorage11_2D *sourceStorage11 = GetAs(sourceStorage); + ASSERT(sourceStorage11); - gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + TextureStorage11 *destStorage11 = GetAs(storage); + ASSERT(destStorage11); - // 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, false); - if (error.isError()) + // Check for fast path where a CopySubresourceRegion can be used. + if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !unpackFlipY && + source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format == destFormat && + sourceStorage11->getFormatSet().texFormat == destStorage11->getFormatSet().texFormat) { - return error; - } + const TextureHelper11 *sourceResource = nullptr; + ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource)); - storage11->invalidateSwizzleCacheLevel(level); + gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); + UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); - return gl::Error(GL_NO_ERROR); -} + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(destStorage11->getResource(context, &destResource)); -gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) -{ - const gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); + gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel); + UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); + D3D11_BOX sourceBox{ + static_cast(sourceRect.x), + static_cast(sourceRect.y), + 0u, + static_cast(sourceRect.x + sourceRect.width), + static_cast(sourceRect.y + sourceRect.height), + 1u, + }; - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); + mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, destOffset.x, + destOffset.y, destOffset.z, sourceResource->get(), + sourceSubresource, &sourceBox); + } + else + { + const d3d11::SharedSRV *sourceSRV = nullptr; + ANGLE_TRY(sourceStorage11->getSRVLevels(context, sourceLevel, sourceLevel, &sourceSRV)); - TextureStorage11_2DArray *storage11 = GetAs(storage); - ASSERT(storage11); + gl::ImageIndex destIndex = gl::ImageIndex::MakeGeneric(destTarget, destLevel); + RenderTargetD3D *destRenderTargetD3D = nullptr; + ANGLE_TRY(destStorage11->getRenderTarget(context, destIndex, &destRenderTargetD3D)); - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); - RenderTargetD3D *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); + RenderTarget11 *destRenderTarget11 = GetAs(destRenderTargetD3D); - ID3D11RenderTargetView *dest = GetAs(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); + const d3d11::RenderTargetView &destRTV = destRenderTarget11->getRenderTargetView(); + ASSERT(destRTV.valid()); - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize( + static_cast(source->getWidth(source->getTarget(), sourceLevel)), + static_cast(source->getHeight(source->getTarget(), sourceLevel)), 1); + if (unpackFlipY) + { + sourceArea.y += sourceArea.height; + 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); + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget11->getWidth(), destRenderTarget11->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, false); - if (error.isError()) - { - return error; + // Use nearest filtering because source and destination are the same size for the direct + // copy + GLenum sourceFormat = source->getFormat(GL_TEXTURE_2D, sourceLevel).info->format; + ANGLE_TRY(mBlit->copyTexture(context, *sourceSRV, sourceArea, sourceSize, sourceFormat, + destRTV, destArea, destSize, nullptr, destFormat, GL_NEAREST, + false, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } - storage11->invalidateSwizzleCacheLevel(level); + destStorage11->markLevelDirty(destLevel); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Renderer11::unapplyRenderTargets() +gl::Error Renderer11::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) { - setOneTimeRenderTarget(NULL); -} + TextureStorage11_2D *destStorage11 = GetAs(storage); + ASSERT(destStorage11); -// When finished with this rendertarget, markAllStateDirty must be called. -void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) -{ - ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(destStorage11->getResource(context, &destResource)); - rtvArray[0] = renderTargetView; + gl::ImageIndex destIndex = gl::ImageIndex::Make2D(destLevel); + UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); - mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); + TextureD3D *sourceD3D = GetImplAs(source); + ASSERT(sourceD3D); - // Do not preserve the serial for this one-time-use render target - for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) - { - mAppliedRTVs[rtIndex] = angle::DirtyPointer; - } - mAppliedDSV = angle::DirtyPointer; + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(sourceD3D->getNativeTexture(context, &sourceStorage)); + + TextureStorage11_2D *sourceStorage11 = GetAs(sourceStorage); + ASSERT(sourceStorage11); + + const TextureHelper11 *sourceResource = nullptr; + ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource)); + + gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); + UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); + + mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, 0, 0, 0, + sourceResource->get(), sourceSubresource, nullptr); + + return gl::NoError(); } -gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +gl::Error Renderer11::createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) { - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mRenderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(format, mRenderer11DeviceCaps); - const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); + const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); if (width > 0 && height > 0) { // Create texture resource D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = formatInfo.texFormat; - desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = formatInfo.texFormat; + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; // If a rendertarget or depthstencil format exists for this texture format, // we'll flag it to allow binding that way. Shader resource views are a little @@ -2987,110 +2707,105 @@ gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, G bool bindRTV = false, bindDSV = false, bindSRV = false; bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); - if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + bindSRV = (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN); + + bool isMultisampledDepthStencil = bindDSV && desc.SampleDesc.Count > 1; + if (isMultisampledDepthStencil && + !mRenderer11DeviceCaps.supportsMultisampledDepthStencilSRVs) { - // Multisample targets flagged for binding as depth stencil cannot also be - // flagged for binding as SRV, so make certain not to add the SRV flag for - // these targets. - bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + bindSRV = false; } - desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | - (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); // The format must be either an RTV or a DSV ASSERT(bindRTV != bindDSV); - ID3D11Texture2D *texture = NULL; - HRESULT result = mDevice->CreateTexture2D(&desc, NULL, &texture); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target texture, result: 0x%X.", result); - } + TextureHelper11 texture; + ANGLE_TRY(allocateTexture(desc, formatInfo, &texture)); - ID3D11ShaderResourceView *srv = NULL; + d3d11::SharedSRV srv; + d3d11::SharedSRV blitSRV; if (bindSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = formatInfo.srvFormat; - srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Format = formatInfo.srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MipLevels = 1; - result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); - if (FAILED(result)) + ANGLE_TRY(allocateResource(srvDesc, texture.get(), &srv)); + + if (formatInfo.blitSRVFormat != formatInfo.srvFormat) + { + D3D11_SHADER_RESOURCE_VIEW_DESC blitSRVDesc; + blitSRVDesc.Format = formatInfo.blitSRVFormat; + blitSRVDesc.ViewDimension = (supportedSamples == 0) + ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; + blitSRVDesc.Texture2D.MostDetailedMip = 0; + blitSRVDesc.Texture2D.MipLevels = 1; + + ANGLE_TRY(allocateResource(blitSRVDesc, texture.get(), &blitSRV)); + } + else { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target shader resource view, result: 0x%X.", result); + blitSRV = srv.makeCopy(); } } if (bindDSV) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = formatInfo.dsvFormat; - dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Format = formatInfo.dsvFormat; + dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D + : D3D11_DSV_DIMENSION_TEXTURE2DMS; dsvDesc.Texture2D.MipSlice = 0; - dsvDesc.Flags = 0; - - ID3D11DepthStencilView *dsv = NULL; - result = mDevice->CreateDepthStencilView(texture, &dsvDesc, &dsv); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target depth stencil view, result: 0x%X.", result); - } + dsvDesc.Flags = 0; - *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); + d3d11::DepthStencilView dsv; + ANGLE_TRY(allocateResource(dsvDesc, texture.get(), &dsv)); - SafeRelease(dsv); + *outRT = new TextureRenderTarget11(std::move(dsv), texture, srv, format, formatInfo, + width, height, 1, supportedSamples); } else if (bindRTV) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = formatInfo.rtvFormat; - rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; + rtvDesc.Format = formatInfo.rtvFormat; + rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D + : D3D11_RTV_DIMENSION_TEXTURE2DMS; rtvDesc.Texture2D.MipSlice = 0; - ID3D11RenderTargetView *rtv = NULL; - result = mDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target render target view, result: 0x%X.", result); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(allocateResource(rtvDesc, texture.get(), &rtv)); - if (formatInfo.dataInitializerFunction != NULL) + if (formatInfo.dataInitializerFunction != nullptr) { - const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - mDeviceContext->ClearRenderTargetView(rtv, clearValues); + const float clearValues[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + mDeviceContext->ClearRenderTargetView(rtv.get(), clearValues); } - *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); - - SafeRelease(rtv); + *outRT = new TextureRenderTarget11(std::move(rtv), texture, srv, blitSRV, format, + formatInfo, width, height, 1, supportedSamples); } else { UNREACHABLE(); } - - SafeRelease(texture); - SafeRelease(srv); } else { - *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); + *outRT = new TextureRenderTarget11(d3d11::RenderTargetView(), TextureHelper11(), + d3d11::SharedSRV(), d3d11::SharedSRV(), format, + d3d11::Format::Get(GL_NONE, mRenderer11DeviceCaps), + width, height, 1, supportedSamples); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) @@ -3098,58 +2813,35 @@ gl::Error Renderer11::createRenderTargetCopy(RenderTargetD3D *source, RenderTarg ASSERT(source != nullptr); RenderTargetD3D *newRT = nullptr; - gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), - source->getInternalFormat(), source->getSamples(), &newRT); - if (error.isError()) - { - return error; - } + ANGLE_TRY(createRenderTarget(source->getWidth(), source->getHeight(), + source->getInternalFormat(), source->getSamples(), &newRT)); RenderTarget11 *source11 = GetAs(source); RenderTarget11 *dest11 = GetAs(newRT); - mDeviceContext->CopySubresourceRegion(dest11->getTexture(), dest11->getSubresourceIndex(), 0, 0, - 0, source11->getTexture(), + mDeviceContext->CopySubresourceRegion(dest11->getTexture().get(), dest11->getSubresourceIndex(), + 0, 0, 0, source11->getTexture().get(), source11->getSubresourceIndex(), nullptr); *outRT = newRT; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data) -{ - return new Framebuffer11(data, this); -} - -ShaderImpl *Renderer11::createShader(const gl::Shader::Data &data) -{ - return new ShaderD3D(data); -} - -ProgramImpl *Renderer11::createProgram(const gl::Program::Data &data) -{ - return new ProgramD3D(data, this); -} - -gl::Error Renderer11::loadExecutable(const void *function, +gl::Error Renderer11::loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) { + ShaderData shaderData(function, length); + switch (type) { - case SHADER_VERTEX: + case gl::SHADER_VERTEX: { - ID3D11VertexShader *vertexShader = NULL; - ID3D11GeometryShader *streamOutShader = NULL; - - HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); - } + d3d11::VertexShader vertexShader; + d3d11::GeometryShader streamOutShader; + ANGLE_TRY(allocateResource(shaderData, &vertexShader)); if (!streamOutVaryings.empty()) { @@ -3163,88 +2855,80 @@ gl::Error Renderer11::loadExecutable(const void *function, entry.SemanticName = streamOutVarying.semanticName.c_str(); entry.SemanticIndex = streamOutVarying.semanticIndex; entry.StartComponent = 0; - entry.ComponentCount = static_cast(streamOutVarying.componentCount); - entry.OutputSlot = static_cast( + entry.ComponentCount = static_cast(streamOutVarying.componentCount); + entry.OutputSlot = static_cast( (separatedOutputBuffers ? streamOutVarying.outputSlot : 0)); soDeclaration.push_back(entry); } - result = mDevice->CreateGeometryShaderWithStreamOutput( - function, static_cast(length), soDeclaration.data(), - static_cast(soDeclaration.size()), NULL, 0, 0, NULL, - &streamOutShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); - } + ANGLE_TRY(allocateResource(shaderData, &soDeclaration, &streamOutShader)); } - *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); + *outExecutable = new ShaderExecutable11(function, length, std::move(vertexShader), + std::move(streamOutShader)); } break; - case SHADER_PIXEL: + case gl::SHADER_FRAGMENT: { - ID3D11PixelShader *pixelShader = NULL; - - HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); - } - - *outExecutable = new ShaderExecutable11(function, length, pixelShader); + d3d11::PixelShader pixelShader; + ANGLE_TRY(allocateResource(shaderData, &pixelShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(pixelShader)); } break; - case SHADER_GEOMETRY: + case gl::SHADER_GEOMETRY: { - ID3D11GeometryShader *geometryShader = NULL; - - HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); - } - - *outExecutable = new ShaderExecutable11(function, length, geometryShader); + d3d11::GeometryShader geometryShader; + ANGLE_TRY(allocateResource(shaderData, &geometryShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(geometryShader)); + } + break; + case gl::SHADER_COMPUTE: + { + d3d11::ComputeShader computeShader; + ANGLE_TRY(allocateResource(shaderData, &computeShader)); + *outExecutable = new ShaderExecutable11(function, length, std::move(computeShader)); } break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + default: + UNREACHABLE(); + return gl::InternalError(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) { - const char *profileType = NULL; + std::stringstream profileStream; + switch (type) { - case SHADER_VERTEX: - profileType = "vs"; - break; - case SHADER_PIXEL: - profileType = "ps"; - break; - case SHADER_GEOMETRY: - profileType = "gs"; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + case gl::SHADER_VERTEX: + profileStream << "vs"; + break; + case gl::SHADER_FRAGMENT: + profileStream << "ps"; + break; + case gl::SHADER_GEOMETRY: + profileStream << "gs"; + break; + case gl::SHADER_COMPUTE: + profileStream << "cs"; + break; + default: + UNREACHABLE(); + return gl::InternalError(); } - std::string profile = FormatString("%s_%d_%d%s", profileType, getMajorShaderModel(), getMinorShaderModel(), getShaderModelSuffix().c_str()); + profileStream << "_" << getMajorShaderModel() << "_" << getMinorShaderModel() + << getShaderModelSuffix(); + std::string profile = profileStream.str(); UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; @@ -3260,11 +2944,12 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, if (workarounds.enableIEEEStrictness) flags |= D3DCOMPILE_IEEE_STRICTNESS; - // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders + // when it would otherwise pass with alternative options. // Try the default flags first and if compilation fails, try some alternatives. std::vector configs; - configs.push_back(CompileConfig(flags, "default" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); + configs.push_back(CompileConfig(flags, "default")); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation")); configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); if (getMajorShaderModel() == 4 && getShaderModelSuffix() != "") @@ -3276,26 +2961,26 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control")); } - D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; + D3D_SHADER_MACRO loopMacros[] = {{"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0}}; - ID3DBlob *binary = NULL; + // TODO(jmadill): Use ComPtr? + ID3DBlob *binary = nullptr; std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, + &debugInfo)); - // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL - // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + // It's possible that binary is NULL if the compiler failed in all configurations. Set the + // executable to NULL and return GL_NO_ERROR to signify that there was a link error but the + // internal state is still OK. if (!binary) { - *outExectuable = NULL; - return gl::Error(GL_NO_ERROR); + *outExectuable = nullptr; + return gl::NoError(); } - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - streamOutVaryings, separatedOutputBuffers, outExectuable); + gl::Error error = loadExecutable(reinterpret_cast(binary->GetBufferPointer()), + binary->GetBufferSize(), type, streamOutVaryings, + separatedOutputBuffers, outExectuable); SafeRelease(binary); if (error.isError()) @@ -3308,12 +2993,17 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, (*outExectuable)->appendDebugInfo(debugInfo); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer11::ensureHLSLCompilerInitialized() +{ + return mCompiler.ensureInitialized(); } UniformStorageD3D *Renderer11::createUniformStorage(size_t storageSize) { - return new UniformStorage11(this, storageSize); + return new UniformStorage11(storageSize); } VertexBuffer *Renderer11::createVertexBuffer() @@ -3326,45 +3016,20 @@ IndexBuffer *Renderer11::createIndexBuffer() return new IndexBuffer11(this); } -BufferImpl *Renderer11::createBuffer() +StreamProducerImpl *Renderer11::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) { - Buffer11 *buffer = new Buffer11(this); - mAliveBuffers.insert(buffer); - return buffer; -} - -VertexArrayImpl *Renderer11::createVertexArray(const gl::VertexArray::Data &data) -{ - return new VertexArray11(data); -} - -QueryImpl *Renderer11::createQuery(GLenum type) -{ - return new Query11(this, type); -} - -FenceNVImpl *Renderer11::createFenceNV() -{ - return new FenceNV11(this); -} - -FenceSyncImpl *Renderer11::createFenceSync() -{ - return new FenceSync11(this); -} - -TransformFeedbackImpl* Renderer11::createTransformFeedback() -{ - return new TransformFeedbackD3D(); + return new StreamProducerNV12(this); } bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const { - ASSERT(getRendererExtensions().pixelBufferObject); + ASSERT(getNativeExtensions().pixelBufferObject); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); - const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mRenderer11DeviceCaps); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); + const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + const d3d11::Format &d3d11FormatInfo = + d3d11::Format::Get(internalFormat, mRenderer11DeviceCaps); // sRGB formats do not work with D3D11 buffer SRVs if (internalFormatInfo.colorEncoding == GL_SRGB) @@ -3385,7 +3050,19 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const } // We don't support formats which we can't represent without conversion - if (dxgiFormatInfo.internalFormat != internalFormat) + if (d3d11FormatInfo.format().glInternalFormat != internalFormat) + { + return false; + } + + // Buffer SRV creation for this format was not working on Windows 10. + if (d3d11FormatInfo.texFormat == DXGI_FORMAT_B5G5R5A1_UNORM) + { + return false; + } + + // This format is not supported as a buffer SRV. + if (d3d11FormatInfo.texFormat == DXGI_FORMAT_A8_UNORM) { return false; } @@ -3393,11 +3070,17 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const return true; } -gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer11::fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) { ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); - return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); + return mPixelTransfer->copyBufferToTexture(context, unpack, offset, destRenderTarget, + destinationFormat, sourcePixelsType, destArea); } ImageD3D *Renderer11::createImage() @@ -3405,31 +3088,44 @@ ImageD3D *Renderer11::createImage() return new Image11(this); } -gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src) +gl::Error Renderer11::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src) { Image11 *dest11 = GetAs(dest); - Image11 *src11 = GetAs(src); - return Image11::generateMipmap(dest11, src11); + Image11 *src11 = GetAs(src); + return Image11::GenerateMipmap(context, dest11, src11, mRenderer11DeviceCaps); } -gl::Error Renderer11::generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) +gl::Error Renderer11::generateMipmapUsingD3D(const gl::Context *context, + 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; - } + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(storage11->getSRVLevels(context, textureState.getEffectiveBaseLevel(), + textureState.getEffectiveMaxLevel(), &srv)); + + mDeviceContext->GenerateMips(srv->get()); - mDeviceContext->GenerateMips(srv); + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +gl::Error Renderer11::copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Image11 *dest11 = GetAs(dest); + Image11 *src11 = GetAs(source); + return Image11::CopyImage(context, dest11, src11, sourceRect, destOffset, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha, mRenderer11DeviceCaps); } TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) @@ -3438,53 +3134,75 @@ TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) return new TextureStorage11_2D(this, swapChain11); } -TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage) +TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) { - return new TextureStorage11_EGLImage(this, eglImage); + return new TextureStorage11_EGLImage(this, eglImage, GetAs(renderTargetD3D)); } -TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +TextureStorage *Renderer11::createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly); + return new TextureStorage11_External(this, stream, desc); } -TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); + return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, + hintLevelZeroOnly); } -TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, + hintLevelZeroOnly); } -TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { - return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, + levels); } -TextureImpl *Renderer11::createTexture(GLenum target) +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { - switch(target) - { - case GL_TEXTURE_2D: return new TextureD3D_2D(this); - case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); - case GL_TEXTURE_3D: return new TextureD3D_3D(this); - case GL_TEXTURE_2D_ARRAY: return new TextureD3D_2DArray(this); - default: - UNREACHABLE(); - } - - return NULL; + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, + levels); } -RenderbufferImpl *Renderer11::createRenderbuffer() +TextureStorage *Renderer11::createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) { - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - return renderbuffer; + return new TextureStorage11_2DMultisample(this, internalformat, width, height, levels, samples, + fixedSampleLocations); } -gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAttachment, +gl::Error Renderer11::readFromAttachment(const gl::Context *context, + const gl::FramebufferAttachment &srcAttachment, const gl::Rectangle &sourceArea, GLenum format, GLenum type, @@ -3497,17 +3215,11 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt 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()); + RenderTarget11 *rt11 = nullptr; + ANGLE_TRY(srcAttachment.getRenderTarget(context, &rt11)); + ASSERT(rt11->getTexture().valid()); - TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(rt11->getTexture()); + const TextureHelper11 &textureHelper = rt11->getTexture(); unsigned int sourceSubResource = rt11->getSubresourceIndex(); const gl::Extents &texSize = textureHelper.getExtents(); @@ -3535,52 +3247,42 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt if (safeArea.width == 0 || safeArea.height == 0) { // no work to do - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Extents safeSize(safeArea.width, safeArea.height, 1); - auto errorOrResult = CreateStagingTexture(textureHelper.getTextureType(), - textureHelper.getFormat(), safeSize, mDevice); - if (errorOrResult.isError()) - { - return errorOrResult.getError(); - } + TextureHelper11 stagingHelper; + ANGLE_TRY_RESULT( + createStagingTexture(textureHelper.getTextureType(), textureHelper.getFormatSet(), safeSize, + StagingAccess::READ), + stagingHelper); - 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) + if (textureHelper.is2D() && textureHelper.getSampleCount() > 1) { D3D11_TEXTURE2D_DESC resolveDesc; resolveDesc.Width = static_cast(texSize.width); resolveDesc.Height = static_cast(texSize.height); - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; resolveDesc.Format = textureHelper.getFormat(); - resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Count = 1; resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; - ID3D11Texture2D *resolveTex2D = nullptr; - HRESULT result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &resolveTex2D); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, - "Renderer11::readTextureData failed to create internal resolve " - "texture for ReadPixels, HRESULT: 0x%X.", - result); - } + ANGLE_TRY( + allocateTexture(resolveDesc, textureHelper.getFormatSet(), &resolvedTextureHelper)); - mDeviceContext->ResolveSubresource(resolveTex2D, 0, textureHelper.getTexture2D(), + mDeviceContext->ResolveSubresource(resolvedTextureHelper.get(), 0, textureHelper.get(), sourceSubResource, textureHelper.getFormat()); - resolvedTextureHelper = TextureHelper11::MakeAndReference(resolveTex2D); sourceSubResource = 0; srcTexture = &resolvedTextureHelper; @@ -3594,132 +3296,66 @@ gl::Error Renderer11::readFromAttachment(const gl::FramebufferAttachment &srcAtt // Select the correct layer from a 3D attachment srcBox.front = 0; - if (textureHelper.getTextureType() == GL_TEXTURE_3D) + if (textureHelper.is3D()) { srcBox.front = static_cast(srcAttachment.layer()); } srcBox.back = srcBox.front + 1; - mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0, - srcTexture->getResource(), sourceSubResource, &srcBox); - - if (invertTexture) - { - gl::PixelPackState invertTexturePack; - - // 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; - - PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0); - error = packPixels(stagingHelper, packParams, pixelsOut); + mDeviceContext->CopySubresourceRegion(stagingHelper.get(), 0, 0, 0, 0, srcTexture->get(), + sourceSubResource, &srcBox); - invertTexturePack.pixelBuffer.set(nullptr); - - return error; - } - else + gl::Buffer *packBuffer = context->getGLState().getTargetBuffer(gl::BufferBinding::PixelPack); + if (!invertTexture) { - PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, packBuffer, 0); return packPixels(stagingHelper, packParams, pixelsOut); } + + // 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 + gl::PixelPackState invertTexturePack; + invertTexturePack.alignment = pack.alignment; + invertTexturePack.reverseRowOrder = !pack.reverseRowOrder; + + PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, packBuffer, + 0); + gl::Error error = packPixels(stagingHelper, packParams, pixelsOut); + ANGLE_TRY(error); + return gl::NoError(); } gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, const PackPixelsParams ¶ms, uint8_t *pixelsOut) { - ID3D11Resource *readResource = textureHelper.getResource(); + ID3D11Resource *readResource = textureHelper.get(); D3D11_MAPPED_SUBRESOURCE mapping; HRESULT hr = mDeviceContext->Map(readResource, 0, D3D11_MAP_READ, 0, &mapping); if (FAILED(hr)) { ASSERT(hr == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal texture for reading, result: 0x%X.", hr); - } - - uint8_t *source; - int inputPitch; - if (params.pack.reverseRowOrder) - { - source = static_cast(mapping.pData) + mapping.RowPitch * (params.area.height - 1); - inputPitch = -static_cast(mapping.RowPitch); - } - else - { - source = static_cast(mapping.pData); - inputPitch = static_cast(mapping.RowPitch); - } - - 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) - { - uint8_t *dest = pixelsOut + params.offset; - for (int y = 0; y < params.area.height; y++) - { - memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceFormatInfo.pixelBytes); - } + return gl::OutOfMemory() << "Failed to map internal texture for reading, " << gl::FmtHR(hr); } - else - { - ColorCopyFunction fastCopyFunc = - dxgiFormatInfo.getFastCopyFunction(params.format, params.type); - GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); - const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); - - if (fastCopyFunc) - { - // Fast copy is possible through some special function - for (int y = 0; y < params.area.height; y++) - { - for (int x = 0; x < params.area.width; x++) - { - uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - fastCopyFunc(src, dest); - } - } - } - else - { - ColorReadFunction colorReadFunction = dxgiFormatInfo.colorReadFunction; - ColorWriteFunction colorWriteFunction = GetColorWriteFunction(params.format, params.type); - uint8_t temp[16]; // Maximum size of any Color type used. - static_assert(sizeof(temp) >= sizeof(gl::ColorF) && - sizeof(temp) >= sizeof(gl::ColorUI) && - sizeof(temp) >= sizeof(gl::ColorI), - "Unexpected size of gl::Color struct."); + uint8_t *source = static_cast(mapping.pData); + int inputPitch = static_cast(mapping.RowPitch); - for (int y = 0; y < params.area.height; y++) - { - for (int x = 0; x < params.area.width; x++) - { - uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + const auto &formatInfo = textureHelper.getFormatSet(); + ASSERT(formatInfo.format().glInternalFormat != GL_NONE); - // readFunc and writeFunc will be using the same type of color, CopyTexImage - // will not allow the copy otherwise. - colorReadFunction(src, temp); - colorWriteFunction(temp, dest); - } - } - } - } + PackPixels(params, formatInfo.format(), inputPitch, source, pixelsOut); mDeviceContext->Unmap(readResource, 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, +gl::Error Renderer11::blitRenderbufferRect(const gl::Context *context, + const gl::Rectangle &readRectIn, const gl::Rectangle &drawRectIn, RenderTargetD3D *readRenderTarget, RenderTargetD3D *drawRenderTarget, @@ -3735,63 +3371,64 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, ASSERT(colorBlit != (depthBlit || stencilBlit)); RenderTarget11 *drawRenderTarget11 = GetAs(drawRenderTarget); - if (!drawRenderTarget) + if (!drawRenderTarget11) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); + return gl::OutOfMemory() + << "Failed to retrieve the internal draw render target from the draw framebuffer."; } - ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); - unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); - ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); - ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); + const TextureHelper11 &drawTexture = drawRenderTarget11->getTexture(); + unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); RenderTarget11 *readRenderTarget11 = GetAs(readRenderTarget); - if (!readRenderTarget) + if (!readRenderTarget11) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); + return gl::OutOfMemory() + << "Failed to retrieve the internal read render target from the read framebuffer."; } - ID3D11Resource *readTexture = NULL; - ID3D11ShaderResourceView *readSRV = NULL; - unsigned int readSubresource = 0; - if (readRenderTarget->getSamples() > 0) + TextureHelper11 readTexture; + unsigned int readSubresource = 0; + d3d11::SharedSRV readSRV; + + if (readRenderTarget->isMultisampled()) { - ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); - ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject(unresolvedResource); + ANGLE_TRY_RESULT( + resolveMultisampledTexture(context, readRenderTarget11, depthBlit, stencilBlit), + readTexture); - if (unresolvedTexture) + if (!stencilBlit) { - readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); - readSubresource = 0; + const auto &readFormatSet = readTexture.getFormatSet(); - SafeRelease(unresolvedTexture); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + viewDesc.Format = readFormatSet.srvFormat; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MipLevels = 1; + viewDesc.Texture2D.MostDetailedMip = 0; - HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); - if (FAILED(hresult)) - { - SafeRelease(readTexture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader resource view to resolve multisampled framebuffer."); - } + ANGLE_TRY(allocateResource(viewDesc, readTexture.get(), &readSRV)); } } else { - readTexture = readRenderTarget11->getTexture(); - readTexture->AddRef(); + ASSERT(readRenderTarget11); + readTexture = readRenderTarget11->getTexture(); readSubresource = readRenderTarget11->getSubresourceIndex(); - readSRV = readRenderTarget11->getShaderResourceView(); - readSRV->AddRef(); + readSRV = readRenderTarget11->getBlitShaderResourceView().makeCopy(); + if (!readSRV.valid()) + { + ASSERT(depthBlit || stencilBlit); + readSRV = readRenderTarget11->getShaderResourceView().makeCopy(); + } + ASSERT(readSRV.valid()); } - if (!readTexture || !readSRV) - { - SafeRelease(readTexture); - SafeRelease(readSRV); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target view from the read render target."); - } + // Stencil blits don't use shaders. + ASSERT(readSRV.valid() || stencilBlit); - gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); - gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + const gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + const 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 @@ -3801,8 +3438,32 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, // by internally scaling the read and draw rectangles. gl::Rectangle readRect = readRectIn; gl::Rectangle drawRect = drawRectIn; - auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) + + auto flip = [](int val) { return val >= 0 ? 1 : -1; }; + + if (readRect.x > readSize.width && readRect.width < 0) + { + int delta = readRect.x - readSize.width; + readRect.x -= delta; + readRect.width += delta; + + int drawDelta = delta * flip(drawRect.width); + drawRect.x += drawDelta; + drawRect.width -= drawDelta; + } + + if (readRect.y > readSize.height && readRect.height < 0) { + int delta = readRect.y - readSize.height; + readRect.y -= delta; + readRect.height += delta; + + int drawDelta = delta * flip(drawRect.height); + drawRect.y += drawDelta; + drawRect.height -= drawDelta; + } + + auto readToDrawX = [&drawRectIn, &readRectIn](int readOffset) { double readToDrawScale = static_cast(drawRectIn.width) / static_cast(readRectIn.width); return static_cast(round(static_cast(readOffset) * readToDrawScale)); @@ -3818,8 +3479,7 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, drawRect.width -= drawOffset; } - auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) - { + auto readToDrawY = [&drawRectIn, &readRectIn](int readOffset) { double readToDrawScale = static_cast(drawRectIn.height) / static_cast(readRectIn.height); return static_cast(round(static_cast(readOffset) * readToDrawScale)); @@ -3853,24 +3513,41 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, drawRect.height += drawOffset; } - bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); + if (readRect.x1() > readSize.width) + { + int delta = readRect.x1() - readSize.width; + readRect.width -= delta; + drawRect.width -= delta * flip(drawRect.width); + } + + if (readRect.y1() > readSize.height) + { + int delta = readRect.y1() - readSize.height; + readRect.height -= delta; + drawRect.height -= delta * flip(drawRect.height); + } + + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, nullptr); - const auto &destFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()); - const auto &srcFormatInfo = gl::GetInternalFormatInfo(readRenderTarget->getInternalFormat()); - const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat()); + const auto &destFormatInfo = + gl::GetSizedInternalFormatInfo(drawRenderTarget->getInternalFormat()); + const auto &srcFormatInfo = + gl::GetSizedInternalFormatInfo(readRenderTarget->getInternalFormat()); + const auto &formatSet = drawRenderTarget11->getFormatSet(); + const auto &nativeFormat = formatSet.format(); // 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.red = + (srcFormatInfo.redBits > 0) && (destFormatInfo.redBits == 0) && (nativeFormat.redBits > 0); colorMask.green = (srcFormatInfo.greenBits > 0) && (destFormatInfo.greenBits == 0) && - (dxgiFormatInfo.greenBits > 0); + (nativeFormat.greenBits > 0); colorMask.blue = (srcFormatInfo.blueBits > 0) && (destFormatInfo.blueBits == 0) && - (dxgiFormatInfo.blueBits > 0); + (nativeFormat.blueBits > 0); colorMask.alpha = (srcFormatInfo.alphaBits > 0) && (destFormatInfo.alphaBits == 0) && - (dxgiFormatInfo.alphaBits > 0); + (nativeFormat.alphaBits > 0); // We only currently support masking off the alpha channel. bool colorMaskingNeeded = colorMask.alpha; @@ -3884,18 +3561,19 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; - bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; + bool flipRequired = + readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || readRect.y < 0 || readRect.y + readRect.height > readSize.height || drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; - bool partialDSBlit = (dxgiFormatInfo.depthBits > 0 && depthBlit) != (dxgiFormatInfo.stencilBits > 0 && stencilBlit); + bool partialDSBlit = + (nativeFormat.depthBits > 0 && depthBlit) != (nativeFormat.stencilBits > 0 && stencilBlit); - gl::Error result(GL_NO_ERROR); - - if (readRenderTarget11->getDXGIFormat() == drawRenderTarget11->getDXGIFormat() && + if (readRenderTarget11->getFormatSet().formatID == + drawRenderTarget11->getFormatSet().formatID && !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && !colorMaskingNeeded && (!(depthBlit || stencilBlit) || wholeBufferCopy)) { @@ -3903,16 +3581,17 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, UINT dstY = drawRect.y; D3D11_BOX readBox; - readBox.left = readRect.x; - readBox.right = readRect.x + readRect.width; - readBox.top = readRect.y; + readBox.left = readRect.x; + readBox.right = readRect.x + readRect.width; + readBox.top = readRect.y; readBox.bottom = readRect.y + readRect.height; - readBox.front = 0; - readBox.back = 1; + readBox.front = 0; + readBox.back = 1; if (scissorNeeded) { - // drawRect is guaranteed to have positive width and height because stretchRequired is false. + // drawRect is guaranteed to have positive width and height because stretchRequired is + // false. ASSERT(drawRect.width >= 0 || drawRect.height >= 0); if (drawRect.x < scissor->x) @@ -3937,11 +3616,10 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox // We also require complete framebuffer copies for depth-stencil blit. - D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + D3D11_BOX *pSrcBox = wholeBufferCopy ? nullptr : &readBox; - mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, - readTexture, readSubresource, pSrcBox); - result = gl::Error(GL_NO_ERROR); + mDeviceContext->CopySubresourceRegion(drawTexture.get(), drawSubresource, dstX, dstY, 0, + readTexture.get(), readSubresource, pSrcBox); } else { @@ -3950,47 +3628,56 @@ gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRectIn, if (depthBlit && stencilBlit) { - result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); + ANGLE_TRY(mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor)); } else if (depthBlit) { - result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, - scissor); + const d3d11::DepthStencilView &drawDSV = drawRenderTarget11->getDepthStencilView(); + ASSERT(readSRV.valid()); + ANGLE_TRY(mBlit->copyDepth(context, readSRV, readArea, readSize, drawDSV, drawArea, + drawSize, scissor)); } else if (stencilBlit) { - result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); + ANGLE_TRY(mBlit->copyStencil(context, readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor)); } else { + const d3d11::RenderTargetView &drawRTV = drawRenderTarget11->getRenderTargetView(); + // 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, destFormatInfo.format, filter, maskOffAlpha); + ASSERT(readSRV.valid()); + ANGLE_TRY(mBlit->copyTexture( + context, readSRV, readArea, readSize, srcFormatInfo.format, drawRTV, drawArea, + drawSize, scissor, destFormatInfo.format, filter, maskOffAlpha, false, false)); } } - SafeRelease(readTexture); - SafeRelease(readSRV); - - return result; + return gl::NoError(); } bool Renderer11::isES3Capable() const { - return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel) > 2); -}; + return (d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel).major > 2); +} + +RendererClass Renderer11::getRendererClass() const +{ + return RENDERER_D3D11; +} void Renderer11::onSwap() { // Send histogram updates every half hour const double kHistogramUpdateInterval = 30 * 60; - const double currentTime = ANGLEPlatformCurrent()->monotonicallyIncreasingTime(); + auto *platform = ANGLEPlatformCurrent(); + const double currentTime = platform->monotonicallyIncreasingTime(platform); const double timeSinceLastUpdate = currentTime - mLastHistogramUpdateTime; if (timeSinceLastUpdate > kHistogramUpdateInterval) @@ -4005,7 +3692,7 @@ void Renderer11::updateHistograms() // Update the buffer CPU memory histogram { size_t sizeSum = 0; - for (auto &buffer : mAliveBuffers) + for (const Buffer11 *buffer : mAliveBuffers) { sizeSum += buffer->getTotalCPUBufferMemoryBytes(); } @@ -4015,53 +3702,71 @@ void Renderer11::updateHistograms() } } +void Renderer11::onBufferCreate(const Buffer11 *created) +{ + mAliveBuffers.insert(created); +} + void Renderer11::onBufferDelete(const Buffer11 *deleted) { mAliveBuffers.erase(deleted); } -ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) +gl::ErrorOrResult Renderer11::resolveMultisampledTexture( + const gl::Context *context, + RenderTarget11 *renderTarget, + bool depth, + bool stencil) { - D3D11_TEXTURE2D_DESC textureDesc; - source->GetDesc(&textureDesc); + if (depth && !stencil) + { + return mBlit->resolveDepth(context, renderTarget); + } - if (textureDesc.SampleDesc.Count > 1) + if (stencil) { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = textureDesc.Usage; - resolveDesc.BindFlags = textureDesc.BindFlags; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; + return mBlit->resolveStencil(context, renderTarget, depth); + } - ID3D11Texture2D *resolveTexture = NULL; - HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); - if (FAILED(result)) - { - ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); - return NULL; - } + const auto &formatSet = renderTarget->getFormatSet(); - mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); - return resolveTexture; - } - else + ASSERT(renderTarget->isMultisampled()); + const d3d11::SharedSRV &sourceSRV = renderTarget->getShaderResourceView(); + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + sourceSRV.get()->GetDesc(&sourceSRVDesc); + ASSERT(sourceSRVDesc.ViewDimension == D3D_SRV_DIMENSION_TEXTURE2DMS); + + if (!mCachedResolveTexture.valid() || + mCachedResolveTexture.getExtents().width != renderTarget->getWidth() || + mCachedResolveTexture.getExtents().height != renderTarget->getHeight() || + mCachedResolveTexture.getFormat() != formatSet.texFormat) { - source->AddRef(); - return source; + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = renderTarget->getWidth(); + resolveDesc.Height = renderTarget->getHeight(); + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = formatSet.texFormat; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ANGLE_TRY(allocateTexture(resolveDesc, formatSet, &mCachedResolveTexture)); } + + mDeviceContext->ResolveSubresource(mCachedResolveTexture.get(), 0, + renderTarget->getTexture().get(), + renderTarget->getSubresourceIndex(), formatSet.texFormat); + return mCachedResolveTexture; } bool Renderer11::getLUID(LUID *adapterLuid) const { adapterLuid->HighPart = 0; - adapterLuid->LowPart = 0; + adapterLuid->LowPart = 0; if (!mDxgiAdapter) { @@ -4078,45 +3783,70 @@ bool Renderer11::getLUID(LUID *adapterLuid) const return true; } -VertexConversionType Renderer11::getVertexConversionType(gl::VertexFormatType vertexFormatType) const +VertexConversionType Renderer11::getVertexConversionType( + gl::VertexFormatType vertexFormatType) const { - return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).conversionType; + return d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel) + .conversionType; } GLenum Renderer11::getVertexComponentType(gl::VertexFormatType vertexFormatType) const { - return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel).nativeFormat).componentType; + const auto &format = + d3d11::GetVertexFormatInfo(vertexFormatType, mRenderer11DeviceCaps.featureLevel); + return d3d11::GetComponentType(format.nativeFormat); } -void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, - gl::Extensions *outExtensions, gl::Limitations *outLimitations) const +gl::ErrorOrResult Renderer11::getVertexSpaceRequired( + const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const { - d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, - outExtensions, outLimitations); -} + if (!attrib.enabled) + { + return 16u; + } -WorkaroundsD3D Renderer11::generateWorkarounds() const -{ - return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps.featureLevel); + unsigned int elementCount = 0; + const unsigned int divisor = binding.getDivisor(); + if (instances == 0 || divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), divisor); + } + + gl::VertexFormatType formatType = gl::GetVertexFormatType(attrib); + const D3D_FEATURE_LEVEL featureLevel = mRenderer11DeviceCaps.featureLevel; + const d3d11::VertexFormat &vertexFormatInfo = + d3d11::GetVertexFormatInfo(formatType, featureLevel); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(vertexFormatInfo.nativeFormat); + unsigned int elementSize = dxgiFormatInfo.pixelBytes; + if (elementSize > std::numeric_limits::max() / elementCount) + { + return gl::OutOfMemory() << "New vertex buffer size would result in an overflow."; + } + + return elementSize * elementCount; } -void Renderer11::createAnnotator() +void Renderer11::generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, + gl::Extensions *outExtensions, + gl::Limitations *outLimitations) const { - // 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 + d3d11_gl::GenerateCaps(mDevice, mDeviceContext, mRenderer11DeviceCaps, outCaps, outTextureCaps, + outExtensions, outLimitations); } -gl::Error Renderer11::clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) +angle::WorkaroundsD3D Renderer11::generateWorkarounds() const { - return mStateManager.clearTextures(samplerType, rangeStart, rangeEnd); + return d3d11::GenerateWorkarounds(mRenderer11DeviceCaps, mAdapterDescription); } egl::Error Renderer11::getEGLDevice(DeviceImpl **device) @@ -4136,6 +3866,224 @@ egl::Error Renderer11::getEGLDevice(DeviceImpl **device) } *device = static_cast(mEGLDevice); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); +} + +ContextImpl *Renderer11::createContext(const gl::ContextState &state) +{ + return new Context11(state, this); +} + +FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::FramebufferState &state) +{ + return new Framebuffer11(state, this); +} + +gl::Error Renderer11::getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut) +{ + if (!mScratchMemoryBuffer.get(requestedSize, bufferOut)) + { + return gl::OutOfMemory() << "Failed to allocate internal buffer."; + } + return gl::NoError(); +} + +gl::Version Renderer11::getMaxSupportedESVersion() const +{ + return d3d11_gl::GetMaximumClientVersion(mRenderer11DeviceCaps.featureLevel); +} + +gl::DebugAnnotator *Renderer11::getAnnotator() +{ + return mAnnotator; +} + +gl::Error Renderer11::applyComputeShader(const gl::Context *context) +{ + ANGLE_TRY(ensureHLSLCompilerInitialized()); + + const auto &glState = context->getGLState(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ShaderExecutableD3D *computeExe = nullptr; + ANGLE_TRY(programD3D->getComputeExecutable(&computeExe)); + ASSERT(computeExe != nullptr); + + mStateManager.setComputeShader(&GetAs(computeExe)->getComputeShader()); + ANGLE_TRY(mStateManager.applyComputeUniforms(programD3D)); + + return gl::NoError(); +} + +gl::Error Renderer11::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + ANGLE_TRY(mStateManager.updateStateForCompute(context, numGroupsX, numGroupsY, numGroupsZ)); + ANGLE_TRY(applyComputeShader(context)); + + mDeviceContext->Dispatch(numGroupsX, numGroupsY, numGroupsZ); + + return gl::NoError(); +} + +gl::ErrorOrResult Renderer11::createStagingTexture( + ResourceType textureType, + const d3d11::Format &formatSet, + const gl::Extents &size, + StagingAccess readAndWriteAccess) +{ + if (textureType == ResourceType::Texture2D) + { + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = formatSet.texFormat; + 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; + + if (readAndWriteAccess == StagingAccess::READ_WRITE) + { + stagingDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + + TextureHelper11 stagingTex; + ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex)); + return stagingTex; + } + ASSERT(textureType == ResourceType::Texture3D); + + D3D11_TEXTURE3D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.Depth = 1; + stagingDesc.MipLevels = 1; + stagingDesc.Format = formatSet.texFormat; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + TextureHelper11 stagingTex; + ANGLE_TRY(allocateTexture(stagingDesc, formatSet, &stagingTex)); + return stagingTex; +} + +gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE2D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut) +{ + d3d11::Texture2D texture; + ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture)); + textureOut->init(std::move(texture), desc, format); + return gl::NoError(); +} + +gl::Error Renderer11::allocateTexture(const D3D11_TEXTURE3D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut) +{ + d3d11::Texture3D texture; + ANGLE_TRY(mResourceManager11.allocate(this, &desc, initData, &texture)); + textureOut->init(std::move(texture), desc, format); + return gl::NoError(); +} + +gl::Error Renderer11::getBlendState(const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState) +{ + return mStateCache.getBlendState(this, key, outBlendState); +} + +gl::Error Renderer11::getRasterizerState(const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState) +{ + return mStateCache.getRasterizerState(this, rasterState, scissorEnabled, outRasterizerState); } + +gl::Error Renderer11::getDepthStencilState(const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState) +{ + return mStateCache.getDepthStencilState(this, dsState, outDSState); +} + +gl::Error Renderer11::getSamplerState(const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState) +{ + return mStateCache.getSamplerState(this, samplerState, outSamplerState); +} + +gl::Error Renderer11::clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) +{ + RenderTarget11 *rt11 = GetAs(renderTarget); + + if (rt11->getDepthStencilView().valid()) + { + const auto &format = rt11->getFormatSet(); + const UINT clearFlags = (format.format().depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) | + (format.format().stencilBits ? D3D11_CLEAR_STENCIL : 0); + mDeviceContext->ClearDepthStencilView(rt11->getDepthStencilView().get(), clearFlags, + clearDepthValue, + static_cast(clearStencilValue)); + return gl::NoError(); + } + + ASSERT(rt11->getRenderTargetView().valid()); + ID3D11RenderTargetView *rtv = rt11->getRenderTargetView().get(); + + // There are complications with some types of RTV and FL 9_3 with ClearRenderTargetView. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ff476388(v=vs.85).aspx + ASSERT(mRenderer11DeviceCaps.featureLevel > D3D_FEATURE_LEVEL_9_3 || !IsArrayRTV(rtv)); + + const auto &d3d11Format = rt11->getFormatSet(); + const auto &glFormat = gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat()); + + gl::ColorF safeClearColor = clearColorValue; + + if (d3d11Format.format().alphaBits > 0 && glFormat.alphaBits == 0) + { + safeClearColor.alpha = 1.0f; + } + + mDeviceContext->ClearRenderTargetView(rtv, &safeClearColor.red); + return gl::NoError(); +} + +bool Renderer11::canSelectViewInVertexShader() const +{ + return !getWorkarounds().selectViewInGeometryShader && + getRenderer11DeviceCaps().supportsVpRtIndexWriteFromVertexShader; +} + +gl::Error Renderer11::markTransformFeedbackUsage(const gl::Context *context) +{ + const gl::State &glState = context->getGLState(); + const gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const gl::OffsetBindingPointer &binding = + transformFeedback->getIndexedBuffer(i); + if (binding.get() != nullptr) + { + BufferD3D *bufferD3D = GetImplAs(binding.get()); + ANGLE_TRY(bufferD3D->markTransformFeedbackUsage(context)); + } + } + + return gl::NoError(); } + +} // namespace rx 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 b4e7761ffc..a8c24e681b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h @@ -14,13 +14,14 @@ #include "libANGLE/AttributeMap.h" #include "libANGLE/angletypes.h" #include "libANGLE/renderer/d3d/HLSLCompiler.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.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" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" #include "libANGLE/renderer/d3d/d3d11/StateManager11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" namespace gl { @@ -28,36 +29,46 @@ class FramebufferAttachment; struct ImageIndex; } -struct ID3D11DeviceContext1; - namespace rx { - -class VertexDataManager; -class IndexDataManager; -class StreamingIndexBufferInterface; class Blit11; class Buffer11; class Clear11; +class Context11; +class IndexDataManager; +struct PackPixelsParams; class PixelTransfer11; class RenderTarget11; +class StreamingIndexBufferInterface; class Trim11; -struct PackPixelsParams; +class VertexDataManager; struct Renderer11DeviceCaps { + 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 + bool supportsDXGI1_2; // Support for DXGI 1.2 + bool supportsClearView; // Support for ID3D11DeviceContext1::ClearView + bool supportsConstantBufferOffsets; // Support for Constant buffer offset + bool supportsVpRtIndexWriteFromVertexShader; // VP/RT can be selected in the Vertex Shader + // stage. + bool supportsMultisampledDepthStencilSRVs; // D3D feature level 10.0 no longer allows creation + // of textures with both the bind SRV and DSV flags + // when multisampled. Textures will need to be + // resolved before reading. crbug.com/656989 + UINT B5G6R5support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G6R5_UNORM + UINT B5G6R5maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B5G6R5_UNORM + UINT B4G4R4A4support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B4G4R4A4_UNORM + UINT B4G4R4A4maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B4G4R4A4_UNORM + UINT B5G5R5A1support; // Bitfield of D3D11_FORMAT_SUPPORT values for DXGI_FORMAT_B5G5R5A1_UNORM + UINT B5G5R5A1maxSamples; // Maximum number of samples supported by DXGI_FORMAT_B5G5R5A1_UNORM + Optional driverVersion; // Four-part driver version number. }; enum { - MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, + MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 }; @@ -103,172 +114,244 @@ class Renderer11 : public RendererD3D { public: explicit Renderer11(egl::Display *display); - virtual ~Renderer11(); + ~Renderer11() override; egl::Error initialize() override; - virtual bool resetDevice(); + bool resetDevice() override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override; - gl::Error flush() override; - gl::Error finish() override; + ContextImpl *createContext(const gl::ContextState &state) override; + + gl::Error flush(); + gl::Error finish(); - SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + bool isValidNativeWindow(EGLNativeWindowType window) const override; + NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const override; + + SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) override; - - 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; - 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; + EGLint orientation, + EGLint samples) override; + egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const override; + egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const override; + + bool applyPrimitiveType(const gl::State &glState, GLenum mode, GLsizei count); // lost device bool testDeviceLost() override; bool testDeviceResettable() override; - std::string getRendererDescription() const override; + std::string getRendererDescription() const; DeviceIdentifier getAdapterIdentifier() const override; - virtual unsigned int getReservedVertexUniformVectors() const; - virtual unsigned int getReservedFragmentUniformVectors() const; - virtual unsigned int getReservedVertexUniformBuffers() const; - virtual unsigned int getReservedFragmentUniformBuffers() const; + unsigned int getReservedVertexUniformVectors() const; + unsigned int getReservedFragmentUniformVectors() const; + unsigned int getReservedVertexUniformBuffers() const; + unsigned int getReservedFragmentUniformBuffers() const; bool getShareHandleSupport() const; - virtual int getMajorShaderModel() const; + bool getNV12TextureSupport() const; + + int getMajorShaderModel() const override; int getMinorShaderModel() const override; std::string getShaderModelSuffix() const override; // Pixel operations - virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); - virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level); + gl::Error copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) override; + gl::Error copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) override; // RenderTarget creation - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + gl::Error createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) override; gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override; - // Framebuffer creation - FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; - - // Shader creation - ShaderImpl *createShader(const gl::Shader::Data &data) override; - ProgramImpl *createProgram(const gl::Program::Data &data) override; - // Shader operations - gl::Error loadExecutable(const void *function, + gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) override; gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) override; + gl::Error ensureHLSLCompilerInitialized() 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); - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - - // Texture creation - virtual TextureImpl *createTexture(GLenum target); - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer(); - - // Buffer creation - virtual BufferImpl *createBuffer(); - virtual VertexBuffer *createVertexBuffer(); - virtual IndexBuffer *createIndexBuffer(); - - // Vertex Array creation - VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); + ImageD3D *createImage() override; + gl::Error generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *source) override; + gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) override; + gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; + TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) override; + TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + TextureStorage *createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) override; + + VertexBuffer *createVertexBuffer() override; + IndexBuffer *createIndexBuffer() override; + + // Stream Creation + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; // 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; } + IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + + gl::Error getBlendState(const d3d11::BlendStateKey &key, + const d3d11::BlendState **outBlendState); + gl::Error getRasterizerState(const gl::RasterizerState &rasterState, + bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, + const d3d11::DepthStencilState **outDSState); + gl::Error getSamplerState(const gl::SamplerState &samplerState, + ID3D11SamplerState **outSamplerState); Blit11 *getBlitter() { return mBlit; } Clear11 *getClearer() { return mClear; } + gl::DebugAnnotator *getAnnotator(); // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override; + gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) override; - void markAllStateDirty(); - void unapplyRenderTargets(); - void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); gl::Error packPixels(const TextureHelper11 &textureHelper, const PackPixelsParams ¶ms, uint8_t *pixelsOut); bool getLUID(LUID *adapterLuid) const override; - VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override; + VertexConversionType getVertexConversionType( + gl::VertexFormatType vertexFormatType) const override; GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override; - gl::Error readFromAttachment(const gl::FramebufferAttachment &srcAttachment, + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + gl::ErrorOrResult getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const override; + + gl::Error readFromAttachment(const gl::Context *context, + const gl::FramebufferAttachment &srcAttachment, const gl::Rectangle &sourceArea, GLenum format, GLenum type, @@ -276,145 +359,175 @@ class Renderer11 : public RendererD3D 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); + gl::Error blitRenderbufferRect(const gl::Context *context, + 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; - const Renderer11DeviceCaps &getRenderer11DeviceCaps() { return mRenderer11DeviceCaps; }; + const Renderer11DeviceCaps &getRenderer11DeviceCaps() const { return mRenderer11DeviceCaps; }; - RendererClass getRendererClass() const override { return RENDERER_D3D11; } - InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; } + RendererClass getRendererClass() const override; StateManager11 *getStateManager() { return &mStateManager; } void onSwap(); + void onBufferCreate(const Buffer11 *created); void onBufferDelete(const Buffer11 *deleted); 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; + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint startVertex, + GLsizei count, + GLsizei instances); - void syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override; + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + + gl::Error drawArraysIndirect(const gl::Context *context, GLenum mode, const void *indirect); + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect); + + // Necessary hack for default framebuffers in D3D. + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + gl::Error getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut); + + gl::Version getMaxSupportedESVersion() const override; + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); + gl::Error applyComputeShader(const gl::Context *context); + + gl::ErrorOrResult createStagingTexture(ResourceType textureType, + const d3d11::Format &formatSet, + const gl::Extents &size, + StagingAccess readAndWriteAccess); + + template + gl::Error allocateResource(const DescT &desc, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, &desc, nullptr, resourceOut); + } + + template + gl::Error allocateResource(const DescT &desc, InitDataT *initData, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, &desc, initData, resourceOut); + } + + template + gl::Error allocateResourceNoDesc(InitDataT *initData, ResourceT *resourceOut) + { + return mResourceManager11.allocate(this, nullptr, initData, resourceOut); + } + + template + gl::Error allocateTexture(const DescT &desc, + const d3d11::Format &format, + TextureHelper11 *textureOut) + { + return allocateTexture(desc, format, nullptr, textureOut); + } + + gl::Error allocateTexture(const D3D11_TEXTURE2D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut); + + gl::Error allocateTexture(const D3D11_TEXTURE3D_DESC &desc, + const d3d11::Format &format, + const D3D11_SUBRESOURCE_DATA *initData, + TextureHelper11 *textureOut); + + gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) override; + + bool canSelectViewInVertexShader() const 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, + void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, gl::Limitations *outLimitations) const override; - WorkaroundsD3D generateWorkarounds() const override; + angle::WorkaroundsD3D generateWorkarounds() const override; - gl::Error drawLineLoop(const gl::Data &data, + gl::Error drawLineLoop(const gl::Context *context, GLsizei count, GLenum type, - const GLvoid *indices, - const TranslatedIndexData *indexInfo, + const void *indices, + int baseVertex, int instances); - gl::Error drawTriangleFan(const gl::Data &data, + gl::Error drawTriangleFan(const gl::Context *context, GLsizei count, GLenum type, - const GLvoid *indices, - int minIndex, + const void *indices, + int baseVertex, int instances); - ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + gl::ErrorOrResult resolveMultisampledTexture(const gl::Context *context, + RenderTarget11 *renderTarget, + bool depth, + bool stencil); void populateRenderer11DeviceCaps(); void updateHistograms(); - HMODULE mD3d11Module; - HMODULE mDxgiModule; - HMODULE mDCompModule; - std::vector mAvailableFeatureLevels; - D3D_DRIVER_TYPE mRequestedDriverType; - bool mCreatedWithDeviceEXT; - DeviceD3D *mEGLDevice; + gl::Error copyImageInternal(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + RenderTargetD3D *destRenderTarget); - HLSLCompiler mCompiler; + gl::SupportedSampleSet generateSampleSetForEGLConfig( + const gl::TextureCaps &colorBufferFormatCaps, + const gl::TextureCaps &depthStencilBufferFormatCaps) const; + HRESULT callD3D11CreateDevice(PFN_D3D11_CREATE_DEVICE createDevice, bool debug); egl::Error initializeD3DDevice(); - void initializeDevice(); + egl::Error initializeDevice(); void releaseDeviceResources(); void release(); d3d11::ANGLED3D11DeviceType getDeviceType() const; - RenderStateCache mStateCache; + gl::Error markTransformFeedbackUsage(const gl::Context *context); - // current render target states - uintptr_t mAppliedRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - uintptr_t mAppliedDSV; + HMODULE mD3d11Module; + HMODULE mDxgiModule; + HMODULE mDCompModule; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mRequestedDriverType; + bool mCreateDebugDevice; + bool mCreatedWithDeviceEXT; + DeviceD3D *mEGLDevice; - // Currently applied sampler states - std::vector mForceSetVertexSamplerStates; - std::vector mCurVertexSamplerStates; + HLSLCompiler mCompiler; - std::vector mForceSetPixelSamplerStates; - std::vector mCurPixelSamplerStates; + RenderStateCache mStateCache; StateManager11 mStateManager; - // Currently applied primitive topology - D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; - - // Currently applied index buffer - ID3D11Buffer *mAppliedIB; - DXGI_FORMAT mAppliedIBFormat; - unsigned int mAppliedIBOffset; - bool mAppliedIBChanged; - - // Currently applied transform feedback buffers - size_t mAppliedNumXFBBindings; - ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers - // in use for streamout - GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified - // buffer offsets to transform feedback - // buffers - UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, - // which may differ from GLs, due - // to different append behavior - - // Currently applied shaders - uintptr_t mAppliedVertexShader; - uintptr_t mAppliedGeometryShader; - uintptr_t mAppliedPixelShader; - - 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_PixelConstants11 mAppliedPixelConstants; - ID3D11Buffer *mDriverConstantBufferPS; - ID3D11Buffer *mCurrentPixelConstantBuffer; - unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; - GLintptr mCurrentConstantBufferPSOffset[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; - GLsizeiptr mCurrentConstantBufferPSSize[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; - - ID3D11Buffer *mCurrentGeometryConstantBuffer; - - // Vertex, index and input layouts - VertexDataManager *mVertexDataManager; - IndexDataManager *mIndexDataManager; - InputLayoutCache mInputLayoutCache; - StreamingIndexBufferInterface *mLineLoopIB; StreamingIndexBufferInterface *mTriangleFanIB; @@ -429,10 +542,10 @@ class Renderer11 : public RendererD3D Trim11 *mTrim; // Sync query - ID3D11Query *mSyncQuery; + d3d11::Query mSyncQuery; // Created objects state tracking - std::set mAliveBuffers; + std::set mAliveBuffers; double mLastHistogramUpdateTime; @@ -440,18 +553,24 @@ class Renderer11 : public RendererD3D Renderer11DeviceCaps mRenderer11DeviceCaps; ID3D11DeviceContext *mDeviceContext; ID3D11DeviceContext1 *mDeviceContext1; + ID3D11DeviceContext3 *mDeviceContext3; IDXGIAdapter *mDxgiAdapter; DXGI_ADAPTER_DESC mAdapterDescription; char mDescription[128]; - DXGIFactory *mDxgiFactory; -#if !defined(ANGLE_MINGW32_COMPAT) + IDXGIFactory *mDxgiFactory; ID3D11Debug *mDebug; -#endif std::vector mScratchIndexDataBuffer; + angle::ScratchBuffer mScratchMemoryBuffer; + + gl::DebugAnnotator *mAnnotator; + mutable Optional mSupportsShareHandles; + ResourceManager11 mResourceManager11; + + TextureHelper11 mCachedResolveTexture; }; -} -#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ +} // namespace rx +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp new file mode 100644 index 0000000000..c228380a34 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp @@ -0,0 +1,533 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ResourceManager11: +// Centralized point of allocation for all D3D11 Resources. + +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +namespace +{ + +constexpr uint8_t kDebugInitTextureDataValue = 0x48; +constexpr FLOAT kDebugColorInitClearValue[4] = {0.3f, 0.5f, 0.7f, 0.5f}; +constexpr FLOAT kDebugDepthInitValue = 0.2f; +constexpr UINT8 kDebugStencilInitValue = 3; + +uint64_t ComputeMippedMemoryUsage(unsigned int width, + unsigned int height, + unsigned int depth, + uint64_t pixelSize, + unsigned int mipLevels) +{ + uint64_t sizeSum = 0; + + for (unsigned int level = 0; level < mipLevels; ++level) + { + unsigned int mipWidth = std::max(width >> level, 1u); + unsigned int mipHeight = std::max(height >> level, 1u); + unsigned int mipDepth = std::max(depth >> level, 1u); + sizeSum += static_cast(mipWidth * mipHeight * mipDepth) * pixelSize; + } + + return sizeSum; +} + +uint64_t ComputeMemoryUsage(const D3D11_TEXTURE2D_DESC *desc) +{ + ASSERT(desc); + uint64_t pixelBytes = + static_cast(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); + return ComputeMippedMemoryUsage(desc->Width, desc->Height, 1, pixelBytes, desc->MipLevels); +} + +uint64_t ComputeMemoryUsage(const D3D11_TEXTURE3D_DESC *desc) +{ + ASSERT(desc); + uint64_t pixelBytes = + static_cast(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes); + return ComputeMippedMemoryUsage(desc->Width, desc->Height, desc->Depth, pixelBytes, + desc->MipLevels); +} + +uint64_t ComputeMemoryUsage(const D3D11_BUFFER_DESC *desc) +{ + ASSERT(desc); + return static_cast(desc->ByteWidth); +} + +template +uint64_t ComputeMemoryUsage(const T *desc) +{ + return 0; +} + +template +uint64_t ComputeGenericMemoryUsage(ID3D11DeviceChild *genericResource) +{ + auto *typedResource = static_cast *>(genericResource); + GetDescType desc; + typedResource->GetDesc(&desc); + return ComputeMemoryUsage(&desc); +} + +uint64_t ComputeGenericMemoryUsage(ResourceType resourceType, ID3D11DeviceChild *resource) +{ + switch (resourceType) + { + case ResourceType::Texture2D: + return ComputeGenericMemoryUsage(resource); + case ResourceType::Texture3D: + return ComputeGenericMemoryUsage(resource); + case ResourceType::Buffer: + return ComputeGenericMemoryUsage(resource); + + default: + return 0; + } +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_BLEND_DESC *desc, + void * /*initData*/, + ID3D11BlendState **blendState) +{ + return device->CreateBlendState(desc, blendState); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_BUFFER_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Buffer **buffer) +{ + return device->CreateBuffer(desc, initData, buffer); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11ComputeShader **resourceOut) +{ + return device->CreateComputeShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_DEPTH_STENCIL_DESC *desc, + void * /*initData*/, + ID3D11DepthStencilState **resourceOut) +{ + return device->CreateDepthStencilState(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_DEPTH_STENCIL_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11DepthStencilView **resourceOut) +{ + return device->CreateDepthStencilView(resource, desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + const std::vector *initData, + ID3D11GeometryShader **resourceOut) +{ + if (initData) + { + return device->CreateGeometryShaderWithStreamOutput( + desc->get(), desc->size(), initData->data(), static_cast(initData->size()), + nullptr, 0, 0, nullptr, resourceOut); + } + else + { + return device->CreateGeometryShader(desc->get(), desc->size(), nullptr, resourceOut); + } +} + +HRESULT CreateResource(ID3D11Device *device, + const InputElementArray *desc, + const ShaderData *initData, + ID3D11InputLayout **resourceOut) +{ + return device->CreateInputLayout(desc->get(), static_cast(desc->size()), initData->get(), + initData->size(), resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11PixelShader **resourceOut) +{ + return device->CreatePixelShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_QUERY_DESC *desc, + void * /*initData*/, + ID3D11Query **resourceOut) +{ + return device->CreateQuery(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_RASTERIZER_DESC *desc, + void * /*initData*/, + ID3D11RasterizerState **rasterizerState) +{ + return device->CreateRasterizerState(desc, rasterizerState); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_RENDER_TARGET_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11RenderTargetView **renderTargetView) +{ + return device->CreateRenderTargetView(resource, desc, renderTargetView); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_SAMPLER_DESC *desc, + void * /*initData*/, + ID3D11SamplerState **resourceOut) +{ + return device->CreateSamplerState(desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_SHADER_RESOURCE_VIEW_DESC *desc, + ID3D11Resource *resource, + ID3D11ShaderResourceView **resourceOut) +{ + return device->CreateShaderResourceView(resource, desc, resourceOut); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_TEXTURE2D_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Texture2D **texture) +{ + return device->CreateTexture2D(desc, initData, texture); +} + +HRESULT CreateResource(ID3D11Device *device, + const D3D11_TEXTURE3D_DESC *desc, + const D3D11_SUBRESOURCE_DATA *initData, + ID3D11Texture3D **texture) +{ + return device->CreateTexture3D(desc, initData, texture); +} + +HRESULT CreateResource(ID3D11Device *device, + const ShaderData *desc, + void * /*initData*/, + ID3D11VertexShader **resourceOut) +{ + return device->CreateVertexShader(desc->get(), desc->size(), nullptr, resourceOut); +} + +DXGI_FORMAT GetTypedDepthStencilFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_R16_TYPELESS: + return DXGI_FORMAT_D16_UNORM; + case DXGI_FORMAT_R24G8_TYPELESS: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_D32_FLOAT; + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + return dxgiFormat; + } +} + +template +gl::Error ClearResource(Renderer11 *renderer, const DescT *desc, ResourceT *texture) +{ + // No-op. + return gl::NoError(); +} + +template <> +gl::Error ClearResource(Renderer11 *renderer, + const D3D11_TEXTURE2D_DESC *desc, + ID3D11Texture2D *texture) +{ + ID3D11DeviceContext *context = renderer->getDeviceContext(); + + if ((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Flags = 0; + dsvDesc.Format = GetTypedDepthStencilFormat(desc->Format); + + const auto &format = d3d11_angle::GetFormat(dsvDesc.Format); + UINT clearFlags = (format.depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) | + (format.stencilBits > 0 ? D3D11_CLEAR_STENCIL : 0); + + // Must process each mip level individually. + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + if (desc->SampleDesc.Count == 0) + { + dsvDesc.Texture2D.MipSlice = mipLevel; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + } + else + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } + + d3d11::DepthStencilView dsv; + ANGLE_TRY(renderer->allocateResource(dsvDesc, texture, &dsv)); + + context->ClearDepthStencilView(dsv.get(), clearFlags, kDebugDepthInitValue, + kDebugStencilInitValue); + } + } + else + { + ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); + d3d11::RenderTargetView rtv; + ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv)); + + context->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); + } + + return gl::NoError(); +} + +template <> +gl::Error ClearResource(Renderer11 *renderer, + const D3D11_TEXTURE3D_DESC *desc, + ID3D11Texture3D *texture) +{ + ID3D11DeviceContext *context = renderer->getDeviceContext(); + + ASSERT((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) == 0); + ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0); + + d3d11::RenderTargetView rtv; + ANGLE_TRY(renderer->allocateResourceNoDesc(texture, &rtv)); + + context->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue); + return gl::NoError(); +} + +#define ANGLE_RESOURCE_STRINGIFY_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) #RESTYPE, + +constexpr std::array kResourceTypeNames = { + {ANGLE_RESOURCE_TYPE_OP(Stringify, ANGLE_RESOURCE_STRINGIFY_OP)}}; +static_assert(kResourceTypeNames[NumResourceTypes - 1] != nullptr, + "All members must be initialized."); + +} // anonymous namespace + +// ResourceManager11 Implementation. +ResourceManager11::ResourceManager11() + : mInitializeAllocations(false), + mAllocatedResourceCounts({{}}), + mAllocatedResourceDeviceMemory({{}}) +{ +} + +ResourceManager11::~ResourceManager11() +{ + for (size_t count : mAllocatedResourceCounts) + { + ASSERT(count == 0); + } + + for (uint64_t memorySize : mAllocatedResourceDeviceMemory) + { + ASSERT(memorySize == 0); + } +} + +template +gl::Error ResourceManager11::allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + Resource11 *resourceOut) +{ + ID3D11Device *device = renderer->getDevice(); + T *resource = nullptr; + + GetInitDataFromD3D11 *shadowInitData = initData; + if (!shadowInitData && mInitializeAllocations) + { + shadowInitData = createInitDataIfNeeded(desc); + } + + HRESULT hr = CreateResource(device, desc, shadowInitData, &resource); + if (FAILED(hr)) + { + ASSERT(!resource); + if (d3d11::isDeviceLostError(hr)) + { + renderer->notifyDeviceLost(); + } + return gl::OutOfMemory() << "Error allocating " + << std::string(kResourceTypeNames[ResourceTypeIndex()]) << ". " + << gl::FmtHR(hr); + } + + if (!shadowInitData && mInitializeAllocations) + { + ANGLE_TRY(ClearResource(renderer, desc, resource)); + } + + ASSERT(resource); + incrResource(GetResourceTypeFromD3D11(), ComputeMemoryUsage(desc)); + *resourceOut = std::move(Resource11(resource, this)); + return gl::NoError(); +} + +void ResourceManager11::incrResource(ResourceType resourceType, uint64_t memorySize) +{ + size_t typeIndex = ResourceTypeIndex(resourceType); + + mAllocatedResourceCounts[typeIndex]++; + mAllocatedResourceDeviceMemory[typeIndex] += memorySize; + + // This checks for integer overflow. + ASSERT(mAllocatedResourceCounts[typeIndex] > 0); + ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); +} + +void ResourceManager11::decrResource(ResourceType resourceType, uint64_t memorySize) +{ + size_t typeIndex = ResourceTypeIndex(resourceType); + + ASSERT(mAllocatedResourceCounts[typeIndex] > 0); + mAllocatedResourceCounts[typeIndex]--; + ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize); + mAllocatedResourceDeviceMemory[typeIndex] -= memorySize; +} + +void ResourceManager11::onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource) +{ + ASSERT(resource); + decrResource(resourceType, ComputeGenericMemoryUsage(resourceType, resource)); +} + +template <> +const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded( + const D3D11_TEXTURE2D_DESC *desc) +{ + ASSERT(desc); + + if ((desc->BindFlags & (D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_RENDER_TARGET)) != 0) + { + // This will be done using ClearView methods. + return nullptr; + } + + size_t requiredSize = static_cast(ComputeMemoryUsage(desc)); + if (mZeroMemory.size() < requiredSize) + { + mZeroMemory.resize(requiredSize); + mZeroMemory.fill(kDebugInitTextureDataValue); + } + + const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); + + UINT subresourceCount = desc->MipLevels * desc->ArraySize; + if (mShadowInitData.size() < subresourceCount) + { + mShadowInitData.resize(subresourceCount); + } + + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + for (UINT arrayIndex = 0; arrayIndex < desc->ArraySize; ++arrayIndex) + { + UINT subresourceIndex = D3D11CalcSubresource(mipLevel, arrayIndex, desc->MipLevels); + D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; + + UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); + UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); + + data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; + data->SysMemSlicePitch = data->SysMemPitch * levelHeight; + data->pSysMem = mZeroMemory.data(); + } + } + + return mShadowInitData.data(); +} + +template <> +const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded( + const D3D11_TEXTURE3D_DESC *desc) +{ + ASSERT(desc); + + if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0) + { + // This will be done using ClearView methods. + return nullptr; + } + + size_t requiredSize = static_cast(ComputeMemoryUsage(desc)); + if (mZeroMemory.size() < requiredSize) + { + mZeroMemory.resize(requiredSize); + mZeroMemory.fill(kDebugInitTextureDataValue); + } + + const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format); + + UINT subresourceCount = desc->MipLevels; + if (mShadowInitData.size() < subresourceCount) + { + mShadowInitData.resize(subresourceCount); + } + + for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel) + { + UINT subresourceIndex = D3D11CalcSubresource(mipLevel, 0, desc->MipLevels); + D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex]; + + UINT levelWidth = std::max(desc->Width >> mipLevel, 1u); + UINT levelHeight = std::max(desc->Height >> mipLevel, 1u); + + data->SysMemPitch = levelWidth * formatSizeInfo.pixelBytes; + data->SysMemSlicePitch = data->SysMemPitch * levelHeight; + data->pSysMem = mZeroMemory.data(); + } + + return mShadowInitData.data(); +} + +template +GetInitDataFromD3D11 *ResourceManager11::createInitDataIfNeeded(const GetDescFromD3D11 *desc) +{ + // No-op. + return nullptr; +} + +void ResourceManager11::setAllocationsInitialized(bool initialize) +{ + mInitializeAllocations = initialize; +} + +#define ANGLE_INSTANTIATE_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template \ +gl::Error \ + ResourceManager11::allocate(Renderer11 *, const DESCTYPE *, INITDATATYPE *, \ + Resource11 *); + +ANGLE_RESOURCE_TYPE_OP(Instantitate, ANGLE_INSTANTIATE_OP) +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h new file mode 100644 index 0000000000..0bdde9f8b6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h @@ -0,0 +1,366 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ResourceManager11: +// Centralized point of allocation for all D3D11 Resources. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ + +#include +#include + +#include "common/MemoryBuffer.h" +#include "common/angleutils.h" +#include "common/debug.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ +// These two methods are declared here to prevent circular includes. +namespace d3d11 +{ +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template +HRESULT SetDebugName(angle::ComPtr &resource, const char *name) +{ + return SetDebugName(resource.Get(), name); +} +} // namespace d3d11 + +class Renderer11; +class ResourceManager11; +template +class SharedResource11; +class TextureHelper11; + +using InputElementArray = WrappedArray; +using ShaderData = WrappedArray; + +// Format: ResourceType, D3D11 type, DESC type, init data type. +#define ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + OP(NAME, BlendState, ID3D11BlendState, D3D11_BLEND_DESC, void) \ + OP(NAME, Buffer, ID3D11Buffer, D3D11_BUFFER_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, ComputeShader, ID3D11ComputeShader, ShaderData, void) \ + OP(NAME, DepthStencilState, ID3D11DepthStencilState, D3D11_DEPTH_STENCIL_DESC, void) \ + OP(NAME, DepthStencilView, ID3D11DepthStencilView, D3D11_DEPTH_STENCIL_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, GeometryShader, ID3D11GeometryShader, ShaderData, \ + const std::vector) \ + OP(NAME, InputLayout, ID3D11InputLayout, InputElementArray, const ShaderData) \ + OP(NAME, PixelShader, ID3D11PixelShader, ShaderData, void) \ + OP(NAME, Query, ID3D11Query, D3D11_QUERY_DESC, void) \ + OP(NAME, RasterizerState, ID3D11RasterizerState, D3D11_RASTERIZER_DESC, void) \ + OP(NAME, RenderTargetView, ID3D11RenderTargetView, D3D11_RENDER_TARGET_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, SamplerState, ID3D11SamplerState, D3D11_SAMPLER_DESC, void) \ + OP(NAME, ShaderResourceView, ID3D11ShaderResourceView, D3D11_SHADER_RESOURCE_VIEW_DESC, \ + ID3D11Resource) \ + OP(NAME, Texture2D, ID3D11Texture2D, D3D11_TEXTURE2D_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, Texture3D, ID3D11Texture3D, D3D11_TEXTURE3D_DESC, const D3D11_SUBRESOURCE_DATA) \ + OP(NAME, VertexShader, ID3D11VertexShader, ShaderData, void) + +#define ANGLE_RESOURCE_TYPE_LIST(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) RESTYPE, + +enum class ResourceType +{ + ANGLE_RESOURCE_TYPE_OP(List, ANGLE_RESOURCE_TYPE_LIST) Last +}; + +#undef ANGLE_RESOURCE_TYPE_LIST + +constexpr size_t ResourceTypeIndex(ResourceType resourceType) +{ + return static_cast(resourceType); +} + +constexpr size_t NumResourceTypes = ResourceTypeIndex(ResourceType::Last); + +#define ANGLE_RESOURCE_TYPE_TO_D3D11(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = D3D11TYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_DESC(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = DESCTYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_INIT_DATA(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + using Value = INITDATATYPE; \ + }; + +#define ANGLE_RESOURCE_TYPE_TO_TYPE(NAME, OP) \ + template \ + struct NAME; \ + ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + \ +template struct NAME \ + { \ + }; \ + \ +template using Get##NAME = typename NAME::Value; + +ANGLE_RESOURCE_TYPE_TO_TYPE(D3D11Type, ANGLE_RESOURCE_TYPE_TO_D3D11) +ANGLE_RESOURCE_TYPE_TO_TYPE(DescType, ANGLE_RESOURCE_TYPE_TO_DESC) +ANGLE_RESOURCE_TYPE_TO_TYPE(InitDataType, ANGLE_RESOURCE_TYPE_TO_INIT_DATA) + +#undef ANGLE_RESOURCE_TYPE_TO_D3D11 +#undef ANGLE_RESOURCE_TYPE_TO_DESC +#undef ANGLE_RESOURCE_TYPE_TO_INIT_DATA +#undef ANGLE_RESOURCE_TYPE_TO_TYPE + +#define ANGLE_TYPE_TO_RESOURCE_TYPE(NAME, OP) \ + template \ + struct NAME; \ + ANGLE_RESOURCE_TYPE_OP(NAME, OP) \ + \ +template struct NAME \ + { \ + }; \ + \ +template constexpr ResourceType Get##NAME() \ + { \ + return NAME::Value; \ + } + +#define ANGLE_D3D11_TO_RESOURCE_TYPE(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + \ +template<> struct NAME \ + { \ + static constexpr ResourceType Value = ResourceType::RESTYPE; \ + }; + +ANGLE_TYPE_TO_RESOURCE_TYPE(ResourceTypeFromD3D11, ANGLE_D3D11_TO_RESOURCE_TYPE) + +#undef ANGLE_D3D11_TO_RESOURCE_TYPE +#undef ANGLE_TYPE_TO_RESOURCE_TYPE + +template +using GetDescFromD3D11 = GetDescType::Value>; + +template +using GetInitDataFromD3D11 = GetInitDataType::Value>; + +template +constexpr size_t ResourceTypeIndex() +{ + return static_cast(GetResourceTypeFromD3D11()); +} + +template +struct TypedData +{ + TypedData() {} + ~TypedData(); + + T *object = nullptr; + ResourceManager11 *manager = nullptr; +}; + +// Smart pointer type. Wraps the resource and a factory for safe deletion. +template class Pointer, typename DataT> +class Resource11Base : angle::NonCopyable +{ + public: + T *get() const { return mData->object; } + T *const *getPointer() const { return &mData->object; } + + void setDebugName(const char *name) { d3d11::SetDebugName(mData->object, name); } + + void set(T *object) + { + ASSERT(!valid()); + mData->object = object; + } + + bool valid() const { return (mData->object != nullptr); } + + void reset() + { + if (valid()) + mData.reset(new DataT()); + } + + ResourceSerial getSerial() const + { + return ResourceSerial(reinterpret_cast(mData->object)); + } + + protected: + friend class TextureHelper11; + + Resource11Base() : mData(new DataT()) {} + + Resource11Base(Resource11Base &&movedObj) : mData(new DataT()) + { + std::swap(mData, movedObj.mData); + } + + virtual ~Resource11Base() { mData.reset(); } + + Resource11Base &operator=(Resource11Base &&movedObj) + { + std::swap(mData, movedObj.mData); + return *this; + } + + Pointer mData; +}; + +template +using UniquePtr = typename std::unique_ptr>; + +template +class Resource11 : public Resource11Base> +{ + public: + Resource11() {} + Resource11(Resource11 &&other) + : Resource11Base>(std::move(other)) + { + } + Resource11 &operator=(Resource11 &&other) + { + std::swap(this->mData, other.mData); + return *this; + } + + private: + template + friend class SharedResource11; + friend class ResourceManager11; + + Resource11(ResourceT *object, ResourceManager11 *manager) + { + this->mData->object = object; + this->mData->manager = manager; + } +}; + +template +class SharedResource11 : public Resource11Base> +{ + public: + SharedResource11() {} + SharedResource11(SharedResource11 &&movedObj) + : Resource11Base>(std::move(movedObj)) + { + } + + SharedResource11 &operator=(SharedResource11 &&other) + { + std::swap(this->mData, other.mData); + return *this; + } + + SharedResource11 makeCopy() const + { + SharedResource11 copy; + copy.mData = this->mData; + return std::move(copy); + } + + private: + friend class ResourceManager11; + SharedResource11(Resource11 &&obj) : Resource11Base>() + { + std::swap(this->mData->manager, obj.mData->manager); + + // Can't use std::swap because of ID3D11Resource. + auto temp = this->mData->object; + this->mData->object = obj.mData->object; + obj.mData->object = static_cast(temp); + } +}; + +class ResourceManager11 final : angle::NonCopyable +{ + public: + ResourceManager11(); + ~ResourceManager11(); + + template + gl::Error allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + Resource11 *resourceOut); + + template + gl::Error allocate(Renderer11 *renderer, + const GetDescFromD3D11 *desc, + GetInitDataFromD3D11 *initData, + SharedResource11 *sharedRes) + { + Resource11 res; + ANGLE_TRY(allocate(renderer, desc, initData, &res)); + *sharedRes = std::move(res); + return gl::NoError(); + } + + template + void onRelease(T *resource) + { + onReleaseGeneric(GetResourceTypeFromD3D11(), resource); + } + + void onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource); + + void setAllocationsInitialized(bool initialize); + + private: + void incrResource(ResourceType resourceType, uint64_t memorySize); + void decrResource(ResourceType resourceType, uint64_t memorySize); + + template + GetInitDataFromD3D11 *createInitDataIfNeeded(const GetDescFromD3D11 *desc); + + bool mInitializeAllocations; + + std::array mAllocatedResourceCounts; + std::array mAllocatedResourceDeviceMemory; + angle::MemoryBuffer mZeroMemory; + + std::vector mShadowInitData; +}; + +template +TypedData::~TypedData() +{ + if (object) + { + // We can have a nullptr factory when holding passed-in resources. + if (manager) + { + manager->onRelease(object); + } + object->Release(); + } +} + +#define ANGLE_RESOURCE_TYPE_CLASS(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \ + using RESTYPE = Resource11; + +namespace d3d11 +{ +ANGLE_RESOURCE_TYPE_OP(ClassList, ANGLE_RESOURCE_TYPE_CLASS) + +using SharedSRV = SharedResource11; +} // namespace d3d11 + +#undef ANGLE_RESOURCE_TYPE_CLASS + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RESOURCEFACTORY11_H_ 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 4da51afe49..73a530add0 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -13,86 +13,107 @@ namespace rx { -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::PixelShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(std::move(executable)), + mVertexExecutable(), + mGeometryExecutable(), + mStreamOutExecutable(), + mComputeExecutable() { - mPixelExecutable = executable; - mVertexExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = NULL; } -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::VertexShader &&executable, + d3d11::GeometryShader &&streamOut) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(std::move(executable)), + mGeometryExecutable(), + mStreamOutExecutable(std::move(streamOut)), + mComputeExecutable() { - mVertexExecutable = executable; - mPixelExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = streamOut; } -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) - : ShaderExecutableD3D(function, length) +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::GeometryShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(), + mGeometryExecutable(std::move(executable)), + mStreamOutExecutable(), + mComputeExecutable() +{ +} + +ShaderExecutable11::ShaderExecutable11(const void *function, + size_t length, + d3d11::ComputeShader &&executable) + : ShaderExecutableD3D(function, length), + mPixelExecutable(), + mVertexExecutable(), + mGeometryExecutable(), + mStreamOutExecutable(), + mComputeExecutable(std::move(executable)) { - mGeometryExecutable = executable; - mVertexExecutable = NULL; - mPixelExecutable = NULL; - mStreamOutExecutable = NULL; } ShaderExecutable11::~ShaderExecutable11() { - SafeRelease(mVertexExecutable); - SafeRelease(mPixelExecutable); - SafeRelease(mGeometryExecutable); - SafeRelease(mStreamOutExecutable); } -ID3D11VertexShader *ShaderExecutable11::getVertexShader() const +const d3d11::VertexShader &ShaderExecutable11::getVertexShader() const { return mVertexExecutable; } -ID3D11PixelShader *ShaderExecutable11::getPixelShader() const +const d3d11::PixelShader &ShaderExecutable11::getPixelShader() const { return mPixelExecutable; } -ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const +const d3d11::GeometryShader &ShaderExecutable11::getGeometryShader() const { return mGeometryExecutable; } -ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const +const d3d11::GeometryShader &ShaderExecutable11::getStreamOutShader() const { return mStreamOutExecutable; } -UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) - : UniformStorageD3D(initialSize), - mConstantBuffer(NULL) +const d3d11::ComputeShader &ShaderExecutable11::getComputeShader() const { - ID3D11Device *d3d11Device = renderer->getDevice(); + return mComputeExecutable; +} - if (initialSize > 0) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = static_cast(initialSize); - constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; - - HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - } +UniformStorage11::UniformStorage11(size_t initialSize) + : UniformStorageD3D(initialSize), mConstantBuffer() +{ } UniformStorage11::~UniformStorage11() { - SafeRelease(mConstantBuffer); } +gl::Error UniformStorage11::getConstantBuffer(Renderer11 *renderer, const d3d11::Buffer **bufferOut) +{ + if (size() > 0 && !mConstantBuffer.valid()) + { + D3D11_BUFFER_DESC desc = {0}; + desc.ByteWidth = static_cast(size()); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + ANGLE_TRY(renderer->allocateResource(desc, &mConstantBuffer)); + } + + *bufferOut = &mConstantBuffer; + return gl::NoError(); } + +} // namespace rx 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 379f39fe53..3f417578a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h @@ -11,6 +11,7 @@ #define LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -20,36 +21,42 @@ class UniformStorage11; class ShaderExecutable11 : public ShaderExecutableD3D { public: - ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); - ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); - ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); - - virtual ~ShaderExecutable11(); - - ID3D11PixelShader *getPixelShader() const; - ID3D11VertexShader *getVertexShader() const; - ID3D11GeometryShader *getGeometryShader() const; - ID3D11GeometryShader *getStreamOutShader() const; + ShaderExecutable11(const void *function, size_t length, d3d11::PixelShader &&executable); + ShaderExecutable11(const void *function, + size_t length, + d3d11::VertexShader &&executable, + d3d11::GeometryShader &&streamOut); + ShaderExecutable11(const void *function, size_t length, d3d11::GeometryShader &&executable); + ShaderExecutable11(const void *function, size_t length, d3d11::ComputeShader &&executable); + + ~ShaderExecutable11() override; + + const d3d11::PixelShader &getPixelShader() const; + const d3d11::VertexShader &getVertexShader() const; + const d3d11::GeometryShader &getGeometryShader() const; + const d3d11::GeometryShader &getStreamOutShader() const; + const d3d11::ComputeShader &getComputeShader() const; private: - ID3D11PixelShader *mPixelExecutable; - ID3D11VertexShader *mVertexExecutable; - ID3D11GeometryShader *mGeometryExecutable; - ID3D11GeometryShader *mStreamOutExecutable; + d3d11::PixelShader mPixelExecutable; + d3d11::VertexShader mVertexExecutable; + d3d11::GeometryShader mGeometryExecutable; + d3d11::GeometryShader mStreamOutExecutable; + d3d11::ComputeShader mComputeExecutable; }; class UniformStorage11 : public UniformStorageD3D { public: - UniformStorage11(Renderer11 *renderer, size_t initialSize); - virtual ~UniformStorage11(); + UniformStorage11(size_t initialSize); + ~UniformStorage11() override; - ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + gl::Error getConstantBuffer(Renderer11 *renderer, const d3d11::Buffer **bufferOut); private: - ID3D11Buffer *mConstantBuffer; + d3d11::Buffer mConstantBuffer; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp index aa34fd4de8..e9902d3f14 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp @@ -8,11 +8,22 @@ #include "libANGLE/renderer/d3d/d3d11/StateManager11.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/Query.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" namespace rx { @@ -22,15 +33,16 @@ namespace bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) { unsigned mipLevel = index.mipIndex; - unsigned layerIndex = index.layerIndex; + GLint 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; + bool allLevels = (desc.Texture2D.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; unsigned mipMin = index.mipIndex; unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex; @@ -42,22 +54,25 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: { - unsigned maxSrvMip = + bool allLevels = (desc.Texture2DArray.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip; - maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip; + maxSrvMip = allLevels ? 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; + desc.Texture2DArray.FirstArraySlice <= static_cast(layerIndex) && + static_cast(layerIndex) < maxSlice; } case D3D11_SRV_DIMENSION_TEXTURECUBE: { - unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; - maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip; + bool allLevels = (desc.TextureCube.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; return gl::IsCubeMapTextureTarget(type) && desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; @@ -65,8 +80,9 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR case D3D11_SRV_DIMENSION_TEXTURE3D: { - unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; - maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip; + bool allLevels = (desc.Texture3D.MipLevels == std::numeric_limits::max()); + unsigned int maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; + maxSrvMip = allLevels ? INT_MAX : maxSrvMip; return type == GL_TEXTURE_3D && desc.Texture3D.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; @@ -82,15 +98,97 @@ bool ImageIndexConflictsWithSRV(const gl::ImageIndex &index, D3D11_SHADER_RESOUR // Does *not* increment the resource ref count!! ID3D11Resource *GetViewResource(ID3D11View *view) { - ID3D11Resource *resource = NULL; + ID3D11Resource *resource = nullptr; ASSERT(view); view->GetResource(&resource); resource->Release(); return resource; } +int GetWrapBits(GLenum wrap) +{ + switch (wrap) + { + case GL_CLAMP_TO_EDGE: + return 0x1; + case GL_REPEAT: + return 0x2; + case GL_MIRRORED_REPEAT: + return 0x3; + default: + UNREACHABLE(); + return 0; + } +} + +Optional FindFirstNonInstanced( + const std::vector ¤tAttributes) +{ + for (size_t index = 0; index < currentAttributes.size(); ++index) + { + if (currentAttributes[index]->divisor == 0) + { + return Optional(index); + } + } + + return Optional::Invalid(); +} + +void SortAttributesByLayout(const gl::Program *program, + const std::vector &vertexArrayAttribs, + const std::vector ¤tValueAttribs, + AttribIndexArray *sortedD3DSemanticsOut, + std::vector *sortedAttributesOut) +{ + sortedAttributesOut->clear(); + + const auto &locationToSemantic = + GetImplAs(program)->getAttribLocationToD3DSemantics(); + + for (auto locationIndex : program->getActiveAttribLocationsMask()) + { + int d3dSemantic = locationToSemantic[locationIndex]; + if (sortedAttributesOut->size() <= static_cast(d3dSemantic)) + { + sortedAttributesOut->resize(d3dSemantic + 1); + } + + (*sortedD3DSemanticsOut)[d3dSemantic] = d3dSemantic; + + const auto *arrayAttrib = &vertexArrayAttribs[locationIndex]; + if (arrayAttrib->attribute && arrayAttrib->attribute->enabled) + { + (*sortedAttributesOut)[d3dSemantic] = arrayAttrib; + } + else + { + ASSERT(currentValueAttribs[locationIndex].attribute); + (*sortedAttributesOut)[d3dSemantic] = ¤tValueAttribs[locationIndex]; + } + } +} + +void UpdateUniformBuffer(ID3D11DeviceContext *deviceContext, + UniformStorage11 *storage, + const d3d11::Buffer *buffer) +{ + deviceContext->UpdateSubresource(buffer->get(), 0, nullptr, storage->getDataPointer(0, 0), 0, + 0); +} + } // anonymous namespace +// StateManager11::SRVCache Implementation. + +StateManager11::SRVCache::SRVCache() : mHighestUsedSRV(0) +{ +} + +StateManager11::SRVCache::~SRVCache() +{ +} + void StateManager11::SRVCache::update(size_t resourceIndex, ID3D11ShaderResourceView *srv) { ASSERT(resourceIndex < mCurrentSRVs.size()); @@ -128,27 +226,348 @@ void StateManager11::SRVCache::clear() mHighestUsedSRV = 0; } +// ShaderConstants11 implementation + +ShaderConstants11::ShaderConstants11() + : mVertexDirty(true), + mPixelDirty(true), + mComputeDirty(true), + mSamplerMetadataVSDirty(true), + mSamplerMetadataPSDirty(true), + mSamplerMetadataCSDirty(true) +{ +} + +ShaderConstants11::~ShaderConstants11() +{ +} + +void ShaderConstants11::init(const gl::Caps &caps) +{ + mSamplerMetadataVS.resize(caps.maxVertexTextureImageUnits); + mSamplerMetadataPS.resize(caps.maxTextureImageUnits); + mSamplerMetadataCS.resize(caps.maxComputeTextureImageUnits); +} + +size_t ShaderConstants11::getRequiredBufferSize(gl::SamplerType samplerType) const +{ + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + return sizeof(Vertex) + mSamplerMetadataVS.size() * sizeof(SamplerMetadata); + case gl::SAMPLER_PIXEL: + return sizeof(Pixel) + mSamplerMetadataPS.size() * sizeof(SamplerMetadata); + case gl::SAMPLER_COMPUTE: + return sizeof(Compute) + mSamplerMetadataCS.size() * sizeof(SamplerMetadata); + default: + UNREACHABLE(); + return 0; + } +} + +void ShaderConstants11::markDirty() +{ + mVertexDirty = true; + mPixelDirty = true; + mComputeDirty = true; + mSamplerMetadataVSDirty = true; + mSamplerMetadataPSDirty = true; + mSamplerMetadataCSDirty = true; +} + +bool ShaderConstants11::updateSamplerMetadata(SamplerMetadata *data, const gl::Texture &texture) +{ + bool dirty = false; + unsigned int baseLevel = texture.getTextureState().getEffectiveBaseLevel(); + GLenum sizedFormat = + texture.getFormat(texture.getTarget(), baseLevel).info->sizedInternalFormat; + if (data->baseLevel != static_cast(baseLevel)) + { + data->baseLevel = static_cast(baseLevel); + dirty = true; + } + + // Some metadata is needed only for integer textures. We avoid updating the constant buffer + // unnecessarily by changing the data only in case the texture is an integer texture and + // the values have changed. + bool needIntegerTextureMetadata = false; + // internalFormatBits == 0 means a 32-bit texture in the case of integer textures. + int internalFormatBits = 0; + switch (sizedFormat) + { + case GL_RGBA32I: + case GL_RGBA32UI: + case GL_RGB32I: + case GL_RGB32UI: + case GL_RG32I: + case GL_RG32UI: + case GL_R32I: + case GL_R32UI: + needIntegerTextureMetadata = true; + break; + case GL_RGBA16I: + case GL_RGBA16UI: + case GL_RGB16I: + case GL_RGB16UI: + case GL_RG16I: + case GL_RG16UI: + case GL_R16I: + case GL_R16UI: + needIntegerTextureMetadata = true; + internalFormatBits = 16; + break; + case GL_RGBA8I: + case GL_RGBA8UI: + case GL_RGB8I: + case GL_RGB8UI: + case GL_RG8I: + case GL_RG8UI: + case GL_R8I: + case GL_R8UI: + needIntegerTextureMetadata = true; + internalFormatBits = 8; + break; + case GL_RGB10_A2UI: + needIntegerTextureMetadata = true; + internalFormatBits = 10; + break; + default: + break; + } + if (needIntegerTextureMetadata) + { + if (data->internalFormatBits != internalFormatBits) + { + data->internalFormatBits = internalFormatBits; + dirty = true; + } + // Pack the wrap values into one integer so we can fit all the metadata in one 4-integer + // vector. + GLenum wrapS = texture.getWrapS(); + GLenum wrapT = texture.getWrapT(); + GLenum wrapR = texture.getWrapR(); + int wrapModes = GetWrapBits(wrapS) | (GetWrapBits(wrapT) << 2) | (GetWrapBits(wrapR) << 4); + if (data->wrapModes != wrapModes) + { + data->wrapModes = wrapModes; + dirty = true; + } + } + + return dirty; +} + +void ShaderConstants11::setComputeWorkGroups(GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + mCompute.numWorkGroups[0] = numGroupsX; + mCompute.numWorkGroups[1] = numGroupsY; + mCompute.numWorkGroups[2] = numGroupsZ; + mComputeDirty = true; +} + +void ShaderConstants11::setMultiviewWriteToViewportIndex(GLfloat index) +{ + mVertex.multiviewWriteToViewportIndex = index; + mVertexDirty = true; + mPixel.multiviewWriteToViewportIndex = index; + mPixelDirty = true; +} + +void ShaderConstants11::onViewportChange(const gl::Rectangle &glViewport, + const D3D11_VIEWPORT &dxViewport, + bool is9_3, + bool presentPathFast) +{ + mVertexDirty = true; + mPixelDirty = true; + + // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders + // using viewAdjust (like the D3D9 renderer). + if (is9_3) + { + mVertex.viewAdjust[0] = static_cast((glViewport.width - dxViewport.Width) + + 2 * (glViewport.x - dxViewport.TopLeftX)) / + dxViewport.Width; + mVertex.viewAdjust[1] = static_cast((glViewport.height - dxViewport.Height) + + 2 * (glViewport.y - dxViewport.TopLeftY)) / + dxViewport.Height; + mVertex.viewAdjust[2] = static_cast(glViewport.width) / dxViewport.Width; + mVertex.viewAdjust[3] = static_cast(glViewport.height) / dxViewport.Height; + } + + mPixel.viewCoords[0] = glViewport.width * 0.5f; + mPixel.viewCoords[1] = glViewport.height * 0.5f; + mPixel.viewCoords[2] = glViewport.x + (glViewport.width * 0.5f); + mPixel.viewCoords[3] = glViewport.y + (glViewport.height * 0.5f); + + // Instanced pointsprite emulation requires ViewCoords to be defined in the + // the vertex shader. + mVertex.viewCoords[0] = mPixel.viewCoords[0]; + mVertex.viewCoords[1] = mPixel.viewCoords[1]; + mVertex.viewCoords[2] = mPixel.viewCoords[2]; + mVertex.viewCoords[3] = mPixel.viewCoords[3]; + + const float zNear = dxViewport.MinDepth; + const float zFar = dxViewport.MaxDepth; + + mPixel.depthFront[0] = (zFar - zNear) * 0.5f; + mPixel.depthFront[1] = (zNear + zFar) * 0.5f; + + mVertex.depthRange[0] = zNear; + mVertex.depthRange[1] = zFar; + mVertex.depthRange[2] = zFar - zNear; + + mPixel.depthRange[0] = zNear; + mPixel.depthRange[1] = zFar; + mPixel.depthRange[2] = zFar - zNear; + + mPixel.viewScale[0] = 1.0f; + mPixel.viewScale[1] = presentPathFast ? 1.0f : -1.0f; + // Updates to the multiviewWriteToViewportIndex member are to be handled whenever the draw + // framebuffer's layout is changed. + + mVertex.viewScale[0] = mPixel.viewScale[0]; + mVertex.viewScale[1] = mPixel.viewScale[1]; +} + +void ShaderConstants11::onSamplerChange(gl::SamplerType samplerType, + unsigned int samplerIndex, + const gl::Texture &texture) +{ + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + if (updateSamplerMetadata(&mSamplerMetadataVS[samplerIndex], texture)) + { + mSamplerMetadataVSDirty = true; + } + break; + case gl::SAMPLER_PIXEL: + if (updateSamplerMetadata(&mSamplerMetadataPS[samplerIndex], texture)) + { + mSamplerMetadataPSDirty = true; + } + break; + case gl::SAMPLER_COMPUTE: + if (updateSamplerMetadata(&mSamplerMetadataCS[samplerIndex], texture)) + { + mSamplerMetadataCSDirty = true; + } + break; + default: + UNREACHABLE(); + break; + } +} + +gl::Error ShaderConstants11::updateBuffer(ID3D11DeviceContext *deviceContext, + gl::SamplerType samplerType, + const ProgramD3D &programD3D, + const d3d11::Buffer &driverConstantBuffer) +{ + bool dirty = false; + size_t dataSize = 0; + const uint8_t *data = nullptr; + const uint8_t *samplerData = nullptr; + + switch (samplerType) + { + case gl::SAMPLER_VERTEX: + dirty = mVertexDirty || mSamplerMetadataVSDirty; + dataSize = sizeof(Vertex); + data = reinterpret_cast(&mVertex); + samplerData = reinterpret_cast(mSamplerMetadataVS.data()); + mVertexDirty = false; + mSamplerMetadataVSDirty = false; + break; + case gl::SAMPLER_PIXEL: + dirty = mPixelDirty || mSamplerMetadataPSDirty; + dataSize = sizeof(Pixel); + data = reinterpret_cast(&mPixel); + samplerData = reinterpret_cast(mSamplerMetadataPS.data()); + mPixelDirty = false; + mSamplerMetadataPSDirty = false; + break; + case gl::SAMPLER_COMPUTE: + dirty = mComputeDirty || mSamplerMetadataCSDirty; + dataSize = sizeof(Compute); + data = reinterpret_cast(&mCompute); + samplerData = reinterpret_cast(mSamplerMetadataCS.data()); + mComputeDirty = false; + mSamplerMetadataCSDirty = false; + break; + default: + UNREACHABLE(); + break; + } + + ASSERT(driverConstantBuffer.valid()); + + if (!dirty) + { + return gl::NoError(); + } + + // Previous buffer contents are discarded, so we need to refresh the whole buffer. + D3D11_MAPPED_SUBRESOURCE mapping = {0}; + HRESULT result = + deviceContext->Map(driverConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapping); + + if (FAILED(result)) + { + return gl::OutOfMemory() << "Internal error mapping constant buffer: " << gl::FmtHR(result); + } + + size_t samplerDataBytes = sizeof(SamplerMetadata) * programD3D.getUsedSamplerRange(samplerType); + + memcpy(mapping.pData, data, dataSize); + memcpy(reinterpret_cast(mapping.pData) + dataSize, samplerData, samplerDataBytes); + + deviceContext->Unmap(driverConstantBuffer.get(), 0); + + return gl::NoError(); +} + +static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, + GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED_EXT, + GL_COMMANDS_COMPLETED_CHROMIUM}; + StateManager11::StateManager11(Renderer11 *renderer) : mRenderer(renderer), - mBlendStateIsDirty(false), + mInternalDirtyBits(), 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(), + mRenderTargetIsDirty(true), mCurPresentPathFastEnabled(false), mCurPresentPathFastColorBufferHeight(0), - mAppliedDSV(angle::DirtyPointer) + mDirtyCurrentValueAttribs(), + mCurrentValueAttribs(), + mCurrentInputLayout(), + mInputLayoutIsDirty(false), + mVertexAttribsNeedTranslation(false), + mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0), + mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED), + mDirtySwizzles(false), + mAppliedIB(nullptr), + mAppliedIBFormat(DXGI_FORMAT_UNKNOWN), + mAppliedIBOffset(0), + mIndexBufferIsDirty(false), + mVertexDataManager(renderer), + mIndexDataManager(renderer), + mIsMultiviewEnabled(false), + mEmptySerial(mRenderer->generateSerial()), + mIsTransformFeedbackCurrentlyActiveUnpaused(false) { mCurBlendState.blend = false; mCurBlendState.sourceBlendRGB = GL_ONE; @@ -182,64 +601,127 @@ StateManager11::StateManager11(Renderer11 *renderer) mCurRasterState.rasterizerDiscard = false; mCurRasterState.cullFace = false; - mCurRasterState.cullMode = GL_BACK; + mCurRasterState.cullMode = gl::CullFaceMode::Back; mCurRasterState.frontFace = GL_CCW; mCurRasterState.polygonOffsetFill = false; mCurRasterState.polygonOffsetFactor = 0.0f; mCurRasterState.polygonOffsetUnits = 0.0f; mCurRasterState.pointDrawMode = false; mCurRasterState.multiSample = false; + + // Start with all internal dirty bits set. + mInternalDirtyBits.set(); + + // Initially all current value attributes must be updated on first use. + mDirtyCurrentValueAttribs.set(); + + mCurrentVertexBuffers.fill(nullptr); + mCurrentVertexStrides.fill(std::numeric_limits::max()); + mCurrentVertexOffsets.fill(std::numeric_limits::max()); } StateManager11::~StateManager11() { } -void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized, - unsigned int stencilSize) +template +void StateManager11::setShaderResourceInternal(gl::SamplerType shaderType, + UINT resourceSlot, + const SRVType *srv) { - if (!depthStencilInitialized || stencilSize != mCurStencilSize) + 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)) { - mCurStencilSize = stencilSize; - mDepthStencilStateIsDirty = true; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11ShaderResourceView *srvPtr = srv ? srv->get() : nullptr; + if (shaderType == gl::SAMPLER_VERTEX) + { + deviceContext->VSSetShaderResources(resourceSlot, 1, &srvPtr); + } + else + { + deviceContext->PSSetShaderResources(resourceSlot, 1, &srvPtr); + } + + currentSRVs.update(resourceSlot, srvPtr); } } -void StateManager11::setViewportBounds(const int width, const int height) +void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized, + unsigned int stencilSize) { - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && - (mViewportBounds.width != width || mViewportBounds.height != height)) + if (!depthStencilInitialized || stencilSize != mCurStencilSize) { - mViewportBounds = gl::Extents(width, height, 1); - mViewportStateIsDirty = true; + mCurStencilSize = stencilSize; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } } -void StateManager11::updatePresentPath(bool presentPathFastActive, - const gl::FramebufferAttachment *framebufferAttachment) +void StateManager11::checkPresentPath(const gl::Context *context) { - const int colorBufferHeight = - framebufferAttachment ? framebufferAttachment->getSize().height : 0; + if (!mRenderer->presentPathFastEnabled()) + return; + + const auto *framebuffer = context->getGLState().getDrawFramebuffer(); + const auto *firstColorAttachment = framebuffer->getFirstColorbuffer(); + const bool presentPathFastActive = UsePresentPathFast(mRenderer, firstColorAttachment); + + const int colorBufferHeight = firstColorAttachment ? firstColorAttachment->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 + + // Scissor rect may need to be vertically inverted + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); + + // Cull Mode may need to be inverted + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Viewport may need to be vertically inverted + invalidateViewport(context); } } -void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits) +gl::Error StateManager11::updateStateForCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + mShaderConstants.setComputeWorkGroups(numGroupsX, numGroupsY, numGroupsZ); + + // TODO(jmadill): Use dirty bits. + const auto &glState = context->getGLState(); + auto *programD3D = GetImplAs(glState.getProgram()); + programD3D->updateSamplerMapping(); + + // TODO(jmadill): Use dirty bits. + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_COMPUTE)); + + // TODO(jmadill): More complete implementation. + ANGLE_TRY(syncTextures(context)); + + // TODO(Xinghua): applyUniformBuffers for compute shader. + + return gl::NoError(); +} + +void StateManager11::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) { if (!dirtyBits.any()) { return; } - for (unsigned int dirtyBit : angle::IterateBitSet(dirtyBits)) + const auto &state = context->getGLState(); + + for (auto dirtyBit : dirtyBits) { switch (dirtyBit) { @@ -249,7 +731,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB || blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } @@ -261,27 +743,27 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha || blendState.destBlendAlpha != mCurBlendState.destBlendAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } case gl::State::DIRTY_BIT_BLEND_ENABLED: if (state.getBlendState().blend != mCurBlendState.blend) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: if (state.getBlendState().sampleAlphaToCoverage != mCurBlendState.sampleAlphaToCoverage) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_DITHER_ENABLED: if (state.getBlendState().dither != mCurBlendState.dither) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_COLOR_MASK: @@ -292,38 +774,38 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit blendState.colorMaskBlue != mCurBlendState.colorMaskBlue || blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; } case gl::State::DIRTY_BIT_BLEND_COLOR: if (state.getBlendColor() != mCurBlendColor) { - mBlendStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_MASK: if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_FUNC: if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED: if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT: @@ -333,7 +815,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilMask != mCurDepthStencilState.stencilMask || state.getStencilRef() != mCurStencilRef) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -344,7 +826,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilBackMask != mCurDepthStencilState.stencilBackMask || state.getStencilBackRef() != mCurStencilBackRef) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -352,14 +834,14 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (state.getDepthStencilState().stencilWritemask != mCurDepthStencilState.stencilWritemask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK: if (state.getDepthStencilState().stencilBackWritemask != mCurDepthStencilState.stencilBackWritemask) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT: @@ -370,7 +852,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit mCurDepthStencilState.stencilPassDepthFail || depthStencil.stencilPassDepthPass != mCurDepthStencilState.stencilPassDepthPass) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } @@ -383,33 +865,33 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit depthStencil.stencilBackPassDepthPass != mCurDepthStencilState.stencilBackPassDepthPass) { - mDepthStencilStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); } break; } case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: if (state.getRasterizerState().cullFace != mCurRasterState.cullFace) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_CULL_FACE: if (state.getRasterizerState().cullMode != mCurRasterState.cullMode) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_FRONT_FACE: if (state.getRasterizerState().frontFace != mCurRasterState.frontFace) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: if (state.getRasterizerState().polygonOffsetFill != mCurRasterState.polygonOffsetFill) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_POLYGON_OFFSET: @@ -418,7 +900,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (rasterState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor || rasterState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; } @@ -426,58 +908,150 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit if (state.getRasterizerState().rasterizerDiscard != mCurRasterState.rasterizerDiscard) { - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Enabling/disabling rasterizer discard affects the pixel shader. + invalidateShaders(); } break; case gl::State::DIRTY_BIT_SCISSOR: if (state.getScissor() != mCurScissorRect) { - mScissorStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); } break; case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED: if (state.isScissorTestEnabled() != mCurScissorEnabled) { - mScissorStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); // Rasterizer state update needs mCurScissorsEnabled and updates when it changes - mRasterizerStateIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); } break; case gl::State::DIRTY_BIT_DEPTH_RANGE: if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar) { - mViewportStateIsDirty = true; + invalidateViewport(context); } break; case gl::State::DIRTY_BIT_VIEWPORT: if (state.getViewport() != mCurViewport) { - mViewportStateIsDirty = true; + invalidateViewport(context); + } + break; + case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: + invalidateRenderTarget(); + if (mIsMultiviewEnabled) + { + handleMultiviewDrawFramebufferChange(context); + } + break; + case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: + invalidateVertexBuffer(); + // Force invalidate the current value attributes, since the VertexArray11 keeps an + // internal cache of TranslatedAttributes, and they CurrentValue attributes are + // owned by the StateManager11/Context. + mDirtyCurrentValueAttribs.set(); + // Invalidate the cached index buffer. + mIndexBufferIsDirty = true; + break; + case gl::State::DIRTY_BIT_TEXTURE_BINDINGS: + invalidateTexturesAndSamplers(); + break; + case gl::State::DIRTY_BIT_SAMPLER_BINDINGS: + invalidateTexturesAndSamplers(); + break; + case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE: + { + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); + invalidateVertexBuffer(); + invalidateRenderTarget(); + invalidateTexturesAndSamplers(); + invalidateProgramUniforms(); + invalidateProgramUniformBuffers(); + gl::VertexArray *vao = state.getVertexArray(); + if (mIsMultiviewEnabled && vao != nullptr) + { + // If ANGLE_multiview is enabled, the attribute divisor has to be updated for + // each binding. + VertexArray11 *vao11 = GetImplAs(vao); + const gl::Program *program = state.getProgram(); + int numViews = 1; + if (program != nullptr && program->usesMultiview()) + { + numViews = program->getNumViews(); + } + vao11->markAllAttributeDivisorsForAdjustment(numViews); } break; + } + case gl::State::DIRTY_BIT_CURRENT_VALUES: + { + for (auto attribIndex : state.getAndResetDirtyCurrentValues()) + { + invalidateCurrentValueAttrib(attribIndex); + } + } default: break; } } + + // TODO(jmadill): Input layout and vertex buffer state. } -gl::Error StateManager11::setBlendState(const gl::Framebuffer *framebuffer, - const gl::BlendState &blendState, - const gl::ColorF &blendColor, - unsigned int sampleMask) +void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *context) { - if (!mBlendStateIsDirty && sampleMask == mCurSampleMask) + const auto &glState = context->getGLState(); + const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + ASSERT(drawFramebuffer != nullptr); + + // Update viewport offsets. + const std::vector *attachmentViewportOffsets = + drawFramebuffer->getViewportOffsets(); + const std::vector &viewportOffsets = + attachmentViewportOffsets != nullptr + ? *attachmentViewportOffsets + : gl::FramebufferAttachment::GetDefaultViewportOffsetVector(); + if (mViewportOffsets != viewportOffsets) { - return gl::Error(GL_NO_ERROR); - } + mViewportOffsets = viewportOffsets; - ID3D11BlendState *dxBlendState = nullptr; - gl::Error error = - mRenderer->getStateCache().getBlendState(framebuffer, blendState, &dxBlendState); - if (error.isError()) + // Because new viewport offsets are to be applied, we have to mark the internal viewport and + // scissor state as dirty. + invalidateViewport(context); + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); + } + switch (drawFramebuffer->getMultiviewLayout()) { - return error; + case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE: + mShaderConstants.setMultiviewWriteToViewportIndex(1.0f); + break; + case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE: + // Because the base view index is applied as an offset to the 2D texture array when the + // RTV is created, we just have to pass a boolean to select which code path is to be + // used. + mShaderConstants.setMultiviewWriteToViewportIndex(0.0f); + break; + default: + // There is no need to update the value in the constant buffer if the active framebuffer + // object does not have a multiview layout. + break; } +} + +gl::Error StateManager11::syncBlendState(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState, + const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + const d3d11::BlendState *dxBlendState = nullptr; + const d3d11::BlendStateKey &key = + RenderStateCache::GetBlendStateKey(context, framebuffer, blendState); + + ANGLE_TRY(mRenderer->getBlendState(key, &dxBlendState)); ASSERT(dxBlendState != nullptr); @@ -500,62 +1074,53 @@ gl::Error StateManager11::setBlendState(const gl::Framebuffer *framebuffer, blendColors[3] = blendColor.alpha; } - mRenderer->getDeviceContext()->OMSetBlendState(dxBlendState, blendColors, sampleMask); + mRenderer->getDeviceContext()->OMSetBlendState(dxBlendState->get(), blendColors, sampleMask); mCurBlendState = blendState; mCurBlendColor = blendColor; mCurSampleMask = sampleMask; - mBlendStateIsDirty = false; - - return error; + return gl::NoError(); } -gl::Error StateManager11::setDepthStencilState(const gl::State &glState) +gl::Error StateManager11::syncDepthStencilState(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()); + mCurDepthStencilState = glState.getDepthStencilState(); + mCurStencilRef = glState.getStencilRef(); + mCurStencilBackRef = glState.getStencilBackRef(); - // CurDisableDepth/Stencil are reset automatically after we call forceSetDepthStencilState. - if (!mDepthStencilStateIsDirty && mCurDisableDepth.valid() && - disableDepth == mCurDisableDepth.value() && mCurDisableStencil.valid() && - disableStencil == mCurDisableStencil.value()) + // get the maximum size of the stencil ref + unsigned int maxStencil = 0; + if (mCurDepthStencilState.stencilTest && mCurStencilSize > 0) { - return gl::Error(GL_NO_ERROR); + maxStencil = (1 << mCurStencilSize) - 1; } + ASSERT((mCurDepthStencilState.stencilWritemask & maxStencil) == + (mCurDepthStencilState.stencilBackWritemask & maxStencil)); + ASSERT(mCurStencilRef == mCurStencilBackRef); + ASSERT((mCurDepthStencilState.stencilMask & maxStencil) == + (mCurDepthStencilState.stencilBackMask & maxStencil)); - const auto &depthStencilState = glState.getDepthStencilState(); - int stencilRef = glState.getStencilRef(); - int stencilBackRef = glState.getStencilBackRef(); + gl::DepthStencilState modifiedGLState = glState.getDepthStencilState(); - // get the maximum size of the stencil ref - unsigned int maxStencil = 0; - if (depthStencilState.stencilTest && mCurStencilSize > 0) + ASSERT(mCurDisableDepth.valid() && mCurDisableStencil.valid()); + + if (mCurDisableDepth.value()) { - maxStencil = (1 << mCurStencilSize) - 1; + modifiedGLState.depthTest = false; + modifiedGLState.depthMask = false; } - 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()) + if (mCurDisableStencil.value()) { - return error; + modifiedGLState.stencilWritemask = 0; + modifiedGLState.stencilBackWritemask = 0; + modifiedGLState.stencilTest = false; } - ASSERT(dxDepthStencilState); + const d3d11::DepthStencilState *d3dState = nullptr; + ANGLE_TRY(mRenderer->getDepthStencilState(modifiedGLState, &d3dState)); + ASSERT(d3dState); // Max D3D11 stencil reference value is 0xFF, // corresponding to the max 8 bits in a stencil buffer @@ -565,30 +1130,21 @@ gl::Error StateManager11::setDepthStencilState(const gl::State &glState) "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); + UINT dxStencilRef = std::min(mCurStencilRef, 0xFFu); - mRenderer->getDeviceContext()->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); + mRenderer->getDeviceContext()->OMSetDepthStencilState(d3dState->get(), dxStencilRef); - mCurDepthStencilState = depthStencilState; - mCurStencilRef = stencilRef; - mCurStencilBackRef = stencilBackRef; - mCurDisableDepth = disableDepth; - mCurDisableStencil = disableStencil; - - mDepthStencilStateIsDirty = false; - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterState) +gl::Error StateManager11::syncRasterizerState(const gl::Context *context, bool pointDrawMode) { - if (!mRasterizerStateIsDirty) - { - return gl::Error(GL_NO_ERROR); - } + // TODO: Remove pointDrawMode and multiSample from gl::RasterizerState. + gl::RasterizerState rasterState = context->getGLState().getRasterizerState(); + rasterState.pointDrawMode = pointDrawMode; + rasterState.multiSample = mCurRasterState.multiSample; ID3D11RasterizerState *dxRasterState = nullptr; - gl::Error error(GL_NO_ERROR); if (mCurPresentPathFastEnabled) { @@ -607,33 +1163,23 @@ gl::Error StateManager11::setRasterizerState(const gl::RasterizerState &rasterSt modifiedRasterState.frontFace = GL_CCW; } - error = mRenderer->getStateCache().getRasterizerState(modifiedRasterState, - mCurScissorEnabled, &dxRasterState); + ANGLE_TRY( + mRenderer->getRasterizerState(modifiedRasterState, mCurScissorEnabled, &dxRasterState)); } else { - error = mRenderer->getStateCache().getRasterizerState(rasterState, mCurScissorEnabled, - &dxRasterState); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(mRenderer->getRasterizerState(rasterState, mCurScissorEnabled, &dxRasterState)); } mRenderer->getDeviceContext()->RSSetState(dxRasterState); - mCurRasterState = rasterState; - mRasterizerStateIsDirty = false; + mCurRasterState = rasterState; - return error; + return gl::NoError(); } -void StateManager11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +void StateManager11::syncScissorRectangle(const gl::Rectangle &scissor, bool enabled) { - if (!mScissorStateIsDirty) - return; - int modifiedScissorY = scissor.y; if (mCurPresentPathFastEnabled) { @@ -642,37 +1188,41 @@ void StateManager11::setScissorRectangle(const gl::Rectangle &scissor, bool enab 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); + std::array rectangles; + const UINT numRectangles = static_cast(mViewportOffsets.size()); + for (UINT i = 0u; i < numRectangles; ++i) + { + D3D11_RECT &rect = rectangles[i]; + int x = scissor.x + mViewportOffsets[i].x; + int y = modifiedScissorY + mViewportOffsets[i].y; + rect.left = std::max(0, x); + rect.top = std::max(0, y); + rect.right = x + std::max(0, scissor.width); + rect.bottom = y + std::max(0, scissor.height); + } + mRenderer->getDeviceContext()->RSSetScissorRects(numRectangles, rectangles.data()); } mCurScissorRect = scissor; mCurScissorEnabled = enabled; - mScissorStateIsDirty = false; } -void StateManager11::setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, - float zNear, - float zFar) +void StateManager11::syncViewport(const gl::Context *context) { - 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); + const auto &glState = context->getGLState(); + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + float actualZNear = gl::clamp01(glState.getNearPlane()); + float actualZFar = gl::clamp01(glState.getFarPlane()); + + const auto &caps = context->getCaps(); + 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) + bool is9_3 = mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3; + + if (is9_3) { // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget. dxMaxViewportBoundsX = static_cast(mViewportBounds.width); @@ -681,173 +1231,295 @@ void StateManager11::setViewport(const gl::Caps *caps, 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); + const auto &viewport = glState.getViewport(); + std::array dxViewports; + const UINT numRectangles = static_cast(mViewportOffsets.size()); - D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = static_cast(dxViewportTopLeftX); + int dxViewportTopLeftX = 0; + int dxViewportTopLeftY = 0; + int dxViewportWidth = 0; + int dxViewportHeight = 0; - 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 + for (UINT i = 0u; i < numRectangles; ++i) { - dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); - } + dxViewportTopLeftX = gl::clamp(viewport.x + mViewportOffsets[i].x, dxMinViewportBoundsX, + dxMaxViewportBoundsX); + dxViewportTopLeftY = gl::clamp(viewport.y + mViewportOffsets[i].y, dxMinViewportBoundsY, + dxMaxViewportBoundsY); + dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX); + dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY); + + D3D11_VIEWPORT &dxViewport = dxViewports[i]; + 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; + // The es 3.1 spec section 9.2 states that, "If there are no attachments, rendering + // will be limited to a rectangle having a lower left of (0, 0) and an upper right of + // (width, height), where width and height are the framebuffer object's default width + // and height." See http://anglebug.com/1594 + // If the Framebuffer has no color attachment and the default width or height is smaller + // than the current viewport, use the smaller of the two sizes. + // If framebuffer default width or height is 0, the params should not set. + if (!framebuffer->getFirstNonNullAttachment() && + (framebuffer->getDefaultWidth() || framebuffer->getDefaultHeight())) + { + dxViewport.Width = + static_cast(std::min(viewport.width, framebuffer->getDefaultWidth())); + dxViewport.Height = + static_cast(std::min(viewport.height, framebuffer->getDefaultHeight())); + } + else + { + dxViewport.Width = static_cast(dxViewportWidth); + dxViewport.Height = static_cast(dxViewportHeight); + } + dxViewport.MinDepth = actualZNear; + dxViewport.MaxDepth = actualZFar; + } - mRenderer->getDeviceContext()->RSSetViewports(1, &dxViewport); + mRenderer->getDeviceContext()->RSSetViewports(numRectangles, dxViewports.data()); 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) + const D3D11_VIEWPORT adjustViewport = {static_cast(dxViewportTopLeftX), + static_cast(dxViewportTopLeftY), + static_cast(dxViewportWidth), + static_cast(dxViewportHeight), + actualZNear, + actualZFar}; + mShaderConstants.onViewportChange(viewport, adjustViewport, is9_3, mCurPresentPathFastEnabled); +} + +void StateManager11::invalidateRenderTarget() +{ + mRenderTargetIsDirty = true; +} + +void StateManager11::processFramebufferInvalidation(const gl::Context *context) +{ + if (!mRenderTargetIsDirty) { - 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; + return; } - 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); + ASSERT(context); - // 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]; + mRenderTargetIsDirty = false; + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); - mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; - mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + // The pixel shader is dependent on the output layout. + invalidateShaders(); - 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; + // The D3D11 blend state is heavily dependent on the current render target. + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); - mPixelConstants.viewScale[0] = 1.0f; - mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f; - mPixelConstants.viewScale[2] = 1.0f; - mPixelConstants.viewScale[3] = 1.0f; + gl::Framebuffer *fbo = context->getGLState().getDrawFramebuffer(); + ASSERT(fbo); - mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0]; - mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1]; - mVertexConstants.viewScale[2] = mPixelConstants.viewScale[2]; - mVertexConstants.viewScale[3] = mPixelConstants.viewScale[3]; + // 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()); - mViewportStateIsDirty = false; -} + // Similarly we disable the stencil portion of the DS attachment if the app only binds depth. + bool disableStencil = (fbo->hasDepth() && !fbo->hasStencil()); -void StateManager11::invalidateRenderTarget() -{ - for (auto &appliedRTV : mAppliedRTVs) + if (!mCurDisableDepth.valid() || disableDepth != mCurDisableDepth.value() || + !mCurDisableStencil.valid() || disableStencil != mCurDisableStencil.value()) + { + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); + mCurDisableDepth = disableDepth; + mCurDisableStencil = disableStencil; + } + + bool multiSample = (fbo->getCachedSamples(context) != 0); + if (multiSample != mCurRasterState.multiSample) + { + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + mCurRasterState.multiSample = multiSample; + } + + checkPresentPath(context); + + if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { - appliedRTV = angle::DirtyPointer; + const auto *firstAttachment = fbo->getFirstNonNullAttachment(); + if (firstAttachment) + { + const auto &size = firstAttachment->getSize(); + if (mViewportBounds.width != size.width || mViewportBounds.height != size.height) + { + mViewportBounds = gl::Extents(size.width, size.height, 1); + invalidateViewport(context); + } + } } - mAppliedDSV = angle::DirtyPointer; } -void StateManager11::invalidateEverything() +void StateManager11::invalidateBoundViews() { - 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) +void StateManager11::invalidateVertexBuffer() { - // TODO(jmadill): Use context caps? - UINT drawBuffers = mRenderer->getRendererCaps().maxDrawBuffers; + unsigned int limit = std::min(mRenderer->getNativeCaps().maxVertexAttributes, + gl::MAX_VERTEX_ATTRIBS); + mDirtyVertexBufferRange = gl::RangeUI(0, limit); + mInputLayoutIsDirty = true; + mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS); + invalidateVertexAttributeTranslation(); +} - // 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) +void StateManager11::invalidateViewport(const gl::Context *context) +{ + mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); + + // Viewport affects the driver constants. + invalidateDriverUniforms(); +} + +void StateManager11::invalidateTexturesAndSamplers() +{ + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + invalidateSwizzles(); + + // Texture state affects the driver uniforms (base level, etc). + invalidateDriverUniforms(); +} + +void StateManager11::invalidateSwizzles() +{ + mDirtySwizzles = true; +} + +void StateManager11::invalidateProgramUniforms() +{ + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS); +} + +void StateManager11::invalidateDriverUniforms() +{ + mInternalDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS); +} + +void StateManager11::invalidateProgramUniformBuffers() +{ + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS); +} + +void StateManager11::invalidateConstantBuffer(unsigned int slot) +{ + if (slot == d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER) + { + invalidateDriverUniforms(); + } + else if (slot == d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK) + { + invalidateProgramUniforms(); + } + else { - return false; + invalidateProgramUniformBuffers(); } +} - // The D3D11 blend state is heavily dependent on the current render target. - mBlendStateIsDirty = true; +void StateManager11::invalidateShaders() +{ + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); +} + +void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv) +{ + if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv))) + { + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + } + + mRenderer->getDeviceContext()->OMSetRenderTargets(1, &rtv, dsv); + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); +} + +void StateManager11::setRenderTargets(ID3D11RenderTargetView **rtvs, + UINT numRTVs, + ID3D11DepthStencilView *dsv) +{ + bool anyDirty = false; + + for (UINT rtvIndex = 0; rtvIndex < numRTVs; ++rtvIndex) + { + anyDirty = anyDirty || unsetConflictingView(rtvs[rtvIndex]); + } - for (UINT rtIndex = 0; rtIndex < drawBuffers; rtIndex++) + if (dsv) { - mAppliedRTVs[rtIndex] = reinterpret_cast(renderTargets[rtIndex]); + anyDirty = anyDirty || unsetConflictingView(dsv); } - mAppliedDSV = reinterpret_cast(depthStencil); - mRenderer->getDeviceContext()->OMSetRenderTargets(drawBuffers, renderTargets.data(), - depthStencil); - return true; + if (anyDirty) + { + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + } + + mRenderer->getDeviceContext()->OMSetRenderTargets(numRTVs, (numRTVs > 0) ? rtvs : nullptr, dsv); + mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET); } -void StateManager11::setRenderTarget(ID3D11RenderTargetView *renderTarget, - ID3D11DepthStencilView *depthStencil) +void StateManager11::invalidateVertexAttributeTranslation() { - mRenderer->getDeviceContext()->OMSetRenderTargets(1, &renderTarget, depthStencil); + mVertexAttribsNeedTranslation = true; } -void StateManager11::setShaderResource(gl::SamplerType shaderType, - UINT resourceSlot, - ID3D11ShaderResourceView *srv) +void StateManager11::onBeginQuery(Query11 *query) { - auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + mCurrentQueries.insert(query); +} - ASSERT(static_cast(resourceSlot) < currentSRVs.size()); - const SRVRecord &record = currentSRVs[resourceSlot]; +void StateManager11::onDeleteQueryObject(Query11 *query) +{ + mCurrentQueries.erase(query); +} - if (record.srv != reinterpret_cast(srv)) +gl::Error StateManager11::onMakeCurrent(const gl::Context *context) +{ + const gl::State &state = context->getGLState(); + + for (Query11 *query : mCurrentQueries) { - auto deviceContext = mRenderer->getDeviceContext(); - if (shaderType == gl::SAMPLER_VERTEX) - { - deviceContext->VSSetShaderResources(resourceSlot, 1, &srv); - } - else + ANGLE_TRY(query->pause()); + } + mCurrentQueries.clear(); + + for (GLenum queryType : QueryTypes) + { + gl::Query *query = state.getActiveQuery(queryType); + if (query != nullptr) { - deviceContext->PSSetShaderResources(resourceSlot, 1, &srv); + Query11 *query11 = GetImplAs(query); + ANGLE_TRY(query11->resume()); + mCurrentQueries.insert(query11); } - - currentSRVs.update(resourceSlot, srv); } + + return gl::NoError(); } gl::Error StateManager11::clearTextures(gl::SamplerType samplerType, @@ -856,185 +1528,1548 @@ gl::Error StateManager11::clearTextures(gl::SamplerType samplerType, { if (rangeStart == rangeEnd) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - gl::Range clearRange(rangeStart, rangeStart); - clearRange.extend(std::min(rangeEnd, currentSRVs.highestUsed())); - + gl::Range clearRange(rangeStart, std::min(rangeEnd, currentSRVs.highestUsed())); if (clearRange.empty()) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - auto deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); if (samplerType == gl::SAMPLER_VERTEX) { - deviceContext->VSSetShaderResources(static_cast(rangeStart), - static_cast(rangeEnd - rangeStart), + deviceContext->VSSetShaderResources(static_cast(clearRange.low()), + static_cast(clearRange.length()), &mNullSRVs[0]); } else { - deviceContext->PSSetShaderResources(static_cast(rangeStart), - static_cast(rangeEnd - rangeStart), + deviceContext->PSSetShaderResources(static_cast(clearRange.low()), + static_cast(clearRange.length()), &mNullSRVs[0]); } - for (size_t samplerIndex = rangeStart; samplerIndex < rangeEnd; ++samplerIndex) + for (size_t samplerIndex : clearRange) { currentSRVs.update(samplerIndex, nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType, +bool StateManager11::unsetConflictingView(ID3D11View *view) +{ + uintptr_t resource = reinterpret_cast(GetViewResource(view)); + return unsetConflictingSRVs(gl::SAMPLER_VERTEX, resource, nullptr) || + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resource, nullptr); +} + +bool StateManager11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, - const gl::ImageIndex &index) + const gl::ImageIndex *index) { auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + bool foundOne = false; + for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) { auto &record = currentSRVs[resourceIndex]; if (record.srv && record.resource == resource && - ImageIndexConflictsWithSRV(index, record.desc)) + (!index || ImageIndexConflictsWithSRV(*index, record.desc))) { - setShaderResource(samplerType, static_cast(resourceIndex), NULL); + setShaderResourceInternal( + samplerType, static_cast(resourceIndex), nullptr); + foundOne = true; } } + + return foundOne; +} + +void StateManager11::unsetConflictingAttachmentResources( + const gl::FramebufferAttachment *attachment, + ID3D11Resource *resource) +{ + // Unbind render target SRVs from the shader here to prevent D3D11 warnings. + if (attachment->type() == GL_TEXTURE) + { + uintptr_t resourcePtr = reinterpret_cast(resource); + const gl::ImageIndex &index = attachment->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, resourcePtr, &index); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resourcePtr, &index); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + uintptr_t resourcePtr = reinterpret_cast(resource); + unsetConflictingSRVs(gl::SAMPLER_VERTEX, resourcePtr, nullptr); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, resourcePtr, nullptr); + } } -void StateManager11::initialize(const gl::Caps &caps) +gl::Error StateManager11::initialize(const gl::Caps &caps, const gl::Extensions &extensions) { mCurVertexSRVs.initialize(caps.maxVertexTextureImageUnits); mCurPixelSRVs.initialize(caps.maxTextureImageUnits); // Initialize cached NULL SRV block mNullSRVs.resize(caps.maxTextureImageUnits, nullptr); + + mCurrentValueAttribs.resize(caps.maxVertexAttributes); + + mForceSetVertexSamplerStates.resize(caps.maxVertexTextureImageUnits, true); + mForceSetPixelSamplerStates.resize(caps.maxTextureImageUnits, true); + mForceSetComputeSamplerStates.resize(caps.maxComputeTextureImageUnits, true); + + mCurVertexSamplerStates.resize(caps.maxVertexTextureImageUnits); + mCurPixelSamplerStates.resize(caps.maxTextureImageUnits); + mCurComputeSamplerStates.resize(caps.maxComputeTextureImageUnits); + + mShaderConstants.init(caps); + + mIsMultiviewEnabled = extensions.multiview; + mViewportOffsets.resize(1u); + + ANGLE_TRY(mVertexDataManager.initialize()); + + mCurrentAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); + + return gl::NoError(); } -gl::Error StateManager11::syncFramebuffer(const gl::Framebuffer *framebuffer) +void StateManager11::deinitialize() { - // 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; + mCurrentValueAttribs.clear(); + mInputLayoutCache.clear(); + mVertexDataManager.deinitialize(); + mIndexDataManager.deinitialize(); + + mDriverConstantBufferVS.reset(); + mDriverConstantBufferPS.reset(); + mDriverConstantBufferCS.reset(); +} - framebufferRTVs.fill(nullptr); +gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer) +{ + Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); - const Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); - const gl::AttachmentList &colorbuffers = framebuffer11->getColorAttachmentsForRender(); + // Applies the render target surface, depth stencil surface, viewport rectangle and + // scissor rectangle to the renderer + ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->cachedComplete()); - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + // 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 (framebuffer->id() == 0) { - const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) + ASSERT(!framebuffer11->hasAnyInternalDirtyBit()); + const gl::Extents &size = framebuffer->getFirstColorbuffer()->getSize(); + if (size.width == 0 || size.height == 0) { - // 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); - } + return gl::NoError(); + } + } - // Extract the render target dimensions and view - RenderTarget11 *renderTarget = NULL; - gl::Error error = colorbuffer->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); + RTVArray framebufferRTVs = {{}}; - framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); - ASSERT(framebufferRTVs[colorAttachment]); + const auto &colorRTs = framebuffer11->getCachedColorRenderTargets(); - if (missingColorRenderTarget) - { - renderTargetWidth = renderTarget->getWidth(); - renderTargetHeight = renderTarget->getHeight(); - renderTargetFormat = renderTarget->getDXGIFormat(); - missingColorRenderTarget = false; - } + size_t appliedRTIndex = 0; + bool skipInactiveRTs = mRenderer->getWorkarounds().mrtPerfWorkaround; + const auto &drawStates = framebuffer->getDrawBufferStates(); + gl::DrawBufferMask activeProgramOutputs = + context->getContextState().getState().getProgram()->getActiveOutputVariables(); + UINT maxExistingRT = 0; - // 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); - } + for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex) + { + const RenderTarget11 *renderTarget = colorRTs[rtIndex]; + + // Skip inactive rendertargets if the workaround is enabled. + if (skipInactiveRTs && + (!renderTarget || drawStates[rtIndex] == GL_NONE || !activeProgramOutputs[rtIndex])) + { + continue; } - } - // 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()) + if (renderTarget) { - return error; + framebufferRTVs[appliedRTIndex] = renderTarget->getRenderTargetView().get(); + ASSERT(framebufferRTVs[appliedRTIndex]); + maxExistingRT = static_cast(appliedRTIndex) + 1; + + // Unset conflicting texture SRVs + const auto *attachment = framebuffer->getColorbuffer(rtIndex); + ASSERT(attachment); + unsetConflictingAttachmentResources(attachment, renderTarget->getTexture().get()); } - ASSERT(depthStencilRenderTarget); - framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); + appliedRTIndex++; + } + + // Get the depth stencil buffers + ID3D11DepthStencilView *framebufferDSV = nullptr; + const auto *depthStencilRenderTarget = framebuffer11->getCachedDepthStencilRenderTarget(); + if (depthStencilRenderTarget) + { + framebufferDSV = depthStencilRenderTarget->getDepthStencilView().get(); 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(); - } + // Unset conflicting texture SRVs + const auto *attachment = framebuffer->getDepthOrStencilbuffer(); + ASSERT(attachment); + unsetConflictingAttachmentResources(attachment, + depthStencilRenderTarget->getTexture().get()); + } + + // TODO(jmadill): Use context caps? + ASSERT(maxExistingRT <= static_cast(mRenderer->getNativeCaps().maxDrawBuffers)); + + // Apply the render target and depth stencil + mRenderer->getDeviceContext()->OMSetRenderTargets(maxExistingRT, framebufferRTVs.data(), + framebufferDSV); + + return gl::NoError(); +} + +void StateManager11::invalidateCurrentValueAttrib(size_t attribIndex) +{ + mDirtyCurrentValueAttribs.set(attribIndex); + mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS); +} + +gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState) +{ + const auto &activeAttribsMask = glState.getProgram()->getActiveAttribLocationsMask(); + const auto &dirtyActiveAttribs = (activeAttribsMask & mDirtyCurrentValueAttribs); + + if (!dirtyActiveAttribs.any()) + { + return gl::NoError(); + } + + const auto &vertexAttributes = glState.getVertexArray()->getVertexAttributes(); + const auto &vertexBindings = glState.getVertexArray()->getVertexBindings(); + mDirtyCurrentValueAttribs = (mDirtyCurrentValueAttribs & ~dirtyActiveAttribs); + + for (auto attribIndex : dirtyActiveAttribs) + { + if (vertexAttributes[attribIndex].enabled) + continue; + + const auto *attrib = &vertexAttributes[attribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(attribIndex); + TranslatedAttribute *currentValueAttrib = &mCurrentValueAttribs[attribIndex]; + currentValueAttrib->currentValueType = currentValue.Type; + currentValueAttrib->attribute = attrib; + currentValueAttrib->binding = &vertexBindings[attrib->bindingIndex]; - // Unbind render target SRVs from the shader here to prevent D3D11 warnings. - if (depthStencil->type() == GL_TEXTURE) + mDirtyVertexBufferRange.extend(static_cast(attribIndex)); + mInputLayoutIsDirty = true; + + ANGLE_TRY(mVertexDataManager.storeCurrentValue(currentValue, currentValueAttrib, + static_cast(attribIndex))); + } + + return gl::NoError(); +} + +void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + if (inputLayout == nullptr) + { + if (!mCurrentInputLayout.empty()) { - 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); + deviceContext->IASetInputLayout(nullptr); + mCurrentInputLayout.clear(); + mInputLayoutIsDirty = true; } } + else if (inputLayout->getSerial() != mCurrentInputLayout) + { + deviceContext->IASetInputLayout(inputLayout->get()); + mCurrentInputLayout = inputLayout->getSerial(); + mInputLayoutIsDirty = true; + } +} + +bool StateManager11::queueVertexBufferChange(size_t bufferIndex, + ID3D11Buffer *buffer, + UINT stride, + UINT offset) +{ + if (buffer != mCurrentVertexBuffers[bufferIndex] || + stride != mCurrentVertexStrides[bufferIndex] || + offset != mCurrentVertexOffsets[bufferIndex]) + { + mInputLayoutIsDirty = true; + mDirtyVertexBufferRange.extend(static_cast(bufferIndex)); + + mCurrentVertexBuffers[bufferIndex] = buffer; + mCurrentVertexStrides[bufferIndex] = stride; + mCurrentVertexOffsets[bufferIndex] = offset; + return true; + } + + return false; +} + +bool StateManager11::queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly) +{ + if (offsetOnly != mCurrentVertexOffsets[bufferIndex]) + { + mInputLayoutIsDirty = true; + mDirtyVertexBufferRange.extend(static_cast(bufferIndex)); + mCurrentVertexOffsets[bufferIndex] = offsetOnly; + return true; + } + return false; +} + +void StateManager11::applyVertexBufferChanges() +{ + if (mDirtyVertexBufferRange.empty()) + { + return; + } + + ASSERT(mDirtyVertexBufferRange.high() <= gl::MAX_VERTEX_ATTRIBS); + + UINT start = static_cast(mDirtyVertexBufferRange.low()); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->IASetVertexBuffers(start, static_cast(mDirtyVertexBufferRange.length()), + &mCurrentVertexBuffers[start], &mCurrentVertexStrides[start], + &mCurrentVertexOffsets[start]); + + mDirtyVertexBufferRange = gl::RangeUI(gl::MAX_VERTEX_ATTRIBS, 0); +} + +void StateManager11::setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT stride, UINT offset) +{ + ID3D11Buffer *native = buffer ? buffer->get() : nullptr; + if (queueVertexBufferChange(0, native, stride, offset)) + { + applyVertexBufferChanges(); + } +} + +gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMode) +{ + const auto &glState = context->getGLState(); + auto *programD3D = GetImplAs(glState.getProgram()); + + // TODO(jmadill): Use dirty bits. + processFramebufferInvalidation(context); + + // TODO(jmadill): Use dirty bits. + if (programD3D->updateSamplerMapping() == ProgramD3D::SamplerMapping::WasDirty) + { + invalidateTexturesAndSamplers(); + } + + // TODO(jmadill): Use dirty bits. + if (programD3D->areVertexUniformsDirty() || programD3D->areFragmentUniformsDirty()) + { + mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS); + } + + // Transform feedback affects the stream-out geometry shader. + // TODO(jmadill): Use dirty bits. + if (glState.isTransformFeedbackActiveUnpaused() != mIsTransformFeedbackCurrentlyActiveUnpaused) + { + mIsTransformFeedbackCurrentlyActiveUnpaused = glState.isTransformFeedbackActiveUnpaused(); + invalidateShaders(); + } + + // Swizzling can cause internal state changes with blit shaders. + if (mDirtySwizzles) + { + ANGLE_TRY(generateSwizzles(context)); + mDirtySwizzles = false; + } + + gl::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); + ANGLE_TRY(framebuffer11->markAttachmentsDirty(context)); + + if (framebuffer11->hasAnyInternalDirtyBit()) + { + ASSERT(framebuffer->id() != 0); + framebuffer11->syncInternalState(context); + } + + bool pointDrawMode = (drawMode == GL_POINTS); + if (pointDrawMode != mCurRasterState.pointDrawMode) + { + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); + + // Changing from points to not points (or vice-versa) affects the geometry shader. + invalidateShaders(); + } + + // TODO(jiawei.shao@intel.com): This can be recomputed only on framebuffer or multisample mask + // state changes. + RenderTarget11 *firstRT = framebuffer11->getFirstRenderTarget(); + int samples = (firstRT ? firstRT->getSamples() : 0); + unsigned int sampleMask = GetBlendSampleMask(glState, samples); + if (sampleMask != mCurSampleMask) + { + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); + } + + // Changing the vertex attribute state can affect the vertex shader. + gl::VertexArray *vao = glState.getVertexArray(); + VertexArray11 *vao11 = GetImplAs(vao); + if (vao11->flushAttribUpdates(context)) + { + mInternalDirtyBits.set(DIRTY_BIT_SHADERS); + } - if (setRenderTargets(framebufferRTVs, framebufferDSV)) + auto dirtyBitsCopy = mInternalDirtyBits; + mInternalDirtyBits.reset(); + + for (auto dirtyBit : dirtyBitsCopy) { - setViewportBounds(renderTargetWidth, renderTargetHeight); + switch (dirtyBit) + { + case DIRTY_BIT_RENDER_TARGET: + ANGLE_TRY(syncFramebuffer(context, framebuffer)); + break; + case DIRTY_BIT_VIEWPORT_STATE: + syncViewport(context); + break; + case DIRTY_BIT_SCISSOR_STATE: + syncScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); + break; + case DIRTY_BIT_RASTERIZER_STATE: + ANGLE_TRY(syncRasterizerState(context, pointDrawMode)); + break; + case DIRTY_BIT_BLEND_STATE: + ANGLE_TRY(syncBlendState(context, framebuffer, glState.getBlendState(), + glState.getBlendColor(), sampleMask)); + break; + case DIRTY_BIT_DEPTH_STENCIL_STATE: + ANGLE_TRY(syncDepthStencilState(glState)); + break; + case DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE: + // TODO(jmadill): More fine-grained update. + ANGLE_TRY(syncTextures(context)); + break; + case DIRTY_BIT_PROGRAM_UNIFORMS: + ANGLE_TRY(applyUniforms(programD3D)); + break; + case DIRTY_BIT_DRIVER_UNIFORMS: + // This must happen after viewport sync; the viewport affects builtin uniforms. + ANGLE_TRY(applyDriverUniforms(*programD3D)); + break; + case DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS: + ANGLE_TRY(syncUniformBuffers(context, programD3D)); + break; + case DIRTY_BIT_SHADERS: + ANGLE_TRY(syncProgram(context, drawMode)); + break; + case DIRTY_BIT_CURRENT_VALUE_ATTRIBS: + ANGLE_TRY(syncCurrentValueAttribs(glState)); + break; + default: + UNREACHABLE(); + break; + } } - gl::Error error = framebuffer11->invalidateSwizzles(); - if (error.isError()) + ANGLE_TRY(syncTransformFeedbackBuffers(context)); + + // Check that we haven't set any dirty bits in the flushing of the dirty bits loop. + ASSERT(mInternalDirtyBits.none()); + + return gl::NoError(); +} + +void StateManager11::setShaderResourceShared(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::SharedSRV *srv) +{ + setShaderResourceInternal(shaderType, resourceSlot, srv); + + // TODO(jmadill): Narrower dirty region. + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); +} + +void StateManager11::setShaderResource(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::ShaderResourceView *srv) +{ + setShaderResourceInternal(shaderType, resourceSlot, srv); + + // TODO(jmadill): Narrower dirty region. + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); +} + +void StateManager11::setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY primitiveTopology) +{ + if (primitiveTopology != mCurrentPrimitiveTopology) { - return error; + mRenderer->getDeviceContext()->IASetPrimitiveTopology(primitiveTopology); + mCurrentPrimitiveTopology = primitiveTopology; } +} - return gl::Error(GL_NO_ERROR); +void StateManager11::setDrawShaders(const d3d11::VertexShader *vertexShader, + const d3d11::GeometryShader *geometryShader, + const d3d11::PixelShader *pixelShader) +{ + setVertexShader(vertexShader); + setGeometryShader(geometryShader); + setPixelShader(pixelShader); +} + +void StateManager11::setVertexShader(const d3d11::VertexShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedVertexShader) + { + ID3D11VertexShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->VSSetShader(appliedShader, nullptr, 0); + mAppliedVertexShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setGeometryShader(const d3d11::GeometryShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedGeometryShader) + { + ID3D11GeometryShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->GSSetShader(appliedShader, nullptr, 0); + mAppliedGeometryShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setPixelShader(const d3d11::PixelShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedPixelShader) + { + ID3D11PixelShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->PSSetShader(appliedShader, nullptr, 0); + mAppliedPixelShader = serial; + invalidateShaders(); + } +} + +void StateManager11::setComputeShader(const d3d11::ComputeShader *shader) +{ + ResourceSerial serial = shader ? shader->getSerial() : ResourceSerial(0); + + if (serial != mAppliedComputeShader) + { + ID3D11ComputeShader *appliedShader = shader ? shader->get() : nullptr; + mRenderer->getDeviceContext()->CSSetShader(appliedShader, nullptr, 0); + mAppliedComputeShader = serial; + // TODO(jmadill): Dirty bits for compute. + } +} + +void StateManager11::setVertexConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto ¤tSerial = mCurrentConstantBufferVS[slot]; + + mCurrentConstantBufferVSOffset[slot] = 0; + mCurrentConstantBufferVSSize[slot] = 0; + + if (buffer) + { + if (currentSerial != buffer->getSerial()) + { + deviceContext->VSSetConstantBuffers(slot, 1, buffer->getPointer()); + currentSerial = buffer->getSerial(); + invalidateConstantBuffer(slot); + } + } + else + { + if (!currentSerial.empty()) + { + ID3D11Buffer *nullBuffer = nullptr; + deviceContext->VSSetConstantBuffers(slot, 1, &nullBuffer); + currentSerial.clear(); + invalidateConstantBuffer(slot); + } + } +} + +void StateManager11::setPixelConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + auto ¤tSerial = mCurrentConstantBufferPS[slot]; + + mCurrentConstantBufferPSOffset[slot] = 0; + mCurrentConstantBufferPSSize[slot] = 0; + + if (buffer) + { + if (currentSerial != buffer->getSerial()) + { + deviceContext->PSSetConstantBuffers(slot, 1, buffer->getPointer()); + currentSerial = buffer->getSerial(); + invalidateConstantBuffer(slot); + } + } + else + { + if (!currentSerial.empty()) + { + ID3D11Buffer *nullBuffer = nullptr; + deviceContext->PSSetConstantBuffers(slot, 1, &nullBuffer); + currentSerial.clear(); + invalidateConstantBuffer(slot); + } + } +} + +void StateManager11::setDepthStencilState(const d3d11::DepthStencilState *depthStencilState, + UINT stencilRef) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (depthStencilState) + { + deviceContext->OMSetDepthStencilState(depthStencilState->get(), stencilRef); + } + else + { + deviceContext->OMSetDepthStencilState(nullptr, stencilRef); + } + + mInternalDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_STATE); +} + +void StateManager11::setSimpleBlendState(const d3d11::BlendState *blendState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (blendState) + { + deviceContext->OMSetBlendState(blendState->get(), nullptr, 0xFFFFFFFF); + } + else + { + deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF); + } + + mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE); +} + +void StateManager11::setRasterizerState(const d3d11::RasterizerState *rasterizerState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (rasterizerState) + { + deviceContext->RSSetState(rasterizerState->get()); + } + else + { + deviceContext->RSSetState(nullptr); + } + + mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE); +} + +void StateManager11::setSimpleViewport(const gl::Extents &extents) +{ + setSimpleViewport(extents.width, extents.height); +} + +void StateManager11::setSimpleViewport(int width, int height) +{ + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = static_cast(width); + viewport.Height = static_cast(height); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + + mRenderer->getDeviceContext()->RSSetViewports(1, &viewport); + mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); +} + +void StateManager11::setSimplePixelTextureAndSampler(const d3d11::SharedSRV &srv, + const d3d11::SamplerState &samplerState) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + setShaderResourceInternal(gl::SAMPLER_PIXEL, 0, &srv); + deviceContext->PSSetSamplers(0, 1, samplerState.getPointer()); + + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + mForceSetPixelSamplerStates[0] = true; +} + +void StateManager11::setSimpleScissorRect(const gl::Rectangle &glRect) +{ + D3D11_RECT scissorRect; + scissorRect.left = glRect.x; + scissorRect.right = glRect.x + glRect.width; + scissorRect.top = glRect.y; + scissorRect.bottom = glRect.y + glRect.height; + setScissorRectD3D(scissorRect); +} + +void StateManager11::setScissorRectD3D(const D3D11_RECT &d3dRect) +{ + mRenderer->getDeviceContext()->RSSetScissorRects(1, &d3dRect); + mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); +} + +// 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 StateManager11::applyTextures(const gl::Context *context, gl::SamplerType shaderType) +{ + const auto &glState = context->getGLState(); + const auto &caps = context->getCaps(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ASSERT(!programD3D->isSamplerMappingDirty()); + + // TODO(jmadill): Use the Program's sampler bindings. + const auto &completeTextures = glState.getCompleteTextureCache(); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); + for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); + ASSERT(textureUnit != -1); + gl::Texture *texture = completeTextures[textureUnit]; + + // A nullptr texture indicates incomplete. + if (texture) + { + gl::Sampler *samplerObject = glState.getSampler(textureUnit); + + const gl::SamplerState &samplerState = + samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); + + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState)); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); + } + else + { + GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); + + // Texture is not sampler complete or it is in use by the framebuffer. Bind the + // incomplete texture. + gl::Texture *incompleteTexture = nullptr; + ANGLE_TRY(mRenderer->getIncompleteTexture(context, textureType, &incompleteTexture)); + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, + incompleteTexture->getSamplerState())); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits + : caps.maxVertexTextureImageUnits; + ANGLE_TRY(clearTextures(shaderType, samplerRange, samplerCount)); + + return gl::NoError(); +} + +gl::Error StateManager11::syncTextures(const gl::Context *context) +{ + ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +gl::Error StateManager11::setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) +{ +#if !defined(NDEBUG) + // Storage should exist, texture should be complete. Only verified in Debug. + TextureD3D *textureD3D = GetImplAs(texture); + TextureStorage *storage = nullptr; + ANGLE_TRY(textureD3D->getNativeTexture(context, &storage)); + ASSERT(storage); +#endif // !defined(NDEBUG) + + auto *deviceContext = mRenderer->getDeviceContext(); + + if (type == gl::SAMPLER_PIXEL) + { + ASSERT(static_cast(index) < mRenderer->getNativeCaps().maxTextureImageUnits); + + if (mForceSetPixelSamplerStates[index] || + memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->PSSetSamplers(index, 1, &dxSamplerState); + + mCurPixelSamplerStates[index] = samplerState; + } + + mForceSetPixelSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_VERTEX) + { + ASSERT(static_cast(index) < + mRenderer->getNativeCaps().maxVertexTextureImageUnits); + + if (mForceSetVertexSamplerStates[index] || + memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->VSSetSamplers(index, 1, &dxSamplerState); + + mCurVertexSamplerStates[index] = samplerState; + } + + mForceSetVertexSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_COMPUTE) + { + ASSERT(static_cast(index) < + mRenderer->getNativeCaps().maxComputeTextureImageUnits); + + if (mForceSetComputeSamplerStates[index] || + memcmp(&samplerState, &mCurComputeSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = nullptr; + ANGLE_TRY(mRenderer->getSamplerState(samplerState, &dxSamplerState)); + + ASSERT(dxSamplerState != nullptr); + deviceContext->CSSetSamplers(index, 1, &dxSamplerState); + + mCurComputeSamplerStates[index] = samplerState; + } + + mForceSetComputeSamplerStates[index] = false; + } + else + UNREACHABLE(); + + // Sampler metadata that's passed to shaders in uniforms is stored separately from rest of the + // sampler state since having it in contiguous memory makes it possible to memcpy to a constant + // buffer, and it doesn't affect the state set by PSSetSamplers/VSSetSamplers. + mShaderConstants.onSamplerChange(type, index, *texture); + + return gl::NoError(); +} + +gl::Error StateManager11::setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture) +{ + const d3d11::SharedSRV *textureSRV = nullptr; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage)); + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage11 *storage11 = GetAs(texStorage); + + ANGLE_TRY(storage11->getSRV(context, texture->getTextureState(), &textureSRV)); + + // If we get an invalid SRV here, something went wrong in the texture class and we're + // unexpectedly missing the shader resource view. + ASSERT(textureSRV->valid()); + + textureImpl->resetDirty(); + } + + ASSERT( + (type == gl::SAMPLER_PIXEL && + static_cast(index) < mRenderer->getNativeCaps().maxTextureImageUnits) || + (type == gl::SAMPLER_VERTEX && + static_cast(index) < mRenderer->getNativeCaps().maxVertexTextureImageUnits)); + + setShaderResourceInternal(type, index, textureSRV); + return gl::NoError(); +} + +// Things that affect a program's dirtyness: +// 1. Directly changing the program executable -> triggered in StateManager11::syncState. +// 2. The vertex attribute layout -> triggered in VertexArray11::syncState/signal. +// 3. The fragment shader's rendertargets -> triggered in Framebuffer11::syncState/signal. +// 4. Enabling/disabling rasterizer discard. -> triggered in StateManager11::syncState. +// 5. Enabling/disabling transform feedback. -> checked in StateManager11::updateState. +// 6. An internal shader was used. -> triggered in StateManager11::set*Shader. +// 7. Drawing with/without point sprites. -> checked in StateManager11::updateState. +// TODO(jmadill): Use dirty bits for transform feedback. +gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMode) +{ + Context11 *context11 = GetImplAs(context); + ANGLE_TRY(context11->triggerDrawCallProgramRecompilation(context, drawMode)); + + const auto &glState = context->getGLState(); + const auto *va11 = GetImplAs(glState.getVertexArray()); + auto *programD3D = GetImplAs(glState.getProgram()); + + programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState); + + // Binaries must be compiled before the sync. + ASSERT(programD3D->hasVertexExecutableForCachedInputLayout()); + ASSERT(programD3D->hasGeometryExecutableForPrimitiveType(drawMode)); + ASSERT(programD3D->hasPixelExecutableForCachedOutputLayout()); + + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr)); + + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); + + ShaderExecutableD3D *geometryExe = nullptr; + ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe, + nullptr)); + + const d3d11::VertexShader *vertexShader = + (vertexExe ? &GetAs(vertexExe)->getVertexShader() : nullptr); + + // Skip pixel shader if we're doing rasterizer discard. + const d3d11::PixelShader *pixelShader = nullptr; + if (!glState.getRasterizerState().rasterizerDiscard) + { + pixelShader = (pixelExe ? &GetAs(pixelExe)->getPixelShader() : nullptr); + } + + const d3d11::GeometryShader *geometryShader = nullptr; + if (glState.isTransformFeedbackActiveUnpaused()) + { + geometryShader = + (vertexExe ? &GetAs(vertexExe)->getStreamOutShader() : nullptr); + } + else + { + geometryShader = + (geometryExe ? &GetAs(geometryExe)->getGeometryShader() : nullptr); + } + + setDrawShaders(vertexShader, geometryShader, pixelShader); + + // Explicitly clear the shaders dirty bit. + mInternalDirtyBits.reset(DIRTY_BIT_SHADERS); + + return gl::NoError(); +} + +gl::Error StateManager11::applyVertexBuffer(const gl::Context *context, + GLenum mode, + const DrawCallVertexParams &vertexParams, + bool isIndexedRendering) +{ + const auto &state = context->getGLState(); + const gl::VertexArray *vertexArray = state.getVertexArray(); + VertexArray11 *vertexArray11 = GetImplAs(vertexArray); + + if (mVertexAttribsNeedTranslation) + { + ANGLE_TRY(vertexArray11->updateDirtyAndDynamicAttribs(context, &mVertexDataManager, + vertexParams)); + mInputLayoutIsDirty = true; + + // Determine if we need to update attribs on the next draw. + mVertexAttribsNeedTranslation = (vertexArray11->hasActiveDynamicAttrib(context)); + } + + if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != vertexParams.firstVertex()) + { + mLastFirstVertex = vertexParams.firstVertex(); + mInputLayoutIsDirty = true; + } + + if (!mInputLayoutIsDirty) + { + return gl::NoError(); + } + + const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs(); + gl::Program *program = state.getProgram(); + + // Sort the attributes according to ensure we re-use similar input layouts. + AttribIndexArray sortedSemanticIndices; + SortAttributesByLayout(program, vertexArrayAttribs, mCurrentValueAttribs, + &sortedSemanticIndices, &mCurrentAttributes); + + auto featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; + + // If we are using FL 9_3, make sure the first attribute is not instanced + if (featureLevel <= D3D_FEATURE_LEVEL_9_3 && !mCurrentAttributes.empty()) + { + if (mCurrentAttributes[0]->divisor > 0) + { + Optional firstNonInstancedIndex = FindFirstNonInstanced(mCurrentAttributes); + if (firstNonInstancedIndex.valid()) + { + size_t index = firstNonInstancedIndex.value(); + std::swap(mCurrentAttributes[0], mCurrentAttributes[index]); + std::swap(sortedSemanticIndices[0], sortedSemanticIndices[index]); + } + } + } + + // Update the applied input layout by querying the cache. + ANGLE_TRY(mInputLayoutCache.updateInputLayout(mRenderer, state, mCurrentAttributes, mode, + sortedSemanticIndices, vertexParams)); + + // Update the applied vertex buffers. + ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(context, mCurrentAttributes, mode, + vertexParams.firstVertex(), isIndexedRendering)); + + // InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex + // buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger + // allocation. This in turn will signal that the buffer is dirty. Since we just resolved the + // dirty-ness in VertexArray11::updateDirtyAndDynamicAttribs, this can make us do a needless + // update on the second draw call. + // Hence we clear the flags here, after we've applied vertex data, since we know everything + // is clean. This is a bit of a hack. + vertexArray11->clearDirtyAndPromoteDynamicAttribs(context, vertexParams); + + mInputLayoutIsDirty = false; + return gl::NoError(); +} + +gl::Error StateManager11::applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + GLenum type, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround) +{ + const auto &glState = context->getGLState(); + gl::VertexArray *vao = glState.getVertexArray(); + VertexArray11 *vao11 = GetImplAs(vao); + + GLenum destElementType = + GetIndexTranslationDestType(type, lazyIndexRange, usePrimitiveRestartWorkaround); + + if (!vao11->updateElementArrayStorage(context, type, destElementType, indices) && + !mIndexBufferIsDirty) + { + // No streaming or index buffer application necessary. + return gl::NoError(); + } + + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo(); + ANGLE_TRY(mIndexDataManager.prepareIndexData(context, type, destElementType, count, + elementArrayBuffer, indices, indexInfo)); + + ID3D11Buffer *buffer = nullptr; + DXGI_FORMAT bufferFormat = + (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + if (indexInfo->storage) + { + Buffer11 *storage = GetAs(indexInfo->storage); + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDEX), buffer); + } + else + { + IndexBuffer11 *indexBuffer = GetAs(indexInfo->indexBuffer); + buffer = indexBuffer->getBuffer().get(); + } + + // Track dirty indices in the index range cache. + indexInfo->srcIndexData.srcIndicesChanged = + syncIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); + + mIndexBufferIsDirty = false; + + vao11->setCachedIndexInfoValid(); + return gl::NoError(); +} + +void StateManager11::setIndexBuffer(ID3D11Buffer *buffer, + DXGI_FORMAT indexFormat, + unsigned int offset) +{ + if (syncIndexBuffer(buffer, indexFormat, offset)) + { + mIndexBufferIsDirty = true; + } +} + +bool StateManager11::syncIndexBuffer(ID3D11Buffer *buffer, + DXGI_FORMAT indexFormat, + unsigned int offset) +{ + if (buffer != mAppliedIB || indexFormat != mAppliedIBFormat || offset != mAppliedIBOffset) + { + mRenderer->getDeviceContext()->IASetIndexBuffer(buffer, indexFormat, offset); + + mAppliedIB = buffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = offset; + return true; + } + + return false; +} + +// Vertex buffer is invalidated outside this function. +gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, + GLsizei emulatedInstanceId) +{ + return mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation( + mRenderer, mCurrentAttributes, startVertex, emulatedInstanceId); +} + +gl::Error StateManager11::generateSwizzle(const gl::Context *context, gl::Texture *texture) +{ + if (!texture) + { + return gl::NoError(); + } + + TextureD3D *textureD3D = GetImplAs(texture); + ASSERT(textureD3D); + + TextureStorage *texStorage = nullptr; + ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage)); + + if (texStorage) + { + TextureStorage11 *storage11 = GetAs(texStorage); + const gl::TextureState &textureState = texture->getTextureState(); + ANGLE_TRY(storage11->generateSwizzles(context, textureState.getSwizzleState())); + } + + return gl::NoError(); +} + +gl::Error StateManager11::generateSwizzlesForShader(const gl::Context *context, + gl::SamplerType type) +{ + const auto &glState = context->getGLState(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(type); + + for (unsigned int i = 0; i < samplerRange; i++) + { + GLenum textureType = programD3D->getSamplerTextureType(type, i); + GLint textureUnit = programD3D->getSamplerMapping(type, i, context->getCaps()); + if (textureUnit != -1) + { + gl::Texture *texture = glState.getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + if (texture->getTextureState().swizzleRequired()) + { + ANGLE_TRY(generateSwizzle(context, texture)); + } + } + } + + return gl::NoError(); +} + +gl::Error StateManager11::generateSwizzles(const gl::Context *context) +{ + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(generateSwizzlesForShader(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +gl::Error StateManager11::applyUniforms(ProgramD3D *programD3D) +{ + UniformStorage11 *vertexUniformStorage = + GetAs(&programD3D->getVertexUniformStorage()); + UniformStorage11 *fragmentUniformStorage = + GetAs(&programD3D->getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + const d3d11::Buffer *vertexConstantBuffer = nullptr; + ANGLE_TRY(vertexUniformStorage->getConstantBuffer(mRenderer, &vertexConstantBuffer)); + const d3d11::Buffer *pixelConstantBuffer = nullptr; + ANGLE_TRY(fragmentUniformStorage->getConstantBuffer(mRenderer, &pixelConstantBuffer)); + + if (vertexUniformStorage->size() > 0 && programD3D->areVertexUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, vertexUniformStorage, vertexConstantBuffer); + } + + if (fragmentUniformStorage->size() > 0 && programD3D->areFragmentUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, fragmentUniformStorage, pixelConstantBuffer); + } + + unsigned int slot = d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK; + + if (mCurrentConstantBufferVS[slot] != vertexConstantBuffer->getSerial()) + { + deviceContext->VSSetConstantBuffers(slot, 1, vertexConstantBuffer->getPointer()); + mCurrentConstantBufferVS[slot] = vertexConstantBuffer->getSerial(); + mCurrentConstantBufferVSOffset[slot] = 0; + mCurrentConstantBufferVSSize[slot] = 0; + } + + if (mCurrentConstantBufferPS[slot] != pixelConstantBuffer->getSerial()) + { + deviceContext->PSSetConstantBuffers(slot, 1, pixelConstantBuffer->getPointer()); + mCurrentConstantBufferPS[slot] = pixelConstantBuffer->getSerial(); + mCurrentConstantBufferPSOffset[slot] = 0; + mCurrentConstantBufferPSSize[slot] = 0; + } + + programD3D->markUniformsClean(); + + return gl::NoError(); +} + +gl::Error StateManager11::applyDriverUniforms(const ProgramD3D &programD3D) +{ + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (!mDriverConstantBufferVS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_VERTEX); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferVS)); + + ID3D11Buffer *driverVSConstants = mDriverConstantBufferVS.get(); + deviceContext->VSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &driverVSConstants); + } + + if (!mDriverConstantBufferPS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_PIXEL); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferPS)); + + ID3D11Buffer *driverVSConstants = mDriverConstantBufferPS.get(); + deviceContext->PSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &driverVSConstants); + } + + // Sampler metadata and driver constants need to coexist in the same constant buffer to conserve + // constant buffer slots. We update both in the constant buffer if needed. + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_VERTEX, programD3D, + mDriverConstantBufferVS)); + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_PIXEL, programD3D, + mDriverConstantBufferPS)); + + // needed for the point sprite geometry shader + // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it for ES3. + if (mRenderer->isES3Capable()) + { + if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS.getSerial()) + { + ASSERT(mDriverConstantBufferPS.valid()); + deviceContext->GSSetConstantBuffers(0, 1, mDriverConstantBufferPS.getPointer()); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS.getSerial(); + } + } + + return gl::NoError(); +} + +gl::Error StateManager11::applyComputeUniforms(ProgramD3D *programD3D) +{ + UniformStorage11 *computeUniformStorage = + GetAs(&programD3D->getComputeUniformStorage()); + ASSERT(computeUniformStorage); + + const d3d11::Buffer *constantBuffer = nullptr; + ANGLE_TRY(computeUniformStorage->getConstantBuffer(mRenderer, &constantBuffer)); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + if (computeUniformStorage->size() > 0 && programD3D->areComputeUniformsDirty()) + { + UpdateUniformBuffer(deviceContext, computeUniformStorage, constantBuffer); + programD3D->markUniformsClean(); + } + + if (mCurrentComputeConstantBuffer != constantBuffer->getSerial()) + { + deviceContext->CSSetConstantBuffers( + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK, 1, + constantBuffer->getPointer()); + mCurrentComputeConstantBuffer = constantBuffer->getSerial(); + } + + if (!mDriverConstantBufferCS.valid()) + { + size_t requiredSize = mShaderConstants.getRequiredBufferSize(gl::SAMPLER_COMPUTE); + + D3D11_BUFFER_DESC constantBufferDescription = {0}; + d3d11::InitConstantBufferDesc(&constantBufferDescription, requiredSize); + ANGLE_TRY(mRenderer->allocateResource(constantBufferDescription, &mDriverConstantBufferCS)); + ID3D11Buffer *buffer = mDriverConstantBufferCS.get(); + deviceContext->CSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_DRIVER, 1, + &buffer); + } + + ANGLE_TRY(mShaderConstants.updateBuffer(deviceContext, gl::SAMPLER_COMPUTE, *programD3D, + mDriverConstantBufferCS)); + + return gl::NoError(); +} + +gl::Error StateManager11::syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D) +{ + unsigned int reservedVertex = mRenderer->getReservedVertexUniformBuffers(); + unsigned int reservedFragment = mRenderer->getReservedFragmentUniformBuffers(); + + programD3D->updateUniformBufferCache(context->getCaps(), reservedVertex, reservedFragment); + + const auto &vertexUniformBuffers = programD3D->getVertexUniformBufferCache(); + const auto &fragmentUniformBuffers = programD3D->getFragmentUniformBufferCache(); + const auto &glState = context->getGLState(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + + for (size_t bufferIndex = 0; bufferIndex < vertexUniformBuffers.size(); bufferIndex++) + { + GLint binding = vertexUniformBuffers[bufferIndex]; + + if (binding == -1) + { + continue; + } + + const auto &uniformBuffer = glState.getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); + + if (uniformBuffer.get() == nullptr) + { + continue; + } + + Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); + const d3d11::Buffer *constantBuffer = nullptr; + UINT firstConstant = 0; + UINT numConstants = 0; + + ANGLE_TRY(bufferStorage->getConstantBufferRange(context, uniformBufferOffset, + uniformBufferSize, &constantBuffer, + &firstConstant, &numConstants)); + + ASSERT(constantBuffer); + + if (mCurrentConstantBufferVS[bufferIndex] == constantBuffer->getSerial() && + mCurrentConstantBufferVSOffset[bufferIndex] == uniformBufferOffset && + mCurrentConstantBufferVSSize[bufferIndex] == uniformBufferSize) + { + continue; + } + + unsigned int appliedIndex = reservedVertex + static_cast(bufferIndex); + + if (firstConstant != 0 && uniformBufferSize != 0) + { + ASSERT(numConstants != 0); + deviceContext1->VSSetConstantBuffers1(appliedIndex, 1, constantBuffer->getPointer(), + &firstConstant, &numConstants); + } + else + { + deviceContext->VSSetConstantBuffers(appliedIndex, 1, constantBuffer->getPointer()); + } + + mCurrentConstantBufferVS[appliedIndex] = constantBuffer->getSerial(); + mCurrentConstantBufferVSOffset[appliedIndex] = uniformBufferOffset; + mCurrentConstantBufferVSSize[appliedIndex] = uniformBufferSize; + } + + for (size_t bufferIndex = 0; bufferIndex < fragmentUniformBuffers.size(); bufferIndex++) + { + GLint binding = fragmentUniformBuffers[bufferIndex]; + + if (binding == -1) + { + continue; + } + + const auto &uniformBuffer = glState.getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = uniformBuffer.getOffset(); + GLsizeiptr uniformBufferSize = uniformBuffer.getSize(); + + if (uniformBuffer.get() == nullptr) + { + continue; + } + + Buffer11 *bufferStorage = GetImplAs(uniformBuffer.get()); + const d3d11::Buffer *constantBuffer = nullptr; + UINT firstConstant = 0; + UINT numConstants = 0; + + ANGLE_TRY(bufferStorage->getConstantBufferRange(context, uniformBufferOffset, + uniformBufferSize, &constantBuffer, + &firstConstant, &numConstants)); + + ASSERT(constantBuffer); + + if (mCurrentConstantBufferPS[bufferIndex] == constantBuffer->getSerial() && + mCurrentConstantBufferPSOffset[bufferIndex] == uniformBufferOffset && + mCurrentConstantBufferPSSize[bufferIndex] == uniformBufferSize) + { + continue; + } + + unsigned int appliedIndex = reservedFragment + static_cast(bufferIndex); + + if (firstConstant != 0 && uniformBufferSize != 0) + { + deviceContext1->PSSetConstantBuffers1(appliedIndex, 1, constantBuffer->getPointer(), + &firstConstant, &numConstants); + } + else + { + deviceContext->PSSetConstantBuffers(appliedIndex, 1, constantBuffer->getPointer()); + } + + mCurrentConstantBufferPS[appliedIndex] = constantBuffer->getSerial(); + mCurrentConstantBufferPSOffset[appliedIndex] = uniformBufferOffset; + mCurrentConstantBufferPSSize[appliedIndex] = uniformBufferSize; + } + + return gl::NoError(); +} + +gl::Error StateManager11::syncTransformFeedbackBuffers(const gl::Context *context) +{ + const auto &glState = context->getGLState(); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // If transform feedback is not active, unbind all buffers + if (!glState.isTransformFeedbackActiveUnpaused()) + { + if (mAppliedTFSerial != mEmptySerial) + { + deviceContext->SOSetTargets(0, nullptr, nullptr); + mAppliedTFSerial = mEmptySerial; + } + return gl::NoError(); + } + + gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); + TransformFeedback11 *tf11 = GetImplAs(transformFeedback); + if (mAppliedTFSerial == tf11->getSerial() && !tf11->isDirty()) + { + return gl::NoError(); + } + + const std::vector *soBuffers = nullptr; + ANGLE_TRY_RESULT(tf11->getSOBuffers(context), soBuffers); + const std::vector &soOffsets = tf11->getSOBufferOffsets(); + + deviceContext->SOSetTargets(tf11->getNumSOBuffers(), soBuffers->data(), soOffsets.data()); + + mAppliedTFSerial = tf11->getSerial(); + tf11->onApply(); + + return gl::NoError(); +} + +// DrawCallVertexParams implementation. +DrawCallVertexParams::DrawCallVertexParams(GLint firstVertex, + GLsizei vertexCount, + GLsizei instances) + : mHasIndexRange(nullptr), + mFirstVertex(firstVertex), + mVertexCount(vertexCount), + mInstances(instances), + mBaseVertex(0) +{ +} + +// Use when in a drawElements call. +DrawCallVertexParams::DrawCallVertexParams(bool firstVertexDefinitelyZero, + const gl::HasIndexRange &hasIndexRange, + GLint baseVertex, + GLsizei instances) + : mHasIndexRange(&hasIndexRange), + mFirstVertex(), + mVertexCount(0), + mInstances(instances), + mBaseVertex(baseVertex) +{ + if (firstVertexDefinitelyZero) + { + mFirstVertex = baseVertex; + } +} + +GLint DrawCallVertexParams::firstVertex() const +{ + if (!mFirstVertex.valid()) + { + ensureResolved(); + ASSERT(mFirstVertex.valid()); + } + return mFirstVertex.value(); +} + +GLsizei DrawCallVertexParams::vertexCount() const +{ + ensureResolved(); + return mVertexCount; +} + +GLsizei DrawCallVertexParams::instances() const +{ + return mInstances; +} + +void DrawCallVertexParams::ensureResolved() const +{ + if (mHasIndexRange) + { + ASSERT(!mFirstVertex.valid() || mFirstVertex == mBaseVertex); + + // Resolve the index range now if we need to. + const auto &indexRange = mHasIndexRange->getIndexRange().value(); + mFirstVertex = mBaseVertex + static_cast(indexRange.start); + mVertexCount = static_cast(indexRange.vertexCount()); + mHasIndexRange = nullptr; + } } } // 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 index f900882d7e..e48bc83a22 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h @@ -11,12 +11,15 @@ #include -#include "libANGLE/angletypes.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/State.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/Query11.h" #include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" namespace rx { @@ -24,20 +27,147 @@ namespace rx struct RenderTargetDesc; struct Renderer11DeviceCaps; -struct dx_VertexConstants11 +class ShaderConstants11 : angle::NonCopyable { - float depthRange[4]; - float viewAdjust[4]; - float viewCoords[4]; - float viewScale[4]; + public: + ShaderConstants11(); + ~ShaderConstants11(); + + void init(const gl::Caps &caps); + size_t getRequiredBufferSize(gl::SamplerType samplerType) const; + void markDirty(); + + void setComputeWorkGroups(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); + void setMultiviewWriteToViewportIndex(GLfloat index); + void onViewportChange(const gl::Rectangle &glViewport, + const D3D11_VIEWPORT &dxViewport, + bool is9_3, + bool presentPathFast); + void onSamplerChange(gl::SamplerType samplerType, + unsigned int samplerIndex, + const gl::Texture &texture); + + gl::Error updateBuffer(ID3D11DeviceContext *deviceContext, + gl::SamplerType samplerType, + const ProgramD3D &programD3D, + const d3d11::Buffer &driverConstantBuffer); + + private: + struct Vertex + { + Vertex() + : depthRange{.0f}, + viewAdjust{.0f}, + viewCoords{.0f}, + viewScale{.0f}, + multiviewWriteToViewportIndex{.0f}, + padding{.0f} + { + } + + float depthRange[4]; + float viewAdjust[4]; + float viewCoords[4]; + float viewScale[2]; + // multiviewWriteToViewportIndex is used to select either the side-by-side or layered + // code-path in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated + // whenever a multi-view draw framebuffer is made active. + float multiviewWriteToViewportIndex; + + // Added here to manually pad the struct. + float padding; + }; + + struct Pixel + { + Pixel() + : depthRange{.0f}, + viewCoords{.0f}, + depthFront{.0f}, + viewScale{.0f}, + multiviewWriteToViewportIndex(0), + padding(0) + { + } + + float depthRange[4]; + float viewCoords[4]; + float depthFront[4]; + float viewScale[2]; + // multiviewWriteToViewportIndex is used to select either the side-by-side or layered + // code-path in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated + // whenever a multi-view draw framebuffer is made active. + float multiviewWriteToViewportIndex; + + // Added here to manually pad the struct. + float padding; + }; + + struct Compute + { + Compute() : numWorkGroups{0u}, padding(0u) {} + unsigned int numWorkGroups[3]; + unsigned int padding; // This just pads the struct to 16 bytes + }; + + struct SamplerMetadata + { + SamplerMetadata() : baseLevel(0), internalFormatBits(0), wrapModes(0), padding(0) {} + + int baseLevel; + int internalFormatBits; + int wrapModes; + int padding; // This just pads the struct to 16 bytes + }; + + static_assert(sizeof(SamplerMetadata) == 16u, + "Sampler metadata struct must be one 4-vec / 16 bytes."); + + // Return true if dirty. + bool updateSamplerMetadata(SamplerMetadata *data, const gl::Texture &texture); + + Vertex mVertex; + bool mVertexDirty; + Pixel mPixel; + bool mPixelDirty; + Compute mCompute; + bool mComputeDirty; + + std::vector mSamplerMetadataVS; + bool mSamplerMetadataVSDirty; + std::vector mSamplerMetadataPS; + bool mSamplerMetadataPSDirty; + std::vector mSamplerMetadataCS; + bool mSamplerMetadataCSDirty; }; -struct dx_PixelConstants11 +class DrawCallVertexParams final : angle::NonCopyable { - float depthRange[4]; - float viewCoords[4]; - float depthFront[4]; - float viewScale[4]; + public: + // Use when in a drawArrays call. + DrawCallVertexParams(GLint firstVertex, GLsizei vertexCount, GLsizei instances); + + // Use when in a drawElements call. + DrawCallVertexParams(bool firstVertexDefinitelyZero, + const gl::HasIndexRange &hasIndexRange, + GLint baseVertex, + GLsizei instances); + + // It should be possible to also use an overload to handle the 'slow' indirect draw path. + // TODO(jmadill): Indirect draw slow path overload. + + GLint firstVertex() const; + GLsizei vertexCount() const; + GLsizei instances() const; + + private: + void ensureResolved() const; + + mutable const gl::HasIndexRange *mHasIndexRange; + mutable Optional mFirstVertex; + mutable GLsizei mVertexCount; + GLsizei mInstances; + GLint mBaseVertex; }; class StateManager11 final : angle::NonCopyable @@ -46,62 +176,221 @@ class StateManager11 final : angle::NonCopyable StateManager11(Renderer11 *renderer); ~StateManager11(); - void initialize(const gl::Caps &caps); - void syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits); + gl::Error initialize(const gl::Caps &caps, const gl::Extensions &extensions); + void deinitialize(); - gl::Error setBlendState(const gl::Framebuffer *framebuffer, - const gl::BlendState &blendState, - const gl::ColorF &blendColor, - unsigned int sampleMask); + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits); - gl::Error setDepthStencilState(const gl::State &glState); + gl::Error updateStateForCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); - gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize); - void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + // These invalidations methods are called externally. - void setViewport(const gl::Caps *caps, const gl::Rectangle &viewport, float zNear, float zFar); + // Called from TextureStorage11. + void invalidateBoundViews(); - void updatePresentPath(bool presentPathFastActive, - const gl::FramebufferAttachment *framebufferAttachment); + // Called from VertexArray11::updateVertexAttribStorage. + void invalidateCurrentValueAttrib(size_t attribIndex); - const dx_VertexConstants11 &getVertexConstants() const { return mVertexConstants; } - const dx_PixelConstants11 &getPixelConstants() const { return mPixelConstants; } + // Checks are done on a framebuffer state change to trigger other state changes. + // The Context is allowed to be nullptr for these methods, when called in EGL init code. + void invalidateRenderTarget(); - void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize); + // Called by instanced point sprite emulation. + void invalidateVertexBuffer(); + + // Called by Framebuffer11::syncState for the default sized viewport. + void invalidateViewport(const gl::Context *context); + + // Called by TextureStorage11::markLevelDirty. + void invalidateSwizzles(); + + // Called by the Framebuffer11 and VertexArray11. + void invalidateShaders(); + // Called by VertexArray11 to trigger attribute translation. + void invalidateVertexAttributeTranslation(); + + void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv); + void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv); + + void onBeginQuery(Query11 *query); + void onDeleteQueryObject(Query11 *query); + gl::Error onMakeCurrent(const gl::Context *context); + + void setInputLayout(const d3d11::InputLayout *inputLayout); + + // TODO(jmadill): Migrate to d3d11::Buffer. + bool queueVertexBufferChange(size_t bufferIndex, + ID3D11Buffer *buffer, + UINT stride, + UINT offset); + bool queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly); + void applyVertexBufferChanges(); + + void setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT stride, UINT offset); + + gl::Error updateState(const gl::Context *context, GLenum drawMode); + + void setShaderResourceShared(gl::SamplerType shaderType, + UINT resourceSlot, + const d3d11::SharedSRV *srv); void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, - ID3D11ShaderResourceView *srv); + const d3d11::ShaderResourceView *srv); + void setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY primitiveTopology); + + void setDrawShaders(const d3d11::VertexShader *vertexShader, + const d3d11::GeometryShader *geometryShader, + const d3d11::PixelShader *pixelShader); + void setVertexShader(const d3d11::VertexShader *shader); + void setGeometryShader(const d3d11::GeometryShader *shader); + void setPixelShader(const d3d11::PixelShader *shader); + void setComputeShader(const d3d11::ComputeShader *shader); + void setVertexConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer); + void setPixelConstantBuffer(unsigned int slot, const d3d11::Buffer *buffer); + void setDepthStencilState(const d3d11::DepthStencilState *depthStencilState, UINT stencilRef); + void setSimpleBlendState(const d3d11::BlendState *blendState); + void setRasterizerState(const d3d11::RasterizerState *rasterizerState); + void setSimpleViewport(const gl::Extents &viewportExtents); + void setSimpleViewport(int width, int height); + void setSimplePixelTextureAndSampler(const d3d11::SharedSRV &srv, + const d3d11::SamplerState &samplerState); + void setSimpleScissorRect(const gl::Rectangle &glRect); + void setScissorRectD3D(const D3D11_RECT &d3dRect); + + // Not handled by an internal dirty bit because of the extra draw parameters. + gl::Error applyVertexBuffer(const gl::Context *context, + GLenum mode, + const DrawCallVertexParams &vertexParams, + bool isIndexedRendering); + + gl::Error applyIndexBuffer(const gl::Context *context, + const void *indices, + GLsizei count, + GLenum type, + const gl::HasIndexRange &lazyIndexRange, + bool usePrimitiveRestartWorkaround); + + void setIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset); + + gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex, + GLsizei emulatedInstanceId); + + // TODO(jmadill): Should be private. + gl::Error applyComputeUniforms(ProgramD3D *programD3D); + + // Only used in testing. + InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; } + + private: + template + void setShaderResourceInternal(gl::SamplerType shaderType, + UINT resourceSlot, + const SRVType *srv); + + bool unsetConflictingView(ID3D11View *view); + bool unsetConflictingSRVs(gl::SamplerType shaderType, + uintptr_t resource, + const gl::ImageIndex *index); + void unsetConflictingAttachmentResources(const gl::FramebufferAttachment *attachment, + ID3D11Resource *resource); + + gl::Error syncBlendState(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::BlendState &blendState, + const gl::ColorF &blendColor, + unsigned int sampleMask); + + gl::Error syncDepthStencilState(const gl::State &glState); + + gl::Error syncRasterizerState(const gl::Context *context, bool pointDrawMode); + + void syncScissorRectangle(const gl::Rectangle &scissor, bool enabled); + + void syncViewport(const gl::Context *context); + + void checkPresentPath(const gl::Context *context); + + gl::Error syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer); + gl::Error syncProgram(const gl::Context *context, GLenum drawMode); + + gl::Error syncTextures(const gl::Context *context); + gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType); + + gl::Error setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &sampler); + gl::Error setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture); + + // Faster than calling setTexture a jillion times gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd); + void handleMultiviewDrawFramebufferChange(const gl::Context *context); - gl::Error syncFramebuffer(const gl::Framebuffer *framebuffer); + gl::Error syncCurrentValueAttribs(const gl::State &glState); - void invalidateRenderTarget(); - void invalidateEverything(); - bool setRenderTargets(const RenderTargetArray &renderTargets, - ID3D11DepthStencilView *depthStencil); - void setRenderTarget(ID3D11RenderTargetView *renderTarget, - ID3D11DepthStencilView *depthStencil); + gl::Error generateSwizzle(const gl::Context *context, gl::Texture *texture); + gl::Error generateSwizzlesForShader(const gl::Context *context, gl::SamplerType type); + gl::Error generateSwizzles(const gl::Context *context); - private: - void unsetConflictingSRVs(gl::SamplerType shaderType, - uintptr_t resource, - const gl::ImageIndex &index); - void setViewportBounds(const int width, const int height); + gl::Error applyDriverUniforms(const ProgramD3D &programD3D); + gl::Error applyUniforms(ProgramD3D *programD3D); + + gl::Error syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D); + gl::Error syncTransformFeedbackBuffers(const gl::Context *context); + + // These are currently only called internally. + void invalidateTexturesAndSamplers(); + void invalidateDriverUniforms(); + void invalidateProgramUniforms(); + void invalidateProgramUniformBuffers(); + void invalidateConstantBuffer(unsigned int slot); + + // Called by the Framebuffer11 directly. + void processFramebufferInvalidation(const gl::Context *context); + + bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset); + + enum DirtyBitType + { + DIRTY_BIT_RENDER_TARGET, + DIRTY_BIT_VIEWPORT_STATE, + DIRTY_BIT_SCISSOR_STATE, + DIRTY_BIT_RASTERIZER_STATE, + DIRTY_BIT_BLEND_STATE, + DIRTY_BIT_DEPTH_STENCIL_STATE, + DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE, + DIRTY_BIT_PROGRAM_UNIFORMS, + DIRTY_BIT_DRIVER_UNIFORMS, + DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS, + DIRTY_BIT_SHADERS, + DIRTY_BIT_CURRENT_VALUE_ATTRIBS, + DIRTY_BIT_INVALID, + DIRTY_BIT_MAX = DIRTY_BIT_INVALID, + }; + + using DirtyBits = angle::BitSet; Renderer11 *mRenderer; + // Internal dirty bits. + DirtyBits mInternalDirtyBits; + // 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; @@ -110,34 +399,35 @@ class StateManager11 final : angle::NonCopyable 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; + // The viewport offsets are guaranteed to be updated whenever the gl::State::DirtyBits are + // resolved and can be applied to the viewport and scissor whenever the internal viewport and + // scissor bits are resolved. + std::vector mViewportOffsets; + // Things needed in viewport state - dx_VertexConstants11 mVertexConstants; - dx_PixelConstants11 mPixelConstants; + ShaderConstants11 mShaderConstants; // Render target variables gl::Extents mViewportBounds; + bool mRenderTargetIsDirty; // EGL_ANGLE_experimental_present_path variables bool mCurPresentPathFastEnabled; int mCurPresentPathFastColorBufferHeight; - // Current RenderTarget state - std::array mAppliedRTVs; - uintptr_t mAppliedDSV; + // Queries that are currently active in this state + std::set mCurrentQueries; // Currently applied textures struct SRVRecord @@ -154,7 +444,8 @@ class StateManager11 final : angle::NonCopyable class SRVCache : angle::NonCopyable { public: - SRVCache() : mHighestUsedSRV(0) {} + SRVCache(); + ~SRVCache(); void initialize(size_t size) { mCurrentSRVs.resize(size); } @@ -175,6 +466,91 @@ class StateManager11 final : angle::NonCopyable // A block of NULL pointers, cached so we don't re-allocate every draw call std::vector mNullSRVs; + + // Current translations of "Current-Value" data - owned by Context, not VertexArray. + gl::AttributesMask mDirtyCurrentValueAttribs; + std::vector mCurrentValueAttribs; + + // Current applied input layout. + ResourceSerial mCurrentInputLayout; + bool mInputLayoutIsDirty; + bool mVertexAttribsNeedTranslation; + + // Current applied vertex states. + // TODO(jmadill): Figure out how to use ResourceSerial here. + std::array mCurrentVertexBuffers; + std::array mCurrentVertexStrides; + std::array mCurrentVertexOffsets; + gl::RangeUI mDirtyVertexBufferRange; + + // Currently applied primitive topology + D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; + + // Currently applied shaders + ResourceSerial mAppliedVertexShader; + ResourceSerial mAppliedGeometryShader; + ResourceSerial mAppliedPixelShader; + ResourceSerial mAppliedComputeShader; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + std::vector mForceSetComputeSamplerStates; + std::vector mCurComputeSamplerStates; + + // Special dirty bit for swizzles. Since they use internal shaders, must be done in a pre-pass. + bool mDirtySwizzles; + + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; + unsigned int mAppliedIBOffset; + bool mIndexBufferIsDirty; + + // Vertex, index and input layouts + VertexDataManager mVertexDataManager; + IndexDataManager mIndexDataManager; + InputLayoutCache mInputLayoutCache; + std::vector mCurrentAttributes; + Optional mLastFirstVertex; + + // ANGLE_multiview. + bool mIsMultiviewEnabled; + + // Driver Constants. + d3d11::Buffer mDriverConstantBufferVS; + d3d11::Buffer mDriverConstantBufferPS; + d3d11::Buffer mDriverConstantBufferCS; + + ResourceSerial mCurrentComputeConstantBuffer; + ResourceSerial mCurrentGeometryConstantBuffer; + + template + using VertexConstantBufferArray = + std::array; + + VertexConstantBufferArray mCurrentConstantBufferVS; + VertexConstantBufferArray mCurrentConstantBufferVSOffset; + VertexConstantBufferArray mCurrentConstantBufferVSSize; + + template + using FragmentConstantBufferArray = + std::array; + + FragmentConstantBufferArray mCurrentConstantBufferPS; + FragmentConstantBufferArray mCurrentConstantBufferPSOffset; + FragmentConstantBufferArray mCurrentConstantBufferPSSize; + + // Currently applied transform feedback buffers + Serial mAppliedTFSerial; + + Serial mEmptySerial; + + bool mIsTransformFeedbackCurrentlyActiveUnpaused; }; } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp new file mode 100644 index 0000000000..1981b5f7b2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// StreamProducerNV12.cpp: Implements the stream producer for NV12 textures + +#include "libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h" + +#include "common/utilities.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +StreamProducerNV12::StreamProducerNV12(Renderer11 *renderer) + : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mTextureWidth(0), mTextureHeight(0) +{ +} + +StreamProducerNV12::~StreamProducerNV12() +{ + SafeRelease(mTexture); +} + +egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer) const +{ + ID3D11Texture2D *textureD3D = static_cast(pointer); + + // Check that the texture originated from our device + ID3D11Device *device; + textureD3D->GetDevice(&device); + if (device != mRenderer->getDevice()) + { + return egl::EglBadParameter() << "Texture not created on ANGLE D3D device"; + } + + // Get the description and validate it + D3D11_TEXTURE2D_DESC desc; + textureD3D->GetDesc(&desc); + if (desc.Format != DXGI_FORMAT_NV12) + { + return egl::EglBadParameter() << "Texture format not DXGI_FORMAT_NV12"; + } + if (desc.Width < 1 || desc.Height < 1) + { + return egl::EglBadParameter() << "Texture is of size 0"; + } + if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0) + { + return egl::EglBadParameter() << "Texture dimensions are not even"; + } + return egl::NoError(); +} + +void StreamProducerNV12::postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) +{ + ASSERT(pointer != nullptr); + ID3D11Texture2D *textureD3D = static_cast(pointer); + + // Check that the texture originated from our device + ID3D11Device *device; + textureD3D->GetDevice(&device); + + // Get the description + D3D11_TEXTURE2D_DESC desc; + textureD3D->GetDesc(&desc); + + // Release the previous texture if there is one + SafeRelease(mTexture); + + mTexture = textureD3D; + mTexture->AddRef(); + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mArraySlice = static_cast(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0)); +} + +egl::Stream::GLTextureDescription StreamProducerNV12::getGLFrameDescription(int planeIndex) +{ + // The UV plane of NV12 textures has half the width/height of the Y plane + egl::Stream::GLTextureDescription desc; + desc.width = (planeIndex == 0) ? mTextureWidth : (mTextureWidth / 2); + desc.height = (planeIndex == 0) ? mTextureHeight : (mTextureHeight / 2); + desc.internalFormat = (planeIndex == 0) ? GL_R8 : GL_RG8; + desc.mipLevels = 0; + return desc; +} + +ID3D11Texture2D *StreamProducerNV12::getD3DTexture() +{ + return mTexture; +} + +UINT StreamProducerNV12::getArraySlice() +{ + return mArraySlice; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h new file mode 100644 index 0000000000..304c9dfe53 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// StreamProducerNV12.h: Interface for a NV12 texture stream producer + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_ + +#include "libANGLE/renderer/StreamProducerImpl.h" + +namespace rx +{ +class Renderer11; + +class StreamProducerNV12 : public StreamProducerImpl +{ + public: + StreamProducerNV12(Renderer11 *renderer); + ~StreamProducerNV12() override; + + egl::Error validateD3DNV12Texture(void *pointer) const override; + void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) override; + egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) override; + + // Gets a pointer to the internal D3D texture + ID3D11Texture2D *getD3DTexture(); + + // Gets the slice index for the D3D texture that the frame is in + UINT getArraySlice(); + + private: + Renderer11 *mRenderer; + + ID3D11Texture2D *mTexture; + UINT mArraySlice; + UINT mTextureWidth; + UINT mTextureHeight; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_STREAM11_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 42c336c8cf..dcfd06484d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -11,9 +11,9 @@ #include #include "libANGLE/features.h" -#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.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" @@ -21,6 +21,7 @@ // Precompiled shaders #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h" #ifdef ANGLE_ENABLE_KEYEDMUTEX #define ANGLE_RESOURCE_SHARE_TYPE D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX @@ -33,22 +34,30 @@ namespace rx namespace { -bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow nativeWindow, EGLint orientation) +// To avoid overflow in QPC to Microseconds calculations, since we multiply +// by kMicrosecondsPerSecond, then the QPC value should not exceed +// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply. +static constexpr int64_t kQPCOverflowThreshold = 0x8637BD05AF7; +static constexpr int64_t kMicrosecondsPerSecond = 1000000; + +bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow11 *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()); + !(renderer->presentPathFastEnabled() && nativeWindow->getNativeWindow()); } } // anonymous namespace SwapChain11::SwapChain11(Renderer11 *renderer, - NativeWindow nativeWindow, + NativeWindow11 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) - : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + EGLint orientation, + EGLint samples) + : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat), mRenderer(renderer), mWidth(-1), mHeight(-1), @@ -56,33 +65,42 @@ SwapChain11::SwapChain11(Renderer11 *renderer, mAppCreatedShareHandle(mShareHandle != nullptr), mSwapInterval(0), mPassThroughResourcesInit(false), + mNativeWindow(nativeWindow), mFirstSwap(true), mSwapChain(nullptr), -#if defined(ANGLE_ENABLE_D3D11_1) mSwapChain1(nullptr), -#endif mKeyedMutex(nullptr), - mBackBufferTexture(nullptr), - mBackBufferRTView(nullptr), - mBackBufferSRView(nullptr), + mBackBufferTexture(), + mBackBufferRTView(), + mBackBufferSRView(), 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), + mOffscreenTexture(), + mOffscreenRTView(), + mOffscreenSRView(), + mNeedsOffscreenTextureCopy(false), + mOffscreenTextureCopyForSRV(), + mDepthStencilTexture(), + mDepthStencilDSView(), + mDepthStencilSRView(), + mQuadVB(), + mPassThroughSampler(), + mPassThroughIL(), + mPassThroughVS(), + mPassThroughPS(), + mPassThroughRS(), mColorRenderTarget(this, renderer, false), - mDepthStencilRenderTarget(this, renderer, true) + mDepthStencilRenderTarget(this, renderer, true), + mEGLSamples(samples) { // Sanity check that if present path fast is active then we're using the default orientation ASSERT(!mRenderer->presentPathFastEnabled() || orientation == 0); + + // Get the performance counter + LARGE_INTEGER counterFreqency = {}; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + ASSERT(success); + + mQPCFrequency = counterFreqency.QuadPart; } SwapChain11::~SwapChain11() @@ -92,52 +110,56 @@ SwapChain11::~SwapChain11() void SwapChain11::release() { -#if defined(ANGLE_ENABLE_D3D11_1) + // TODO(jmadill): Should probably signal that the RenderTarget is dirty. + SafeRelease(mSwapChain1); -#endif SafeRelease(mSwapChain); SafeRelease(mKeyedMutex); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - SafeRelease(mBackBufferSRView); - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); - SafeRelease(mQuadVB); - SafeRelease(mPassThroughSampler); - SafeRelease(mPassThroughIL); - SafeRelease(mPassThroughVS); - SafeRelease(mPassThroughPS); - SafeRelease(mPassThroughRS); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); + mBackBufferSRView.reset(); + mOffscreenTexture.reset(); + mOffscreenRTView.reset(); + mOffscreenSRView.reset(); + mDepthStencilTexture.reset(); + mDepthStencilDSView.reset(); + mDepthStencilSRView.reset(); + mQuadVB.reset(); + mPassThroughSampler.reset(); + mPassThroughIL.reset(); + mPassThroughVS.reset(); + mPassThroughPS.reset(); + mPassThroughRS.reset(); if (!mAppCreatedShareHandle) { - mShareHandle = NULL; + mShareHandle = nullptr; } } void SwapChain11::releaseOffscreenColorBuffer() { - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); + mOffscreenTexture.reset(); + mOffscreenRTView.reset(); + mOffscreenSRView.reset(); + mNeedsOffscreenTextureCopy = false; + mOffscreenTextureCopyForSRV.reset(); } void SwapChain11::releaseOffscreenDepthBuffer() { - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); + mDepthStencilTexture.reset(); + mDepthStencilDSView.reset(); + mDepthStencilSRView.reset(); } -EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHeight) +EGLint SwapChain11::resetOffscreenBuffers(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { if (mNeedsOffscreenTexture) { - EGLint result = resetOffscreenColorBuffer(backbufferWidth, backbufferHeight); + EGLint result = resetOffscreenColorBuffer(context, backbufferWidth, backbufferHeight); if (result != EGL_SUCCESS) { return result; @@ -156,117 +178,106 @@ EGLint SwapChain11::resetOffscreenBuffers(int backbufferWidth, int backbufferHei return EGL_SUCCESS; } -EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight) +EGLint SwapChain11::resetOffscreenColorBuffer(const gl::Context *context, + int backbufferWidth, + int backbufferHeight) { ASSERT(mNeedsOffscreenTexture); TRACE_EVENT0("gpu.angle", "SwapChain11::resetOffscreenTexture"); ID3D11Device *device = mRenderer->getDevice(); - ASSERT(device != NULL); + ASSERT(device != nullptr); // D3D11 does not allow zero size textures ASSERT(backbufferWidth >= 1); ASSERT(backbufferHeight >= 1); // Preserve the render target content - ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; - if (previousOffscreenTexture) - { - previousOffscreenTexture->AddRef(); - } + TextureHelper11 previousOffscreenTexture(std::move(mOffscreenTexture)); const int previousWidth = mWidth; const int previousHeight = mHeight; releaseOffscreenColorBuffer(); - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - // If the app passed in a share handle, open the resource - // See EGL_ANGLE_d3d_share_handle_client_buffer - if (mAppCreatedShareHandle) + // If the app passed in a share handle or D3D texture, open the resource + // See EGL_ANGLE_d3d_share_handle_client_buffer and EGL_ANGLE_d3d_texture_client_buffer + if (mAppCreatedShareHandle || mD3DTexture != nullptr) { - ID3D11Resource *tempResource11; - HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); + if (mAppCreatedShareHandle) + { + ID3D11Resource *tempResource11; + HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), + (void **)&tempResource11); + ASSERT(SUCCEEDED(result)); - if (FAILED(result)) + mOffscreenTexture.set(d3d11::DynamicCastComObject(tempResource11), + backbufferFormatInfo); + SafeRelease(tempResource11); + } + else if (mD3DTexture != nullptr) { - ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; + mOffscreenTexture.set(d3d11::DynamicCastComObject(mD3DTexture), + backbufferFormatInfo); } - - result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); - SafeRelease(tempResource11); - - if (FAILED(result)) + else { - ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; + UNREACHABLE(); } + ASSERT(mOffscreenTexture.valid()); + mOffscreenTexture.getDesc(&offscreenTextureDesc); - // Validate offscreen texture parameters - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - mOffscreenTexture->GetDesc(&offscreenTextureDesc); - - if (offscreenTextureDesc.Width != (UINT)backbufferWidth || - offscreenTextureDesc.Height != (UINT)backbufferHeight || - offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || - offscreenTextureDesc.MipLevels != 1 || - offscreenTextureDesc.ArraySize != 1) + // Fail if the offscreen texture is not renderable. + if ((offscreenTextureDesc.BindFlags & D3D11_BIND_RENDER_TARGET) == 0) { - ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); + ERR() << "Could not use provided offscreen texture, texture not renderable."; release(); - return EGL_BAD_PARAMETER; + return EGL_BAD_SURFACE; } } else { - const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + const bool useSharedResource = + !mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport(); - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; offscreenTextureDesc.Width = backbufferWidth; offscreenTextureDesc.Height = backbufferHeight; - offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; offscreenTextureDesc.MipLevels = 1; offscreenTextureDesc.ArraySize = 1; - offscreenTextureDesc.SampleDesc.Count = 1; + offscreenTextureDesc.SampleDesc.Count = getD3DSamples(); offscreenTextureDesc.SampleDesc.Quality = 0; offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; offscreenTextureDesc.CPUAccessFlags = 0; offscreenTextureDesc.MiscFlags = useSharedResource ? ANGLE_RESOURCE_SHARE_TYPE : 0; - HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); - - if (FAILED(result)) + gl::Error err = mRenderer->allocateTexture(offscreenTextureDesc, backbufferFormatInfo, + &mOffscreenTexture); + if (err.isError()) { - ERR("Could not create offscreen texture: %08lX", result); + ERR() << "Could not create offscreen texture, " << err; release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } + return EGL_BAD_ALLOC; } - d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); + mOffscreenTexture.setDebugName("Offscreen back buffer texture"); // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client if (useSharedResource) { - IDXGIResource *offscreenTextureResource = NULL; - result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource); + IDXGIResource *offscreenTextureResource = nullptr; + HRESULT result = mOffscreenTexture.get()->QueryInterface( + __uuidof(IDXGIResource), (void **)&offscreenTextureResource); // Fall back to no share handle on failure if (FAILED(result)) { - ERR("Could not query offscreen texture resource: %08lX", result); + ERR() << "Could not query offscreen texture resource, " << gl::FmtHR(result); } else { @@ -275,36 +286,49 @@ EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbuffe if (FAILED(result)) { - mShareHandle = NULL; - ERR("Could not get offscreen texture shared handle: %08lX", result); + mShareHandle = nullptr; + ERR() << "Could not get offscreen texture shared handle, " << gl::FmtHR(result); } } } } // This may return null if the original texture was created without a keyed mutex. - mKeyedMutex = d3d11::DynamicCastComObject(mOffscreenTexture); + mKeyedMutex = d3d11::DynamicCastComObject(mOffscreenTexture.get()); D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; - offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; - offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; + offscreenRTVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; offscreenRTVDesc.Texture2D.MipSlice = 0; - HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + gl::Error err = + mRenderer->allocateResource(offscreenRTVDesc, mOffscreenTexture.get(), &mOffscreenRTView); + ASSERT(!err.isError()); + mOffscreenRTView.setDebugName("Offscreen back buffer render target"); D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; - offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; - offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; offscreenSRVDesc.Texture2D.MostDetailedMip = 0; offscreenSRVDesc.Texture2D.MipLevels = static_cast(-1); - result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); + if (offscreenTextureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + { + err = mRenderer->allocateResource(offscreenSRVDesc, mOffscreenTexture.get(), + &mOffscreenSRView); + ASSERT(!err.isError()); + mOffscreenSRView.setDebugName("Offscreen back buffer shader resource"); + } + else + { + // Special case for external textures that cannot support sampling. Since internally we + // assume our SwapChain is always readable, we make a copy texture that is compatible. + mNeedsOffscreenTextureCopy = true; + } - if (previousOffscreenTexture != nullptr) + if (previousOffscreenTexture.valid()) { D3D11_BOX sourceBox = {0}; sourceBox.left = 0; @@ -316,14 +340,12 @@ EGLint SwapChain11::resetOffscreenColorBuffer(int backbufferWidth, int backbuffe ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); const int yoffset = std::max(backbufferHeight - previousHeight, 0); - deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, - previousOffscreenTexture, 0, &sourceBox); - - SafeRelease(previousOffscreenTexture); + deviceContext->CopySubresourceRegion(mOffscreenTexture.get(), 0, 0, yoffset, 0, + previousOffscreenTexture.get(), 0, &sourceBox); if (mSwapChain) { - swapRect(0, 0, backbufferWidth, backbufferHeight); + swapRect(context, 0, 0, backbufferWidth, backbufferHeight); } } @@ -336,21 +358,38 @@ EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbuffe if (mDepthBufferFormat != GL_NONE) { - const d3d11::TextureFormat &depthBufferFormatInfo = - d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps()); + const d3d11::Format &depthBufferFormatInfo = + d3d11::Format::Get(mDepthBufferFormat, mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC depthStencilTextureDesc; depthStencilTextureDesc.Width = backbufferWidth; depthStencilTextureDesc.Height = backbufferHeight; - depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; depthStencilTextureDesc.MipLevels = 1; depthStencilTextureDesc.ArraySize = 1; - depthStencilTextureDesc.SampleDesc.Count = 1; - depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.SampleDesc.Count = getD3DSamples(); depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + // If there is a multisampled offscreen color texture, the offscreen depth-stencil texture + // must also have the same quality value. + if (mOffscreenTexture.valid() && getD3DSamples() > 1) + { + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture.getDesc(&offscreenTextureDesc); + depthStencilTextureDesc.SampleDesc.Quality = offscreenTextureDesc.SampleDesc.Quality; + } + else + { + depthStencilTextureDesc.SampleDesc.Quality = 0; + } + + // Only create an SRV if it is supported + bool depthStencilSRV = + depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN && + (mRenderer->getRenderer11DeviceCaps().supportsMultisampledDepthStencilSRVs || + depthStencilTextureDesc.SampleDesc.Count <= 1); + if (depthStencilSRV) { depthStencilTextureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; } @@ -358,58 +397,56 @@ EGLint SwapChain11::resetOffscreenDepthBuffer(int backbufferWidth, int backbuffe depthStencilTextureDesc.CPUAccessFlags = 0; depthStencilTextureDesc.MiscFlags = 0; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = - device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); - if (FAILED(result)) + gl::Error err = mRenderer->allocateTexture(depthStencilTextureDesc, depthBufferFormatInfo, + &mDepthStencilTexture); + if (err.isError()) { - ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + ERR() << "Could not create depthstencil surface for new swap chain, " << err; release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } + return EGL_BAD_ALLOC; } - d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + mDepthStencilTexture.setDebugName("Offscreen depth stencil texture"); D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; - depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; - depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; + depthStencilDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; depthStencilDesc.Flags = 0; depthStencilDesc.Texture2D.MipSlice = 0; - result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + err = mRenderer->allocateResource(depthStencilDesc, mDepthStencilTexture.get(), + &mDepthStencilDSView); + ASSERT(!err.isError()); + mDepthStencilDSView.setDebugName("Offscreen depth stencil view"); - if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + if (depthStencilSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; - depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; - depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; + depthStencilSRVDesc.ViewDimension = (mEGLSamples <= 1) + ? D3D11_SRV_DIMENSION_TEXTURE2D + : D3D11_SRV_DIMENSION_TEXTURE2DMS; depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; depthStencilSRVDesc.Texture2D.MipLevels = static_cast(-1); - result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); + err = mRenderer->allocateResource(depthStencilSRVDesc, mDepthStencilTexture.get(), + &mDepthStencilSRView); + ASSERT(!err.isError()); + mDepthStencilSRView.setDebugName("Offscreen depth stencil shader resource"); } } return EGL_SUCCESS; } -EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +EGLint SwapChain11::resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight) { TRACE_EVENT0("gpu.angle", "SwapChain11::resize"); ID3D11Device *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return EGL_BAD_ACCESS; } @@ -427,18 +464,19 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) } // Can only call resize if we have already created our swap buffer and resources - ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView && mBackBufferSRView); + ASSERT(mSwapChain && mBackBufferTexture.valid() && mBackBufferRTView.valid() && + mBackBufferSRView.valid()); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - SafeRelease(mBackBufferSRView); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); + mBackBufferSRView.reset(); // Resize swap chain DXGI_SWAP_CHAIN_DESC desc; HRESULT result = mSwapChain->GetDesc(&desc); if (FAILED(result)) { - ERR("Error reading swap chain description: 0x%08X", result); + ERR() << "Error reading swap chain description, " << gl::FmtHR(result); release(); return EGL_BAD_ALLOC; } @@ -447,7 +485,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) if (FAILED(result)) { - ERR("Error resizing swap chain buffers: 0x%08X", result); + ERR() << "Error resizing swap chain buffers, " << gl::FmtHR(result); release(); if (d3d11::isDeviceLostError(result)) @@ -460,39 +498,64 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) } } - result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ID3D11Texture2D *backbufferTexture = nullptr; + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), + reinterpret_cast(&backbufferTexture)); ASSERT(SUCCEEDED(result)); 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->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource"); - } + const auto &format = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + mBackBufferTexture.set(backbufferTexture, format); + mBackBufferTexture.setDebugName("Back buffer texture"); + + gl::Error err = + mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferRTView); + ASSERT(!err.isError()); + mBackBufferRTView.setDebugName("Back buffer render target"); + + err = mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferSRView); + ASSERT(!err.isError()); + mBackBufferSRView.setDebugName("Back buffer shader resource"); } mFirstSwap = true; - return resetOffscreenBuffers(backbufferWidth, backbufferHeight); + return resetOffscreenBuffers(context, 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; + switch (mOffscreenRenderTargetFormat) + { + case GL_RGBA8: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB8: + case GL_RGB565: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case GL_BGRA8_EXT: + return DXGI_FORMAT_B8G8R8A8_UNORM; + + case GL_RGB10_A2: + return DXGI_FORMAT_R10G10B10A2_UNORM; + + case GL_RGBA16F: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + default: + UNREACHABLE(); + return DXGI_FORMAT_UNKNOWN; + } } -EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +EGLint SwapChain11::reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) { mSwapInterval = static_cast(swapInterval); if (mSwapInterval > 4) @@ -505,25 +568,23 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap // If the swap chain already exists, just resize if (mSwapChain != nullptr) { - return resize(backbufferWidth, backbufferHeight); + return resize(context, backbufferWidth, backbufferHeight); } TRACE_EVENT0("gpu.angle", "SwapChain11::reset"); ID3D11Device *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return EGL_BAD_ACCESS; } // 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); + mBackBufferTexture.reset(); + mBackBufferRTView.reset(); // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains if (backbufferWidth < 1 || backbufferHeight < 1) @@ -532,15 +593,16 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap return EGL_SUCCESS; } - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), - getSwapChainNativeFormat(), - backbufferWidth, backbufferHeight, &mSwapChain); + HRESULT result = mNativeWindow->createSwapChain( + device, mRenderer->getDxgiFactory(), getSwapChainNativeFormat(), backbufferWidth, + backbufferHeight, getD3DSamples(), &mSwapChain); if (FAILED(result)) { - ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + ERR() << "Could not create additional swap chains or offscreen surfaces, " + << gl::FmtHR(result); release(); if (d3d11::isDeviceLostError(result)) @@ -555,27 +617,31 @@ 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"); - - result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); - - result = device->CreateShaderResourceView(mBackBufferTexture, nullptr, &mBackBufferSRView); + ID3D11Texture2D *backbufferTex = nullptr; + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), + reinterpret_cast(&backbufferTex)); ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mBackBufferSRView, "Back buffer shader resource view"); + const auto &format = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + mBackBufferTexture.set(backbufferTex, format); + mBackBufferTexture.setDebugName("Back buffer texture"); + + gl::Error err = + mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferRTView); + ASSERT(!err.isError()); + mBackBufferRTView.setDebugName("Back buffer render target"); + + err = mRenderer->allocateResourceNoDesc(mBackBufferTexture.get(), &mBackBufferSRView); + ASSERT(!err.isError()); + mBackBufferSRView.setDebugName("Back buffer shader resource view"); } mFirstSwap = true; - return resetOffscreenBuffers(backbufferWidth, backbufferHeight); + return resetOffscreenBuffers(context, backbufferWidth, backbufferHeight); } void SwapChain11::initPassThroughResources() @@ -588,11 +654,11 @@ void SwapChain11::initPassThroughResources() TRACE_EVENT0("gpu.angle", "SwapChain11::initPassThroughResources"); ID3D11Device *device = mRenderer->getDevice(); - ASSERT(device != NULL); + ASSERT(device != nullptr); // Make sure our resources are all not allocated, when we create - ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); - ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); + ASSERT(!mQuadVB.valid() && !mPassThroughSampler.valid()); + ASSERT(!mPassThroughIL.valid() && !mPassThroughVS.valid() && !mPassThroughPS.valid()); D3D11_BUFFER_DESC vbDesc; vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; @@ -602,9 +668,9 @@ void SwapChain11::initPassThroughResources() vbDesc.MiscFlags = 0; vbDesc.StructureByteStride = 0; - HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); + gl::Error err = mRenderer->allocateResource(vbDesc, &mQuadVB); + ASSERT(!err.isError()); + mQuadVB.setDebugName("Swap chain quad vertex buffer"); D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; @@ -621,9 +687,9 @@ void SwapChain11::initPassThroughResources() samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; - result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); + err = mRenderer->allocateResource(samplerDesc, &mPassThroughSampler); + ASSERT(!err.isError()); + mPassThroughSampler.setDebugName("Swap chain pass through sampler"); D3D11_INPUT_ELEMENT_DESC quadLayout[] = { @@ -631,17 +697,30 @@ void SwapChain11::initPassThroughResources() { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; - result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); + InputElementArray quadElements(quadLayout); + ShaderData vertexShaderData(g_VS_Passthrough2D); - result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); + err = mRenderer->allocateResource(quadElements, &vertexShaderData, &mPassThroughIL); + ASSERT(!err.isError()); + mPassThroughIL.setDebugName("Swap chain pass through layout"); - result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); + err = mRenderer->allocateResource(vertexShaderData, &mPassThroughVS); + ASSERT(!err.isError()); + mPassThroughVS.setDebugName("Swap chain pass through vertex shader"); + + if (mEGLSamples <= 1) + { + ShaderData pixelShaderData(g_PS_PassthroughRGBA2D); + err = mRenderer->allocateResource(pixelShaderData, &mPassThroughPS); + } + else + { + ShaderData pixelShaderData(g_PS_PassthroughRGBA2DMS); + err = mRenderer->allocateResource(pixelShaderData, &mPassThroughPS); + } + + ASSERT(!err.isError()); + mPassThroughPS.setDebugName("Swap chain pass through pixel shader"); // Use the default rasterizer state but without culling D3D11_RASTERIZER_DESC rasterizerDesc; @@ -655,26 +734,31 @@ void SwapChain11::initPassThroughResources() 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"); + + err = mRenderer->allocateResource(rasterizerDesc, &mPassThroughRS); + ASSERT(!err.isError()); + mPassThroughRS.setDebugName("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) +EGLint SwapChain11::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (mNeedsOffscreenTexture) { - EGLint result = copyOffscreenToBackbuffer(x, y, width, height); + EGLint result = copyOffscreenToBackbuffer(context, x, y, width, height); if (result != EGL_SUCCESS) { return result; } } - EGLint result = present(x, y, width, height); + EGLint result = present(context, x, y, width, height); if (result != EGL_SUCCESS) { return result; @@ -685,7 +769,11 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) return EGL_SUCCESS; } -EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -698,7 +786,8 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, // Set vertices D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + HRESULT result = + deviceContext->Map(mQuadVB.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { return EGL_BAD_ACCESS; @@ -716,7 +805,6 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, float v1 = y / float(height); float u2 = (x + width) / float(width); float v2 = (y + height) / float(height); - // Invert the quad vertices depending on the surface orientation. if ((mOrientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE) != 0) { @@ -732,60 +820,43 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(EGLint x, EGLint y, EGLint width, d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); - deviceContext->Unmap(mQuadVB, 0); + deviceContext->Unmap(mQuadVB.get(), 0); - static UINT stride = sizeof(d3d11::PositionTexCoordVertex); - static UINT startIdx = 0; - deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); - - // Apply state - deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + StateManager11 *stateManager = mRenderer->getStateManager(); - static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); + constexpr UINT stride = sizeof(d3d11::PositionTexCoordVertex); + stateManager->setSingleVertexBuffer(&mQuadVB, stride, 0); - deviceContext->RSSetState(mPassThroughRS); + // Apply state + stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); + stateManager->setSimpleBlendState(nullptr); + stateManager->setRasterizerState(&mPassThroughRS); // Apply shaders - deviceContext->IASetInputLayout(mPassThroughIL); - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - deviceContext->VSSetShader(mPassThroughVS, NULL, 0); - deviceContext->PSSetShader(mPassThroughPS, NULL, 0); - deviceContext->GSSetShader(NULL, NULL, 0); + stateManager->setInputLayout(&mPassThroughIL); + stateManager->setPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + stateManager->setDrawShaders(&mPassThroughVS, nullptr, &mPassThroughPS); - // Apply render targets - mRenderer->setOneTimeRenderTarget(mBackBufferRTView); + // Apply render targets. Use the proxy context in display. + stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr); // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = static_cast(width); - viewport.Height = static_cast(height); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); + stateManager->setSimpleViewport(mWidth, mHeight); // Apply textures - auto stateManager = mRenderer->getStateManager(); - stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); - deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); + stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, 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) +EGLint SwapChain11::present(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -799,9 +870,9 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) 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) + // Dirty rect present is not supported with a multisampled swapchain. + if (mSwapChain1 != nullptr && mEGLSamples <= 1) { if (mFirstSwap) { @@ -818,7 +889,6 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) } } else -#endif { result = mSwapChain->Present(swapInterval, 0); } @@ -826,60 +896,111 @@ EGLint SwapChain11::present(EGLint x, EGLint y, EGLint width, EGLint height) mFirstSwap = false; // Some swapping mechanisms such as DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL unbind the current render - // target. Mark it dirty. + // target. Mark it dirty. Use the proxy context in display since there is none available. mRenderer->getStateManager()->invalidateRenderTarget(); if (result == DXGI_ERROR_DEVICE_REMOVED) { - ERR("Present failed: the D3D11 device was removed: 0x%08X", - mRenderer->getDevice()->GetDeviceRemovedReason()); + ERR() << "Present failed: the D3D11 device was removed, " + << gl::FmtHR(mRenderer->getDevice()->GetDeviceRemovedReason()); return EGL_CONTEXT_LOST; } else if (result == DXGI_ERROR_DEVICE_RESET) { - ERR("Present failed: the D3D11 device was reset from a bad command."); + ERR() << "Present failed: the D3D11 device was reset from a bad command."; return EGL_CONTEXT_LOST; } else if (FAILED(result)) { - ERR("Present failed with error code 0x%08X", result); + ERR() << "Present failed with " << gl::FmtHR(result); } - mNativeWindow.commitChange(); + mNativeWindow->commitChange(); return EGL_SUCCESS; } -ID3D11Texture2D *SwapChain11::getOffscreenTexture() +const TextureHelper11 &SwapChain11::getOffscreenTexture() { return mNeedsOffscreenTexture ? mOffscreenTexture : mBackBufferTexture; } -ID3D11RenderTargetView *SwapChain11::getRenderTarget() +const d3d11::RenderTargetView &SwapChain11::getRenderTarget() { return mNeedsOffscreenTexture ? mOffscreenRTView : mBackBufferRTView; } -ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() +const d3d11::SharedSRV &SwapChain11::getRenderTargetShaderResource() { - return mNeedsOffscreenTexture ? mOffscreenSRView : mBackBufferSRView; + if (!mNeedsOffscreenTexture) + { + ASSERT(mBackBufferSRView.valid()); + return mBackBufferSRView; + } + + if (!mNeedsOffscreenTextureCopy) + { + ASSERT(mOffscreenSRView.valid()); + return mOffscreenSRView; + } + + if (!mOffscreenTextureCopyForSRV.valid()) + { + const d3d11::Format &backbufferFormatInfo = + d3d11::Format::Get(mOffscreenRenderTargetFormat, mRenderer->getRenderer11DeviceCaps()); + + D3D11_TEXTURE2D_DESC offscreenCopyDesc; + mOffscreenTexture.getDesc(&offscreenCopyDesc); + + offscreenCopyDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + offscreenCopyDesc.MiscFlags = 0; + offscreenCopyDesc.CPUAccessFlags = 0; + gl::Error err = mRenderer->allocateTexture(offscreenCopyDesc, backbufferFormatInfo, + &mOffscreenTextureCopyForSRV); + ASSERT(!err.isError()); + mOffscreenTextureCopyForSRV.setDebugName("Offscreen back buffer copy for SRV"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = + (mEGLSamples <= 1) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = static_cast(-1); + + err = mRenderer->allocateResource(offscreenSRVDesc, mOffscreenTextureCopyForSRV.get(), + &mOffscreenSRView); + ASSERT(!err.isError()); + mOffscreenSRView.setDebugName("Offscreen back buffer shader resource"); + } + + // Need to copy the offscreen texture into the shader-readable copy, since it's external and + // we don't know if the copy is up-to-date. This works around the problem we have when the app + // passes in a texture that isn't shader-readable. + mRenderer->getDeviceContext()->CopyResource(mOffscreenTextureCopyForSRV.get(), + mOffscreenTexture.get()); + return mOffscreenSRView; } -ID3D11DepthStencilView *SwapChain11::getDepthStencil() +const d3d11::DepthStencilView &SwapChain11::getDepthStencil() { return mDepthStencilDSView; } -ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() +const d3d11::SharedSRV &SwapChain11::getDepthStencilShaderResource() { return mDepthStencilSRView; } -ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +const TextureHelper11 &SwapChain11::getDepthStencilTexture() { return mDepthStencilTexture; } +void *SwapChain11::getKeyedMutex() +{ + return mKeyedMutex; +} + void SwapChain11::recreate() { // possibly should use this method instead of reset @@ -890,4 +1011,61 @@ void *rx::SwapChain11::getDevice() return mRenderer->getDevice(); } +RenderTargetD3D *SwapChain11::getColorRenderTarget() +{ + return &mColorRenderTarget; +} + +RenderTargetD3D *SwapChain11::getDepthStencilRenderTarget() +{ + return &mDepthStencilRenderTarget; +} + +egl::Error SwapChain11::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + if (!mSwapChain) + { + return egl::EglNotInitialized() << "Swap chain uninitialized"; + } + + DXGI_FRAME_STATISTICS stats = {}; + HRESULT result = mSwapChain->GetFrameStatistics(&stats); + + if (FAILED(result)) + { + return egl::EglBadAlloc() << "Failed to get frame statistics, " << gl::FmtHR(result); + } + + // Conversion from DXGI_FRAME_STATISTICS to the output values: + // stats.SyncRefreshCount -> msc + // stats.PresentCount -> sbc + // stats.SyncQPCTime -> ust with conversion to microseconds via QueryPerformanceFrequency + *msc = stats.SyncRefreshCount; + *sbc = stats.PresentCount; + + LONGLONG syncQPCValue = stats.SyncQPCTime.QuadPart; + // If the QPC Value is below the overflow threshold, we proceed with + // simple multiply and divide. + if (syncQPCValue < kQPCOverflowThreshold) + { + *ust = syncQPCValue * kMicrosecondsPerSecond / mQPCFrequency; + } + else + { + // Otherwise, calculate microseconds in a round about manner to avoid + // overflow and precision issues. + int64_t wholeSeconds = syncQPCValue / mQPCFrequency; + int64_t leftoverTicks = syncQPCValue - (wholeSeconds * mQPCFrequency); + *ust = wholeSeconds * kMicrosecondsPerSecond + + leftoverTicks * kMicrosecondsPerSecond / mQPCFrequency; + } + + return egl::NoError(); +} + +UINT SwapChain11::getD3DSamples() const +{ + return (mEGLSamples == 0) ? 1 : mEGLSamples; } + +} // namespace rx 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 adcd07adb0..eca068210b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h @@ -16,39 +16,54 @@ namespace rx { class Renderer11; +class NativeWindow11; -class SwapChain11 : public SwapChainD3D +class SwapChain11 final : public SwapChainD3D { public: SwapChain11(Renderer11 *renderer, - NativeWindow nativeWindow, + NativeWindow11 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation); - virtual ~SwapChain11(); - - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - virtual void recreate(); - - RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } - RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } - - virtual ID3D11Texture2D *getOffscreenTexture(); - virtual ID3D11RenderTargetView *getRenderTarget(); - virtual ID3D11ShaderResourceView *getRenderTargetShaderResource(); - - virtual ID3D11Texture2D *getDepthStencilTexture(); - virtual ID3D11DepthStencilView *getDepthStencil(); - virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); + EGLint orientation, + EGLint samples); + ~SwapChain11() override; + + EGLint resize(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight) override; + EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) override; + EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; + void recreate() override; + + RenderTargetD3D *getColorRenderTarget() override; + RenderTargetD3D *getDepthStencilRenderTarget() override; + + const TextureHelper11 &getOffscreenTexture(); + const d3d11::RenderTargetView &getRenderTarget(); + const d3d11::SharedSRV &getRenderTargetShaderResource(); + + const TextureHelper11 &getDepthStencilTexture(); + const d3d11::DepthStencilView &getDepthStencil(); + const d3d11::SharedSRV &getDepthStencilShaderResource(); EGLint getWidth() const { return mWidth; } EGLint getHeight() const { return mHeight; } - void *getKeyedMutex() override { return mKeyedMutex; } + void *getKeyedMutex() override; + EGLint getSamples() const { return mEGLSamples; } + + void *getDevice() override; - virtual void *getDevice(); + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; private: void release(); @@ -56,14 +71,23 @@ class SwapChain11 : public SwapChainD3D void releaseOffscreenColorBuffer(); void releaseOffscreenDepthBuffer(); - EGLint resetOffscreenBuffers(int backbufferWidth, int backbufferHeight); - EGLint resetOffscreenColorBuffer(int backbufferWidth, int backbufferHeight); + EGLint resetOffscreenBuffers(const gl::Context *context, + int backbufferWidth, + int backbufferHeight); + EGLint resetOffscreenColorBuffer(const gl::Context *context, + 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); + EGLint copyOffscreenToBackbuffer(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height); + EGLint present(const gl::Context *context, EGLint x, EGLint y, EGLint width, EGLint height); + UINT getD3DSamples() const; Renderer11 *mRenderer; EGLint mWidth; @@ -73,36 +97,41 @@ class SwapChain11 : public SwapChainD3D unsigned int mSwapInterval; bool mPassThroughResourcesInit; + NativeWindow11 *mNativeWindow; // Handler for the Window that the surface is created for. + bool mFirstSwap; - DXGISwapChain *mSwapChain; -#if defined(ANGLE_ENABLE_D3D11_1) + IDXGISwapChain *mSwapChain; IDXGISwapChain1 *mSwapChain1; -#endif IDXGIKeyedMutex *mKeyedMutex; - ID3D11Texture2D *mBackBufferTexture; - ID3D11RenderTargetView *mBackBufferRTView; - ID3D11ShaderResourceView *mBackBufferSRView; + TextureHelper11 mBackBufferTexture; + d3d11::RenderTargetView mBackBufferRTView; + d3d11::SharedSRV mBackBufferSRView; const bool mNeedsOffscreenTexture; - ID3D11Texture2D *mOffscreenTexture; - ID3D11RenderTargetView *mOffscreenRTView; - ID3D11ShaderResourceView *mOffscreenSRView; - - ID3D11Texture2D *mDepthStencilTexture; - ID3D11DepthStencilView *mDepthStencilDSView; - ID3D11ShaderResourceView *mDepthStencilSRView; - - ID3D11Buffer *mQuadVB; - ID3D11SamplerState *mPassThroughSampler; - ID3D11InputLayout *mPassThroughIL; - ID3D11VertexShader *mPassThroughVS; - ID3D11PixelShader *mPassThroughPS; - ID3D11RasterizerState *mPassThroughRS; + TextureHelper11 mOffscreenTexture; + d3d11::RenderTargetView mOffscreenRTView; + d3d11::SharedSRV mOffscreenSRView; + bool mNeedsOffscreenTextureCopy; + TextureHelper11 mOffscreenTextureCopyForSRV; + + TextureHelper11 mDepthStencilTexture; + d3d11::DepthStencilView mDepthStencilDSView; + d3d11::SharedSRV mDepthStencilSRView; + + d3d11::Buffer mQuadVB; + d3d11::SamplerState mPassThroughSampler; + d3d11::InputLayout mPassThroughIL; + d3d11::VertexShader mPassThroughVS; + d3d11::PixelShader mPassThroughPS; + d3d11::RasterizerState mPassThroughRS; SurfaceRenderTarget11 mColorRenderTarget; SurfaceRenderTarget11 mDepthStencilRenderTarget; + + EGLint mEGLSamples; + LONGLONG mQPCFrequency; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ 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 11b9f76464..b702450ded 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp @@ -5,7 +5,8 @@ // // TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived -// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 +// texture. #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" @@ -21,6 +22,7 @@ #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/StreamProducerNV12.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" @@ -29,82 +31,79 @@ namespace rx { -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() - : swizzleRed(GL_INVALID_INDEX), - swizzleGreen(GL_INVALID_INDEX), - swizzleBlue(GL_INVALID_INDEX), - swizzleAlpha(GL_INVALID_INDEX) +namespace { + +void InvalidateRenderTarget(const gl::Context *context, RenderTarget11 *renderTarget) +{ + if (renderTarget) + { + renderTarget->signalDirty(context); + } } -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) - : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +RenderTarget11 *GetRenderTarget(std::unique_ptr *pointer) { + return pointer->get(); } -bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +template +RenderTarget11 *GetRenderTarget(std::pair> *pair) { - return swizzleRed == other.swizzleRed && - swizzleGreen == other.swizzleGreen && - swizzleBlue == other.swizzleBlue && - swizzleAlpha == other.swizzleAlpha; + return pair->second.get(); } -bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +template +void InvalidateRenderTargetContainer(const gl::Context *context, T *renderTargetContainer) { - return !(*this == other); + for (auto &rt : *renderTargetContainer) + { + InvalidateRenderTarget(context, GetRenderTarget(&rt)); + } } -TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) - : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +} // anonymous namespace + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle), dropStencil(dropStencil) { } bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const { - return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); + return std::tie(baseLevel, mipLevels, swizzle, dropStencil) < + std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle, rhs.dropStencil); } -TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags) +TextureStorage11::TextureStorage11(Renderer11 *renderer, + UINT bindFlags, + UINT miscFlags, + GLenum internalFormat) : mRenderer(renderer), mTopLevel(0), mMipLevels(0), - mInternalFormat(GL_NONE), - mTextureFormat(DXGI_FORMAT_UNKNOWN), - mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), - mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), - mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mFormatInfo(d3d11::Format::Get(internalFormat, mRenderer->getRenderer11DeviceCaps())), mTextureWidth(0), mTextureHeight(0), mTextureDepth(0), + mDropStencilTexture(), mBindFlags(bindFlags), mMiscFlags(miscFlags) { - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mLevelSRVs[i] = nullptr; - } } TextureStorage11::~TextureStorage11() { - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mLevelSRVs[level]); - } - - for (SRVCache::iterator i = mSrvCache.begin(); i != mSrvCache.end(); i++) - { - SafeRelease(i->second); - } mSrvCache.clear(); } -DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget) +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + bool renderTarget) { UINT bindFlags = 0; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) { bindFlags |= D3D11_BIND_SHADER_RESOURCE; @@ -121,16 +120,17 @@ DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Rendere return bindFlags; } -DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels) +DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, + const Renderer11DeviceCaps &renderer11DeviceCaps, + bool renderTarget, + int levels) { UINT miscFlags = 0; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (renderTarget && levels > 1) { - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat); - - if (dxgiFormatInfo.nativeMipmapSupport(renderer11DeviceCaps.featureLevel)) + if (d3d11::SupportsMipGen(formatInfo.texFormat, renderer11DeviceCaps.featureLevel)) { miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; } @@ -151,6 +151,8 @@ UINT TextureStorage11::getMiscFlags() const int TextureStorage11::getTopLevel() const { + // Applying top level is meant to be encapsulated inside TextureStorage11. + UNREACHABLE(); return mTopLevel; } @@ -189,24 +191,35 @@ int TextureStorage11::getLevelDepth(int mipLevel) const return std::max(static_cast(mTextureDepth) >> mipLevel, 1); } +gl::Error TextureStorage11::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + return getResource(context, outResource); +} + UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const { - UINT mipSlice = static_cast(index.mipIndex + mTopLevel); - UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits::max()); return subresource; } -gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState, - ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) { - bool swizzleRequired = textureState.swizzleRequired(); - bool mipmapping = gl::IsMipmapFiltered(textureState.samplerState); - unsigned int mipLevels = mipmapping ? (textureState.maxLevel - textureState.baseLevel + 1) : 1; + // Make sure to add the level offset for our tiny compressed texture workaround + const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel(); + bool swizzleRequired = textureState.swizzleRequired(); + bool mipmapping = gl::IsMipmapFiltered(textureState.getSamplerState()); + unsigned int mipLevels = + mipmapping ? (textureState.getEffectiveMaxLevel() - effectiveBaseLevel + 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 - textureState.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 - effectiveBaseLevel); if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { @@ -217,89 +230,133 @@ gl::Error TextureStorage11::getSRV(const gl::TextureState &textureState, 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; - } + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } if (swizzleRequired) { - verifySwizzleExists(textureState.swizzleRed, textureState.swizzleGreen, - textureState.swizzleBlue, textureState.swizzleAlpha); + verifySwizzleExists(textureState.getSwizzleState()); + } + + // We drop the stencil when sampling from the SRV if three conditions hold: + // 1. the drop stencil workaround is enabled. + bool workaround = mRenderer->getWorkarounds().emulateTinyStencilTextures; + // 2. this is a stencil texture. + bool hasStencil = (mFormatInfo.format().stencilBits > 0); + // 3. the texture has a 1x1 or 2x2 mip. + int effectiveTopLevel = effectiveBaseLevel + mipLevels - 1; + bool hasSmallMips = + (getLevelWidth(effectiveTopLevel) <= 2 || getLevelHeight(effectiveTopLevel) <= 2); + + bool useDropStencil = (workaround && hasStencil && hasSmallMips); + SRVKey key(effectiveBaseLevel, mipLevels, swizzleRequired, useDropStencil); + if (useDropStencil) + { + // Ensure drop texture gets created. + DropStencil result = DropStencil::CREATED; + ANGLE_TRY_RESULT(ensureDropStencilTexture(context), result); + + // Clear the SRV cache if necessary. + // TODO(jmadill): Re-use find query result. + auto srvEntry = mSrvCache.find(key); + if (result == DropStencil::CREATED && srvEntry != mSrvCache.end()) + { + mSrvCache.erase(key); + } } - SRVKey key(textureState.baseLevel, mipLevels, swizzleRequired); + ANGLE_TRY(getCachedOrCreateSRV(context, key, outSRV)); + + return gl::NoError(); +} + +gl::Error TextureStorage11::getCachedOrCreateSRV(const gl::Context *context, + const SRVKey &key, + const d3d11::SharedSRV **outSRV) +{ auto iter = mSrvCache.find(key); if (iter != mSrvCache.end()) { - *outSRV = iter->second; - return gl::Error(GL_NO_ERROR); + *outSRV = &iter->second; + return gl::NoError(); } - ID3D11Resource *texture = nullptr; - if (swizzleRequired) + const TextureHelper11 *texture = nullptr; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + + if (key.swizzle) { - gl::Error error = getSwizzleTexture(&texture); - if (error.isError()) - { - return error; - } + const auto &swizzleFormat = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); + ASSERT(!key.dropStencil || swizzleFormat.format().stencilBits == 0); + ANGLE_TRY(getSwizzleTexture(&texture)); + format = swizzleFormat.srvFormat; } - else + else if (key.dropStencil) { - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + ASSERT(mDropStencilTexture.valid()); + texture = &mDropStencilTexture; + format = DXGI_FORMAT_R32_FLOAT; } - - ID3D11ShaderResourceView *srv = nullptr; - DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); - gl::Error error = createSRV(textureState.baseLevel, mipLevels, format, texture, &srv); - if (error.isError()) + else { - return error; + ANGLE_TRY(getResource(context, &texture)); + format = mFormatInfo.srvFormat; } - mSrvCache.insert(std::make_pair(key, srv)); - *outSRV = srv; + d3d11::SharedSRV srv; + + ANGLE_TRY(createSRV(context, key.baseLevel, key.mipLevels, format, *texture, &srv)); - return gl::Error(GL_NO_ERROR); + const auto &insertIt = mSrvCache.insert(std::make_pair(key, std::move(srv))); + *outSRV = &insertIt.first->second; + + return gl::NoError(); } -gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRVLevel(const gl::Context *context, + int mipLevel, + bool blitSRV, + const d3d11::SharedSRV **outSRV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - if (!mLevelSRVs[mipLevel]) + auto &levelSRVs = (blitSRV) ? mLevelBlitSRVs : mLevelSRVs; + auto &otherLevelSRVs = (blitSRV) ? mLevelSRVs : mLevelBlitSRVs; + + if (!levelSRVs[mipLevel].valid()) { - ID3D11Resource *resource = NULL; - gl::Error error = getResource(&resource); - if (error.isError()) + // Only create a different SRV for blit if blit format is different from regular srv format + if (otherLevelSRVs[mipLevel].valid() && mFormatInfo.srvFormat == mFormatInfo.blitSRVFormat) { - return error; + levelSRVs[mipLevel] = otherLevelSRVs[mipLevel].makeCopy(); } - - error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); - if (error.isError()) + else { - return error; + const TextureHelper11 *resource = nullptr; + ANGLE_TRY(getResource(context, &resource)); + + DXGI_FORMAT resourceFormat = + blitSRV ? mFormatInfo.blitSRVFormat : mFormatInfo.srvFormat; + ANGLE_TRY( + createSRV(context, mipLevel, 1, resourceFormat, *resource, &levelSRVs[mipLevel])); } } - *outSRV = mLevelSRVs[mipLevel]; + *outSRV = &levelSRVs[mipLevel]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11::getSRVLevels(const gl::Context *context, + GLint baseLevel, + GLint maxLevel, + const d3d11::SharedSRV **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) + // 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) @@ -310,245 +367,218 @@ gl::Error TextureStorage11::getSRVLevels(GLint baseLevel, GLint maxLevel, ID3D11 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); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } - ID3D11Resource *texture = nullptr; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + // TODO(jmadill): Assert we don't need to drop stencil. - ID3D11ShaderResourceView *srv = nullptr; - error = createSRV(baseLevel, mipLevels, mShaderResourceFormat, texture, &srv); - if (error.isError()) - { - return error; - } + SRVKey key(baseLevel, mipLevels, false, false); + ANGLE_TRY(getCachedOrCreateSRV(context, key, outSRV)); - mSrvCache[key] = srv; - *outSRV = srv; + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +const d3d11::Format &TextureStorage11::getFormatSet() const +{ + return mFormatInfo; } -gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +gl::Error TextureStorage11::generateSwizzles(const gl::Context *context, + const gl::SwizzleState &swizzleTarget) { - SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); for (int level = 0; level < getLevelCount(); level++) { // Check if the swizzle for this level is out of date if (mSwizzleCache[level] != swizzleTarget) { // Need to re-render the swizzle for this level - ID3D11ShaderResourceView *sourceSRV = NULL; - gl::Error error = getSRVLevel(level, &sourceSRV); - if (error.isError()) - { - return error; - } + const d3d11::SharedSRV *sourceSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &sourceSRV)); - ID3D11RenderTargetView *destRTV = NULL; - error = getSwizzleRenderTarget(level, &destRTV); - if (error.isError()) - { - return error; - } + const d3d11::RenderTargetView *destRTV; + ANGLE_TRY(getSwizzleRenderTarget(level, &destRTV)); gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); Blit11 *blitter = mRenderer->getBlitter(); - error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); - if (error.isError()) - { - return error; - } + ANGLE_TRY(blitter->swizzleTexture(context, *sourceSRV, *destRTV, size, swizzleTarget)); mSwizzleCache[level] = swizzleTarget; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +void TextureStorage11::markLevelDirty(int mipLevel) { - if (mipLevel >= 0 && static_cast(mipLevel) < ArraySize(mSwizzleCache)) + if (mipLevel >= 0 && static_cast(mipLevel) < mSwizzleCache.size()) + { + // The default constructor of SwizzleState has GL_INVALID_INDEX for all channels which is + // not a valid swizzle combination + if (mSwizzleCache[mipLevel] != gl::SwizzleState()) + { + // TODO(jmadill): Invalidate specific swizzle. + mRenderer->getStateManager()->invalidateSwizzles(); + mSwizzleCache[mipLevel] = gl::SwizzleState(); + } + } + + if (mDropStencilTexture.valid()) { - // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a - // valid swizzle combination - mSwizzleCache[mipLevel] = SwizzleCacheValue(); + mDropStencilTexture.reset(); } } -void TextureStorage11::invalidateSwizzleCache() +void TextureStorage11::markDirty() { - for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + for (size_t mipLevel = 0; mipLevel < mSwizzleCache.size(); ++mipLevel) { - invalidateSwizzleCacheLevel(mipLevel); + markLevelDirty(static_cast(mipLevel)); } } -gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, - const gl::ImageIndex &index, const gl::Box ©Area) +gl::Error TextureStorage11::updateSubresourceLevel(const gl::Context *context, + const TextureHelper11 &srcTexture, + unsigned int sourceSubresource, + const gl::ImageIndex &index, + const gl::Box ©Area) { - ASSERT(srcTexture); + ASSERT(srcTexture.valid()); - GLint level = index.mipIndex; + const GLint level = index.mipIndex; - invalidateSwizzleCacheLevel(level); + markLevelDirty(level); gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); - bool fullCopy = copyArea.x == 0 && - copyArea.y == 0 && - copyArea.z == 0 && - copyArea.width == texSize.width && - copyArea.height == texSize.height && - copyArea.depth == texSize.depth; + bool fullCopy = copyArea.x == 0 && copyArea.y == 0 && copyArea.z == 0 && + copyArea.width == texSize.width && copyArea.height == texSize.height && + copyArea.depth == texSize.depth; - ID3D11Resource *dstTexture = NULL; - gl::Error error(GL_NO_ERROR); + const TextureHelper11 *dstTexture = nullptr; - // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should - // update the mipmapped texture, even if mapmaps are currently disabled. + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we + // should update the mipmapped texture, even if mapmaps are currently disabled. if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - error = getMippedResource(&dstTexture); + ANGLE_TRY(getMippedResource(context, &dstTexture)); } else { - error = getResource(&dstTexture); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(getResource(context, &dstTexture)); } unsigned int dstSubresource = getSubresourceIndex(index); - ASSERT(dstTexture); + ASSERT(dstTexture->valid()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) + const d3d11::DXGIFormatSize &dxgiFormatSizeInfo = + d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat); + if (!fullCopy && mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead - Blit11 *blitter = mRenderer->getBlitter(); - + Blit11 *blitter = mRenderer->getBlitter(); return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, - dstTexture, dstSubresource, copyArea, texSize, - NULL); + *dstTexture, dstSubresource, copyArea, texSize, nullptr); } - else - { - D3D11_BOX srcBox; - srcBox.left = copyArea.x; - srcBox.top = copyArea.y; - srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatInfo.blockWidth); - srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatInfo.blockHeight); - srcBox.front = copyArea.z; - srcBox.back = copyArea.z + copyArea.depth; - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = + copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatSizeInfo.blockWidth); + srcBox.bottom = + copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatSizeInfo.blockHeight); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, - srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); - return gl::Error(GL_NO_ERROR); - } + deviceContext->CopySubresourceRegion(dstTexture->get(), dstSubresource, copyArea.x, copyArea.y, + copyArea.z, srcTexture.get(), sourceSubresource, + fullCopy ? nullptr : &srcBox); + return gl::NoError(); } -gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error TextureStorage11::copySubresourceLevel(const gl::Context *context, + const TextureHelper11 &dstTexture, + unsigned int dstSubresource, + const gl::ImageIndex &index, + const gl::Box ®ion) { - ASSERT(dstTexture); + ASSERT(dstTexture.valid()); - ID3D11Resource *srcTexture = NULL; - gl::Error error(GL_NO_ERROR); + const TextureHelper11 *srcTexture = nullptr; - // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should - // update the mipmapped texture, even if mapmaps are currently disabled. + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we + // should update the mipmapped texture, even if mapmaps are currently disabled. if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - error = getMippedResource(&srcTexture); + ANGLE_TRY(getMippedResource(context, &srcTexture)); } else { - error = getResource(&srcTexture); - } - - if (error.isError()) - { - return error; + ANGLE_TRY(getResource(context, &srcTexture)); } - ASSERT(srcTexture); + ASSERT(srcTexture->valid()); unsigned int srcSubresource = getSubresourceIndex(index); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL. + // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox + // should be nullptr. D3D11_BOX srcBox; - D3D11_BOX *pSrcBox = NULL; + D3D11_BOX *pSrcBox = nullptr; 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 - // textures on 9_3. - ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).depthBits == 0); - ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).stencilBits == 0); - srcBox.left = region.x; - srcBox.right = region.x + region.width; - srcBox.top = region.y; - srcBox.bottom = region.y + region.height; - srcBox.front = region.z; - srcBox.back = region.z + region.depth; - pSrcBox = &srcBox; + GLsizei width = region.width; + GLsizei height = region.height; + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, nullptr); + + // Keep srcbox as nullptr if we're dealing with tiny mips of compressed textures. + if (width == region.width && height == region.height) + { + // 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 textures on 9_3. + ASSERT(mFormatInfo.dsvFormat == DXGI_FORMAT_UNKNOWN); + srcBox.left = region.x; + srcBox.right = region.x + region.width; + srcBox.top = region.y; + srcBox.bottom = region.y + region.height; + srcBox.front = region.z; + srcBox.back = region.z + region.depth; + pSrcBox = &srcBox; + } } - context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, - srcTexture, srcSubresource, pSrcBox); + deviceContext->CopySubresourceRegion(dstTexture.get(), dstSubresource, region.x, region.y, + region.z, srcTexture->get(), srcSubresource, pSrcBox); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage11::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); - invalidateSwizzleCacheLevel(destIndex.mipIndex); + markLevelDirty(destIndex.mipIndex); - RenderTargetD3D *source = NULL; - gl::Error error = getRenderTarget(sourceIndex, &source); - if (error.isError()) - { - return error; - } + RenderTargetD3D *source = nullptr; + ANGLE_TRY(getRenderTarget(context, sourceIndex, &source)); - RenderTargetD3D *dest = NULL; - error = getRenderTarget(destIndex, &dest); - if (error.isError()) - { - return error; - } + RenderTargetD3D *dest = nullptr; + ANGLE_TRY(getRenderTarget(context, destIndex, &dest)); - ID3D11ShaderResourceView *sourceSRV = GetAs(source)->getShaderResourceView(); - ID3D11RenderTargetView *destRTV = GetAs(dest)->getRenderTargetView(); + RenderTarget11 *rt11 = GetAs(source); + const d3d11::SharedSRV &sourceSRV = rt11->getBlitShaderResourceView(); + const d3d11::RenderTargetView &destRTV = rt11->getRenderTargetView(); gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); @@ -557,90 +587,75 @@ 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, false); + GLenum format = gl::GetUnsizedFormat(source->getInternalFormat()); + return blitter->copyTexture(context, sourceSRV, sourceArea, sourceSize, format, destRTV, + destArea, destSize, nullptr, format, GL_LINEAR, false, false, + false); } -void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +void TextureStorage11::verifySwizzleExists(const gl::SwizzleState &swizzleState) { - SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); for (unsigned int level = 0; level < mMipLevels; level++) { - ASSERT(mSwizzleCache[level] == swizzleTarget); + ASSERT(mSwizzleCache[level] == swizzleState); } } 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++; - } - } + markDirty(); + mSrvCache.clear(); - for (size_t level = 0; level < ArraySize(mLevelSRVs); level++) + for (size_t level = 0; level < mLevelSRVs.size(); level++) { - SafeRelease(mLevelSRVs[level]); + mLevelSRVs[level].reset(); + mLevelBlitSRVs[level].reset(); } } -gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - TextureStorage11 *dest11 = GetAs(destStorage); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + TextureStorage11 *dest11 = GetAs(destStorage); + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +gl::Error TextureStorage11::setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) { ASSERT(!image->isDirty()); - ID3D11Resource *resource = NULL; - gl::Error error = getResource(&resource); - if (error.isError()) - { - return error; - } - ASSERT(resource); + markLevelDirty(index.mipIndex); + + const TextureHelper11 *resource = nullptr; + ANGLE_TRY(getResource(context, &resource)); + ASSERT(resource && resource->valid()); UINT destSubresource = getSubresourceIndex(index); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(image->getInternalFormat(), type); - gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), getLevelDepth(index.mipIndex)); - bool fullUpdate = (destBox == NULL || *destBox == levelBox); + gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), + getLevelDepth(index.mipIndex)); + bool fullUpdate = (destBox == nullptr || *destBox == levelBox); ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); // TODO(jmadill): Handle compressed formats @@ -649,36 +664,44 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image // with compressed formats in the calling logic. ASSERT(!internalFormatInfo.compressed); - int width = destBox ? destBox->width : static_cast(image->getWidth()); - 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, unpack.imageHeight); - GLsizei srcSkipBytes = internalFormatInfo.computeSkipPixels( - srcRowPitch, srcDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels); - - const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); - - size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + const int imageWidth = static_cast(image->getWidth()); + const int width = destBox ? destBox->width : imageWidth; + const int imageHeight = static_cast(image->getHeight()); + const int height = destBox ? destBox->height : imageHeight; + const int imageDepth = static_cast(image->getDepth()); + const int depth = destBox ? destBox->depth : imageDepth; + if (imageWidth < width || imageHeight < height || imageDepth < depth) + fullUpdate = true; + GLuint srcRowPitch = 0; + ANGLE_TRY_RESULT( + internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength), + srcRowPitch); + GLuint srcDepthPitch = 0; + ANGLE_TRY_RESULT(internalFormatInfo.computeDepthPitch(height, unpack.imageHeight, srcRowPitch), + srcDepthPitch); + GLuint srcSkipBytes = 0; + ANGLE_TRY_RESULT( + internalFormatInfo.computeSkipBytes(srcRowPitch, srcDepthPitch, unpack, index.is3D()), + srcSkipBytes); + + const d3d11::Format &d3d11Format = + d3d11::Format::Get(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps()); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(d3d11Format.texFormat); + + const size_t outputPixelSize = dxgiFormatInfo.pixelBytes; UINT bufferRowPitch = static_cast(outputPixelSize) * width; UINT bufferDepthPitch = bufferRowPitch * height; - size_t neededSize = bufferDepthPitch * depth; - MemoryBuffer *conversionBuffer = nullptr; + const size_t neededSize = bufferDepthPitch * depth; + angle::MemoryBuffer *conversionBuffer = nullptr; const uint8_t *data = nullptr; - d3d11::LoadImageFunctionInfo loadFunctionInfo = d3d11Format.loadFunctions.at(type); + LoadImageFunctionInfo loadFunctionInfo = d3d11Format.getLoadFunctions()(type); if (loadFunctionInfo.requiresConversion) { - error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer)); loadFunctionInfo.loadFunction(width, height, depth, pixelData + srcSkipBytes, srcRowPitch, srcDepthPitch, conversionBuffer->data(), bufferRowPitch, bufferDepthPitch); @@ -698,264 +721,233 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image ASSERT(destBox); D3D11_BOX destD3DBox; - destD3DBox.left = destBox->x; - destD3DBox.right = destBox->x + destBox->width; - destD3DBox.top = destBox->y; + destD3DBox.left = destBox->x; + destD3DBox.right = destBox->x + destBox->width; + destD3DBox.top = destBox->y; destD3DBox.bottom = destBox->y + destBox->height; - destD3DBox.front = destBox->z; - destD3DBox.back = destBox->z + destBox->depth; + destD3DBox.front = destBox->z; + destD3DBox.back = destBox->z + destBox->depth; - immediateContext->UpdateSubresource(resource, destSubresource, &destD3DBox, data, + immediateContext->UpdateSubresource(resource->get(), destSubresource, &destD3DBox, data, bufferRowPitch, bufferDepthPitch); } else { - immediateContext->UpdateSubresource(resource, destSubresource, NULL, data, bufferRowPitch, - bufferDepthPitch); + immediateContext->UpdateSubresource(resource->get(), destSubresource, nullptr, data, + bufferRowPitch, bufferDepthPitch); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::ErrorOrResult TextureStorage11::ensureDropStencilTexture( + const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "Drop stencil texture not implemented."; } TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) - : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0), + : TextureStorage11(renderer, + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, + 0, + swapchain->getRenderTargetInternalFormat()), mTexture(swapchain->getOffscreenTexture()), - mLevelZeroTexture(NULL), - mLevelZeroRenderTarget(NULL), + mLevelZeroTexture(), + mLevelZeroRenderTarget(nullptr), mUseLevelZeroTexture(false), - mSwizzleTexture(NULL) + mSwizzleTexture() { - mTexture->AddRef(); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + mAssociatedImages[i] = nullptr; + mRenderTarget[i] = nullptr; } D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); - mMipLevels = texDesc.MipLevels; - mTextureFormat = texDesc.Format; - mTextureWidth = texDesc.Width; + mTexture.getDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureWidth = texDesc.Width; mTextureHeight = texDesc.Height; - mTextureDepth = 1; - - mInternalFormat = swapchain->GetRenderTargetInternalFormat(); - - ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srv->GetDesc(&srvDesc); - mShaderResourceFormat = srvDesc.Format; - - ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - offscreenRTV->GetDesc(&rtvDesc); - mRenderTargetFormat = rtvDesc.Format; - - 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; - - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)), - mTexture(NULL), - mLevelZeroTexture(NULL), - mLevelZeroRenderTarget(NULL), - mUseLevelZeroTexture(false), - mSwizzleTexture(NULL) + mTextureDepth = 1; + mHasKeyedMutex = (texDesc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat), + mTexture(), + mHasKeyedMutex(false), + mLevelZeroTexture(), + mLevelZeroRenderTarget(nullptr), + mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), + mSwizzleTexture() { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + mAssociatedImages[i] = nullptr; + mRenderTarget[i] = nullptr; } - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = 1; + mTextureDepth = 1; - if (hintLevelZeroOnly && levels > 1) - { - //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. - ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); - mUseLevelZeroTexture = true; - } + // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(!mUseLevelZeroTexture || mRenderer->getWorkarounds().zeroMaxLodWorkaround); } -TextureStorage11_2D::~TextureStorage11_2D() +gl::Error TextureStorage11_2D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mAssociatedImages[i] != NULL) + if (mAssociatedImages[i] != nullptr) { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + mAssociatedImages[i]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - gl::Error error = mAssociatedImages[i]->recoverFromAssociatedStorage(); - if (error.isError()) - { - // TODO: Find a way to report this back to the context - } - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - SafeRelease(mLevelZeroTexture); - SafeDelete(mLevelZeroRenderTarget); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + if (mHasKeyedMutex) { - SafeDelete(mRenderTarget[i]); - SafeRelease(mSwizzleRenderTargets[i]); + // If the keyed mutex is released that will unbind it and cause the state cache to become + // desynchronized. + mRenderer->getStateManager()->invalidateBoundViews(); } + + // Invalidate RenderTargets. + InvalidateRenderTargetContainer(context, &mRenderTarget); + InvalidateRenderTarget(context, mLevelZeroRenderTarget.get()); + + return gl::NoError(); +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ } -gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11_2D::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); - TextureStorage11_2D *dest11 = GetAs(destStorage); + TextureStorage11_2D *dest11 = GetAs(destStorage); + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - - // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. - if (mTexture) + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the + // corresponding textures in destStorage. + if (mTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mTexture); + immediateContext->CopyResource(destResource->get(), mTexture.get()); } - if (mLevelZeroTexture) + if (mLevelZeroTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mLevelZeroTexture); + immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } + + return gl::NoError(); } - else - { - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - dest11->invalidateSwizzleCache(); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) { + bool lastSetting = mUseLevelZeroTexture; + if (useLevelZeroTexture && mMipLevels > 1) { - if (!mUseLevelZeroTexture && mTexture) + if (!mUseLevelZeroTexture && mTexture.valid()) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); // Pull data back from the mipped texture if necessary. - ASSERT(mLevelZeroTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(mLevelZeroTexture, 0, 0, 0, 0, mTexture, 0, NULL); + ASSERT(mLevelZeroTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), 0, 0, 0, 0, + mTexture.get(), 0, nullptr); } mUseLevelZeroTexture = true; } else { - if (mUseLevelZeroTexture && mLevelZeroTexture) + if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); // Pull data back from the level zero texture if necessary. - ASSERT(mTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(mTexture, 0, 0, 0, 0, mLevelZeroTexture, 0, NULL); + ASSERT(mTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mTexture.get(), 0, 0, 0, 0, + mLevelZeroTexture.get(), 0, nullptr); } mUseLevelZeroTexture = false; } - return gl::Error(GL_NO_ERROR); + if (lastSetting != mUseLevelZeroTexture) + { + // Mark everything as dirty to be conservative. + if (mLevelZeroRenderTarget) + { + mLevelZeroRenderTarget->signalDirty(context); + } + for (auto &renderTarget : mRenderTarget) + { + if (renderTarget) + { + renderTarget->signalDirty(context); + } + } + } + + return gl::NoError(); } -void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_2D::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); @@ -965,539 +957,569 @@ void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &i } } -bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2D::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[level] == expectedImage); - ASSERT(retValue); - return retValue; - } + const GLint level = index.mipIndex; - return false; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - ASSERT(mAssociatedImages[level] == expectedImage); - - if (mAssociatedImages[level] == expectedImage) - { - mAssociatedImages[level] = NULL; - } - } + ASSERT(mAssociatedImages[level] == expectedImage); + mAssociatedImages[level] = nullptr; } -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image +// recover its data before ending the association. +gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + if (mAssociatedImages[level] != nullptr && mAssociatedImages[level] != incomingImage) { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[level]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2D::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); - *outResource = mLevelZeroTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mLevelZeroTexture; + return gl::NoError(); } - else - { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); + + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2D::getMippedResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2D::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) { // This shouldn't be called unless the zero max LOD workaround is active. ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels) { // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. - bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; - ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround + ? (mipLevels == 1) && (mMipLevels > 1) + : false; + TextureHelper11 *outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + if (!outputTexture->valid() && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mipLevels > 0); - ID3D11Device *device = mRenderer->getDevice(); - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; // Compressed texture size constraints? - desc.Height = mTextureHeight; - desc.MipLevels = mipLevels; - desc.ArraySize = 1; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mFormatInfo.texFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(*outputTexture, "TexStorage2D.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, outputTexture)); + outputTexture->setDebugName("TexStorage2D.Texture"); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); - int level = index.mipIndex; + const int level = index.mipIndex; ASSERT(level >= 0 && level < getLevelCount()); - // In GL ES 2.0, the application can only render to level zero of the texture (Section 4.4.3 of the GLES 2.0 spec, page 113 of version 2.0.25). - // Other parts of TextureStorage11_2D could create RTVs on non-zero levels of the texture (e.g. generateMipmap). - // 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->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0)); - - if (!mRenderTarget[level]) + // In GL ES 2.0, the application can only render to level zero of the texture (Section 4.4.3 of + // the GLES 2.0 spec, page 113 of version 2.0.25). Other parts of TextureStorage11_2D could + // create RTVs on non-zero levels of the texture (e.g. generateMipmap). + // 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->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0)); + ASSERT(outRT); + if (mRenderTarget[level]) { - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - ID3D11ShaderResourceView *srv = NULL; - error = getSRVLevel(level, &srv); - if (error.isError()) - { - return error; - } + *outRT = mRenderTarget[level].get(); + return gl::NoError(); + } - if (mUseLevelZeroTexture) - { - if (!mLevelZeroRenderTarget) - { - ID3D11Device *device = mRenderer->getDevice(); + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(index.mipIndex == 0); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); + } - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, level, false, &srv)); - if (result == E_OUTOFMEMORY) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - ASSERT(SUCCEEDED(result)); + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); - mLevelZeroRenderTarget = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mLevelZeroTexture.get(), &rtv)); - ASSERT(outRT); - *outRT = mLevelZeroRenderTarget; - return gl::Error(GL_NO_ERROR); + mLevelZeroRenderTarget.reset(new TextureRenderTarget11( + std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), + mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), + getLevelHeight(level), 1, 0)); } - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); + *outRT = mLevelZeroRenderTarget.get(); + return gl::NoError(); + } - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } + mRenderTarget[level].reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); - mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + *outRT = mRenderTarget[level].get(); + return gl::NoError(); + } - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mTopLevel + level; - dsvDesc.Flags = 0; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; - ID3D11DepthStencilView *dsv; - HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY,"Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); - } + mRenderTarget[level].reset(new TextureRenderTarget11( + std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); - mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + *outRT = mRenderTarget[level].get(); + return gl::NoError(); +} - // RenderTarget will take ownership of these resources - SafeRelease(dsv); - } - else - { - UNREACHABLE(); - } - } - - ASSERT(outRT); - *outRT = mRenderTarget[level]; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_2D::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2D.MipLevels = mipLevels; + srvDesc.Texture2D.MipLevels = mipLevels; - ID3D11Resource *srvTexture = texture; + const TextureHelper11 *srvTexture = &texture; if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) { ASSERT(mTopLevel == 0); ASSERT(baseLevel == 0); - // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + // This code also assumes that the incoming texture equals either mLevelZeroTexture or + // mTexture. if (mipLevels == 1 && mMipLevels > 1) { // We must use a SRV on the level-zero-only texture. - ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); - srvTexture = mLevelZeroTexture; + ANGLE_TRY(ensureTextureExists(1)); + srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); - ASSERT(mTexture != NULL && texture == mTexture); - srvTexture = mTexture; + ASSERT(mTexture.valid() && texture == mTexture); + srvTexture = &mTexture; } } - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(srvTexture, &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, "TexStorage2D.SRV"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, srvTexture->get(), outSRV)); + outSRV->setDebugName("TexStorage2D.SRV"); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_2D::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = 1; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = format.texFormat; + 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - d3d11::SetDebugName(mSwizzleTexture, "TexStorage2D.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage2D.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + 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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -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) +gl::ErrorOrResult TextureStorage11_2D::ensureDropStencilTexture( + const gl::Context *context) { - 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 + if (mDropStencilTexture.valid()) { - mRenderTargetFormat = DXGI_FORMAT_UNKNOWN; + return DropStencil::ALREADY_EXISTS; } - ID3D11DepthStencilView *dsv = renderTarget11->getDepthStencilView(); - if (dsv != nullptr) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsv->GetDesc(&dsvDesc); - mDepthStencilFormat = dsvDesc.Format; - } - else - { - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; - } + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = 1; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = 0; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; + + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorage2D.DropStencil"); + + ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::Make2D(0, mMipLevels))); - 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; + return DropStencil::CREATED; } -TextureStorage11_EGLImage::~TextureStorage11_EGLImage() +TextureStorage11_External::TextureStorage11_External( + Renderer11 *renderer, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &glDesc) + : TextureStorage11(renderer, D3D11_BIND_SHADER_RESOURCE, 0, glDesc.internalFormat) { - SafeRelease(mSwizzleTexture); - for (size_t i = 0; i < mSwizzleRenderTargets.size(); i++) - { - SafeRelease(mSwizzleRenderTargets[i]); - } + ASSERT(stream->getProducerType() == egl::Stream::ProducerType::D3D11TextureNV12); + StreamProducerNV12 *producer = static_cast(stream->getImplementation()); + mTexture.set(producer->getD3DTexture(), mFormatInfo); + mSubresourceIndex = producer->getArraySlice(); + mTexture.get()->AddRef(); + mMipLevels = 1; + + D3D11_TEXTURE2D_DESC desc; + mTexture.getDesc(&desc); + mTextureWidth = desc.Width; + mTextureHeight = desc.Height; + mTextureDepth = 1; + mHasKeyedMutex = (desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; } -gl::Error TextureStorage11_EGLImage::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_External::onDestroy(const gl::Context *context) { - gl::Error error = checkForUpdatedRenderTarget(); - if (error.isError()) + if (mHasKeyedMutex) { - return error; + // If the keyed mutex is released that will unbind it and cause the state cache to become + // desynchronized. + mRenderer->getStateManager()->invalidateBoundViews(); } - RenderTarget11 *renderTarget11 = nullptr; - error = getImageRenderTarget(&renderTarget11); - if (error.isError()) - { - return error; - } + return gl::NoError(); +} + +TextureStorage11_External::~TextureStorage11_External() +{ +} + +gl::Error TextureStorage11_External::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + UNIMPLEMENTED(); + return gl::NoError(); +} + +void TextureStorage11_External::associateImage(Image11 *image, const gl::ImageIndex &index) +{ + ASSERT(index.mipIndex == 0); + mAssociatedImage = image; +} + +void TextureStorage11_External::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) +{ + ASSERT(index.mipIndex == 0 && mAssociatedImage == expectedImage); +} - *outResource = renderTarget11->getTexture(); - return gl::Error(GL_NO_ERROR); +void TextureStorage11_External::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) +{ + ASSERT(index.mipIndex == 0); + ASSERT(mAssociatedImage == expectedImage); + mAssociatedImage = nullptr; } -gl::Error TextureStorage11_EGLImage::getSRV(const gl::TextureState &textureState, - ID3D11ShaderResourceView **outSRV) +gl::Error TextureStorage11_External::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - gl::Error error = checkForUpdatedRenderTarget(); - if (error.isError()) + ASSERT(index.mipIndex == 0); + + if (mAssociatedImage != nullptr && mAssociatedImage != incomingImage) { - return error; + mAssociatedImage->verifyAssociatedStorageValid(this); + + ANGLE_TRY(mAssociatedImage->recoverFromAssociatedStorage(context)); } - return TextureStorage11::getSRV(textureState, outSRV); + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + // Render targets are not supported for external textures + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureStorage11_External::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) +{ + // Since external textures are treates as non-mipmapped textures, we ignore mipmap levels and + // use the specified subresource ID the storage was created with. + ASSERT(mipLevels == 1); + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + // subresource index is equal to the mip level for 2D textures + srvDesc.Texture2DArray.MostDetailedMip = 0; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = mSubresourceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2D.SRV"); + + return gl::NoError(); +} + +gl::Error TextureStorage11_External::getSwizzleTexture(const TextureHelper11 **outTexture) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +gl::Error TextureStorage11_External::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, + EGLImageD3D *eglImage, + RenderTarget11 *renderTarget11) + : TextureStorage11(renderer, + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, + 0, + renderTarget11->getInternalFormat()), + mImage(eglImage), + mCurrentRenderTarget(0), + mSwizzleTexture(), + mSwizzleRenderTargets(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) +{ + mCurrentRenderTarget = reinterpret_cast(renderTarget11); + + mMipLevels = 1; + mTextureWidth = renderTarget11->getWidth(); + mTextureHeight = renderTarget11->getHeight(); + mTextureDepth = 1; +} + +TextureStorage11_EGLImage::~TextureStorage11_EGLImage() +{ +} + +gl::Error TextureStorage11_EGLImage::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + ANGLE_TRY(checkForUpdatedRenderTarget(context)); + + RenderTarget11 *renderTarget11 = nullptr; + ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); + *outResource = &renderTarget11->getTexture(); + return gl::NoError(); +} + +gl::Error TextureStorage11_EGLImage::getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) +{ + ANGLE_TRY(checkForUpdatedRenderTarget(context)); + return TextureStorage11::getSRV(context, textureState, outSRV); } -gl::Error TextureStorage11_EGLImage::getMippedResource(ID3D11Resource **) +gl::Error TextureStorage11_EGLImage::getMippedResource(const gl::Context *context, + const TextureHelper11 **) { // 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); + return gl::InternalError(); } -gl::Error TextureStorage11_EGLImage::getRenderTarget(const gl::ImageIndex &index, +gl::Error TextureStorage11_EGLImage::getRenderTarget(const gl::Context *context, + 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; - } + ANGLE_TRY(checkForUpdatedRenderTarget(context)); - return mImage->getRenderTarget(outRT); + return mImage->getRenderTarget(context, outRT); } -gl::Error TextureStorage11_EGLImage::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11_EGLImage::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { - ID3D11Resource *sourceResouce = nullptr; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); ASSERT(destStorage); TextureStorage11_2D *dest11 = GetAs(destStorage); - ID3D11Resource *destResource = nullptr; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void TextureStorage11_EGLImage::associateImage(Image11 *, const gl::ImageIndex &) @@ -1508,36 +1530,37 @@ void TextureStorage11_EGLImage::disassociateImage(const gl::ImageIndex &, Image1 { } -bool TextureStorage11_EGLImage::isAssociatedImageValid(const gl::ImageIndex &, Image11 *) +void TextureStorage11_EGLImage::verifyAssociatedImageValid(const gl::ImageIndex &, Image11 *) { - return false; } -gl::Error TextureStorage11_EGLImage::releaseAssociatedImage(const gl::ImageIndex &, Image11 *) +gl::Error TextureStorage11_EGLImage::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &, + Image11 *) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(bool) +gl::Error TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(const gl::Context *context, bool) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureStorage11_EGLImage::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_EGLImage::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = 1; - desc.Format = mSwizzleTextureFormat; + desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; @@ -1545,68 +1568,43 @@ gl::Error TextureStorage11_EGLImage::getSwizzleTexture(ID3D11Resource **outTextu 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"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorageEGLImage.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } gl::Error TextureStorage11_EGLImage::getSwizzleRenderTarget(int mipLevel, - ID3D11RenderTargetView **outRTV) + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; 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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget() +gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget(const gl::Context *context) { RenderTarget11 *renderTarget11 = nullptr; - gl::Error error = getImageRenderTarget(&renderTarget11); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); if (mCurrentRenderTarget != reinterpret_cast(renderTarget11)) { @@ -1614,14 +1612,15 @@ gl::Error TextureStorage11_EGLImage::checkForUpdatedRenderTarget() mCurrentRenderTarget = reinterpret_cast(renderTarget11); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::createSRV(int baseLevel, +gl::Error TextureStorage11_EGLImage::createSRV(const gl::Context *context, + int baseLevel, int mipLevels, DXGI_FORMAT format, - ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(baseLevel == 0); ASSERT(mipLevels == 1); @@ -1637,163 +1636,129 @@ gl::Error TextureStorage11_EGLImage::createSRV(int baseLevel, 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"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorageEGLImage.SRV"); } else { RenderTarget11 *renderTarget = nullptr; - gl::Error error = getImageRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getImageRenderTarget(context, &renderTarget)); ASSERT(texture == renderTarget->getTexture()); - *outSRV = renderTarget->getShaderResourceView(); - (*outSRV)->AddRef(); + *outSRV = renderTarget->getShaderResourceView().makeCopy(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_EGLImage::getImageRenderTarget(RenderTarget11 **outRT) const +gl::Error TextureStorage11_EGLImage::getImageRenderTarget(const gl::Context *context, + RenderTarget11 **outRT) const { RenderTargetD3D *renderTargetD3D = nullptr; - gl::Error error = mImage->getRenderTarget(&renderTargetD3D); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); *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->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) + return gl::NoError(); +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat), + mTexture(), + mLevelZeroTexture(), + mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), + mSwizzleTexture() { - mTexture = NULL; - mSwizzleTexture = NULL; - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - mSwizzleRenderTargets[level] = NULL; - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - mAssociatedImages[face][level] = NULL; - mRenderTarget[face][level] = NULL; + mAssociatedImages[face][level] = nullptr; + mRenderTarget[face][level] = nullptr; } } - mLevelZeroTexture = NULL; - mUseLevelZeroTexture = false; - - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - mLevelZeroRenderTarget[face] = NULL; + mLevelZeroRenderTarget[face] = nullptr; } - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // adjust size if needed for compressed textures int height = size; - d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &size, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = size; + mMipLevels = mTopLevel + levels; + mTextureWidth = size; mTextureHeight = size; - mTextureDepth = 1; + mTextureDepth = 1; - if (hintLevelZeroOnly && levels > 1) - { - //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. - ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); - mUseLevelZeroTexture = true; - } + // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(!mUseLevelZeroTexture || mRenderer->getWorkarounds().zeroMaxLodWorkaround); } -TextureStorage11_Cube::~TextureStorage11_Cube() +gl::Error TextureStorage11_Cube::onDestroy(const gl::Context *context) { for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (unsigned int face = 0; face < gl::CUBE_FACE_COUNT; face++) { - if (mAssociatedImages[face][level] != NULL) + if (mAssociatedImages[face][level] != nullptr) { - bool imageAssociationCorrect = mAssociatedImages[face][level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[face][level]->recoverFromAssociatedStorage(); - } + mAssociatedImages[face][level]->verifyAssociatedStorageValid(this); + + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[face][level]->recoverFromAssociatedStorage(context)); } } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - SafeRelease(mLevelZeroTexture); - - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + for (auto &faceRenderTargets : mRenderTarget) { - SafeDelete(mLevelZeroRenderTarget[face]); + InvalidateRenderTargetContainer(context, &faceRenderTargets); } + InvalidateRenderTargetContainer(context, &mLevelZeroRenderTarget); - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mSwizzleRenderTargets[level]); - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) - { - SafeDelete(mRenderTarget[face][level]); - } - } + return gl::NoError(); +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ } UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const { - if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0) + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && + index.mipIndex == 0) { - UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); UINT subresource = D3D11CalcSubresource(0, arraySlice, 1); ASSERT(subresource != std::numeric_limits::max()); return subresource; } else { - UINT mipSlice = static_cast(index.mipIndex + mTopLevel); - UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits::max()); return subresource; } } -gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage11_Cube::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); @@ -1803,87 +1768,63 @@ gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage) { ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. - if (mTexture) + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the + // corresponding textures in destStorage. + if (mTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mTexture); + immediateContext->CopyResource(destResource->get(), mTexture.get()); } - if (mLevelZeroTexture) + if (mLevelZeroTexture.valid()) { - gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); - if (error.isError()) - { - return error; - } + ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); - immediateContext->CopyResource(destResource, mLevelZeroTexture); + immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } } else { - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } + const TextureHelper11 *sourceResouce = nullptr; + ANGLE_TRY(getResource(context, &sourceResouce)); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } + const TextureHelper11 *destResource = nullptr; + ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); + immediateContext->CopyResource(destResource->get(), sourceResouce->get()); } - dest11->invalidateSwizzleCache(); + dest11->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) { if (useLevelZeroTexture && mMipLevels > 1) { - if (!mUseLevelZeroTexture && mTexture) + if (!mUseLevelZeroTexture && mTexture.valid()) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(1)); // Pull data back from the mipped texture if necessary. - ASSERT(mLevelZeroTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ASSERT(mLevelZeroTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { - context->CopySubresourceRegion(mLevelZeroTexture, D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture, face * mMipLevels, NULL); + deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), + D3D11CalcSubresource(0, face, 1), 0, 0, 0, + mTexture.get(), face * mMipLevels, nullptr); } } @@ -1891,346 +1832,286 @@ gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZero } else { - if (mUseLevelZeroTexture && mLevelZeroTexture) + if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureTextureExists(mMipLevels)); // Pull data back from the level zero texture if necessary. - ASSERT(mTexture); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + ASSERT(mTexture.valid()); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { - context->CopySubresourceRegion(mTexture, D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture, face, NULL); + deviceContext->CopySubresourceRegion(mTexture.get(), + D3D11CalcSubresource(0, face, mMipLevels), 0, + 0, 0, mLevelZeroTexture.get(), face, nullptr); } } mUseLevelZeroTexture = false; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_Cube::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + if (0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)) { mAssociatedImages[layerTarget][level] = image; } } } -bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_Cube::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); - ASSERT(retValue); - return retValue; - } - } - - return false; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); - - if (mAssociatedImages[layerTarget][level] == expectedImage) - { - mAssociatedImages[layerTarget][level] = NULL; - } - } - } + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); + mAssociatedImages[layerTarget][level] = nullptr; } -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image +// recover its data before ending the association. +gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)); if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + if (0 <= layerTarget && layerTarget < static_cast(gl::CUBE_FACE_COUNT)) { // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage) + if (mAssociatedImages[layerTarget][level] != nullptr && + mAssociatedImages[layerTarget][level] != incomingImage) { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[layerTarget][level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[layerTarget][level]->verifyAssociatedStorageValid(this); + + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY( + mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(context)); } } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_Cube::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { - gl::Error error = ensureTextureExists(1); - if (error.isError()) - { - return error; - } - - *outResource = mLevelZeroTexture; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureTextureExists(1)); + *outResource = &mLevelZeroTexture; + return gl::NoError(); } else { - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureTextureExists(mMipLevels)); + *outResource = &mTexture; + return gl::NoError(); } } -gl::Error TextureStorage11_Cube::getMippedResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_Cube::getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) { // This shouldn't be called unless the zero max LOD workaround is active. ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); - gl::Error error = ensureTextureExists(mMipLevels); - if (error.isError()) - { - return error; - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(ensureTextureExists(mMipLevels)); + *outResource = &mTexture; + return gl::NoError(); } gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels) { // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. - bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; - ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround + ? (mipLevels == 1) && (mMipLevels > 1) + : false; + TextureHelper11 *outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; // if the size is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + if (!outputTexture->valid() && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); - ID3D11Device *device = mRenderer->getDevice(); - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mipLevels; - desc.ArraySize = CUBE_FACE_COUNT; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = gl::CUBE_FACE_COUNT; + desc.Format = mFormatInfo.texFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | getMiscFlags(); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | getMiscFlags(); - HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, outputTexture)); + outputTexture->setDebugName("TexStorageCube.Texture"); + } - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); - } + return gl::NoError(); +} + +gl::Error TextureStorage11_Cube::createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = resourceFormat; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.mipIndex; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = index.layerIndex; + srvDesc.Texture2DArray.ArraySize = 1; - d3d11::SetDebugName(*outputTexture, "TexStorageCube.Texture"); + if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_10_0) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + } + else + { + // Will be used with Texture2D sampler, not TextureCube + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; } - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), srv)); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { - int faceIndex = index.layerIndex; - int level = index.mipIndex; + const int faceIndex = index.layerIndex; + const int level = index.mipIndex; ASSERT(level >= 0 && level < getLevelCount()); - ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); + ASSERT(faceIndex >= 0 && faceIndex < static_cast(gl::CUBE_FACE_COUNT)); if (!mRenderTarget[faceIndex][level]) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - return error; + ASSERT(index.mipIndex == 0); + ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); } + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + if (mUseLevelZeroTexture) { if (!mLevelZeroRenderTarget[faceIndex]) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; - rtvDesc.Texture2DArray.ArraySize = 1; + rtvDesc.Texture2DArray.ArraySize = 1; - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mLevelZeroTexture.get(), &rtv)); - if (result == E_OUTOFMEMORY) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - ASSERT(SUCCEEDED(result)); - - mLevelZeroRenderTarget[faceIndex] = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); + mLevelZeroRenderTarget[faceIndex].reset(new TextureRenderTarget11( + std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), + mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), + getLevelHeight(level), 1, 0)); } ASSERT(outRT); - *outRT = mLevelZeroRenderTarget[faceIndex]; - return gl::Error(GL_NO_ERROR); + *outRT = mLevelZeroRenderTarget[faceIndex].get(); + return gl::NoError(); } - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = faceIndex; - srvDesc.Texture2DArray.ArraySize = 1; - - if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) + d3d11::SharedSRV srv; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.srvFormat, &srv)); + d3d11::SharedSRV blitSRV; + if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } else { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + blitSRV = srv.makeCopy(); } - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + srv.setDebugName("TexStorageCube.RenderTargetSRV"); - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); - } + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; - d3d11::SetDebugName(srv, "TexStorageCube.RenderTargetSRV"); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorageCube.RenderTargetRTV"); - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); + } + else if (mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; - rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; - rtvDesc.Texture2DArray.ArraySize = 1; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + dsv.setDebugName("TexStorageCube.RenderTargetDSV"); - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - 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 - SafeRelease(rtv); - SafeRelease(srv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Flags = 0; - dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; - dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; - dsvDesc.Texture2DArray.ArraySize = 1; - - ID3D11DepthStencilView *dsv; - result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - 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 - SafeRelease(dsv); - SafeRelease(srv); + mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( + std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, 0)); } else { @@ -2239,215 +2120,237 @@ gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, Re } ASSERT(outRT); - *outRT = mRenderTarget[faceIndex][level]; - return gl::Error(GL_NO_ERROR); + *outRT = mRenderTarget[faceIndex][level].get(); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_Cube::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; - // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); - if (dxgiFormatInfo.componentType == GL_INT || dxgiFormatInfo.componentType == GL_UNSIGNED_INT) + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six + // 2D textures + const GLenum componentType = d3d11::GetComponentType(format); + if (componentType == GL_INT || componentType == GL_UNSIGNED_INT) { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + srvDesc.Texture2DArray.ArraySize = gl::CUBE_FACE_COUNT; } else { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; } - ID3D11Resource *srvTexture = texture; + const TextureHelper11 *srvTexture = &texture; if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) { ASSERT(mTopLevel == 0); ASSERT(baseLevel == 0); - // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + // This code also assumes that the incoming texture equals either mLevelZeroTexture or + // mTexture. if (mipLevels == 1 && mMipLevels > 1) { // We must use a SRV on the level-zero-only texture. - ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); - srvTexture = mLevelZeroTexture; + ANGLE_TRY(ensureTextureExists(1)); + srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); - ASSERT(mTexture != NULL && texture == mTexture); - srvTexture = mTexture; + ASSERT(mTexture.valid() && texture == mTexture); + srvTexture = &mTexture; } } - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, srvTexture->get(), outSRV)); + outSRV->setDebugName("TexStorageCube.SRV"); - 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, "TexStorageCube.SRV"); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_Cube::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = CUBE_FACE_COUNT; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = gl::CUBE_FACE_COUNT; + desc.Format = format.texFormat; + 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 = D3D11_RESOURCE_MISC_TEXTURECUBE; - - 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - d3d11::SetDebugName(*outTexture, "TexStorageCube.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorageCube.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + rtvDesc.Texture2DArray.ArraySize = gl::CUBE_FACE_COUNT; - 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); - } + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) +gl::Error TextureStorage11::initDropStencilTexture(const gl::Context *context, + const gl::ImageIndexIterator &it) { - mTexture = NULL; - mSwizzleTexture = NULL; + const TextureHelper11 *sourceTexture = nullptr; + ANGLE_TRY(getResource(context, &sourceTexture)); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + gl::ImageIndexIterator itCopy = it; + + while (itCopy.hasNext()) + { + gl::ImageIndex index = itCopy.next(); + gl::Box wholeArea(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), + 1); + gl::Extents wholeSize(wholeArea.width, wholeArea.height, 1); + UINT subresource = getSubresourceIndex(index); + ANGLE_TRY(mRenderer->getBlitter()->copyDepthStencil( + *sourceTexture, subresource, wholeArea, wholeSize, mDropStencilTexture, subresource, + wholeArea, wholeSize, nullptr)); + } + + return gl::NoError(); +} + +gl::ErrorOrResult TextureStorage11_Cube::ensureDropStencilTexture( + const gl::Context *context) +{ + if (mDropStencilTexture.valid()) { - mAssociatedImages[i] = NULL; - mLevelRenderTargets[i] = NULL; - mSwizzleRenderTargets[i] = NULL; + return DropStencil::ALREADY_EXISTS; } - mInternalFormat = internalformat; + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = 6; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorageCube.DropStencil"); + + ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::MakeCube(0, mMipLevels))); + + return DropStencil::CREATED; +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat) +{ + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = nullptr; + mLevelRenderTargets[i] = nullptr; + } // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = depth; + mTextureDepth = depth; } -TextureStorage11_3D::~TextureStorage11_3D() +gl::Error TextureStorage11_3D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mAssociatedImages[i] != NULL) + if (mAssociatedImages[i] != nullptr) { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + mAssociatedImages[i]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[i]->recoverFromAssociatedStorage(); - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); + InvalidateRenderTargetContainer(context, &mLevelRenderTargets); + InvalidateRenderTargetContainer(context, &mLevelLayerRenderTargets); - for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mLevelLayerRenderTargets.clear(); + return gl::NoError(); +} - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - SafeDelete(mLevelRenderTargets[i]); - SafeRelease(mSwizzleRenderTargets[i]); - } +TextureStorage11_3D::~TextureStorage11_3D() +{ } -void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_3D::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); @@ -2457,676 +2360,796 @@ void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &i } } -bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_3D::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[level] == expectedImage); - ASSERT(retValue); - return retValue; - } - - return false; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - ASSERT(mAssociatedImages[level] == expectedImage); - - if (mAssociatedImages[level] == expectedImage) - { - mAssociatedImages[level] = NULL; - } - } + ASSERT(mAssociatedImages[level] == expectedImage); + mAssociatedImages[level] = nullptr; } -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image +// recover its data before ending the association. +gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; + const GLint level = index.mipIndex; ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + if (mAssociatedImages[level] != nullptr && mAssociatedImages[level] != incomingImage) { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[level]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_3D::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { - // If the width, height or depth are not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + // If the width, height or depth are not positive this should be treated as an incomplete + // texture. We handle that here by skipping the d3d texture creation. + if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) { ASSERT(mMipLevels > 0); - ID3D11Device *device = mRenderer->getDevice(); - D3D11_TEXTURE3D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.Depth = mTextureDepth; - desc.MipLevels = mMipLevels; - desc.Format = mTextureFormat; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mFormatInfo.texFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); - } + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(mTexture, "TexStorage3D.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage3D.Texture"); } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_3D::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; srvDesc.Texture3D.MostDetailedMip = baseLevel; - srvDesc.Texture3D.MipLevels = mipLevels; + srvDesc.Texture3D.MipLevels = mipLevels; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage3D.SRV"); - 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, "TexStorage3D.SRV"); - - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_3D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { - int mipLevel = index.mipIndex; + const int mipLevel = index.mipIndex; ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); + ASSERT(mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); if (!index.hasLayer()) { if (!mLevelRenderTargets[mipLevel]) { - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - ID3D11ShaderResourceView *srv = NULL; - error = getSRVLevel(mipLevel, &srv); - if (error.isError()) - { - return error; - } + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, mipLevel, false, &srv)); - ID3D11Device *device = mRenderer->getDevice(); + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, mipLevel, true, &blitSRV)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = static_cast(-1); - - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - 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"); + rtvDesc.Texture3D.WSize = static_cast(-1); - mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage3D.RTV"); - // RenderTarget will take ownership of these resources - SafeRelease(rtv); + mLevelRenderTargets[mipLevel].reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, + getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), + getLevelDepth(mipLevel), 0)); } ASSERT(outRT); - *outRT = mLevelRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRT = mLevelRenderTargets[mipLevel].get(); + return gl::NoError(); } - else - { - int layer = index.layerIndex; - LevelLayerKey key(mipLevel, layer); - if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - // TODO, what kind of SRV is expected here? - ID3D11ShaderResourceView *srv = NULL; + const int layer = index.layerIndex; - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = layer; - rtvDesc.Texture3D.WSize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - ASSERT(SUCCEEDED(result)); + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); - d3d11::SetDebugName(rtv, "TexStorage3D.LayerRTV"); + // TODO, what kind of SRV is expected here? + const d3d11::SharedSRV srv; + const d3d11::SharedSRV blitSRV; - mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage3D.LayerRTV"); - ASSERT(outRT); - *outRT = mLevelLayerRenderTargets[key]; - return gl::Error(GL_NO_ERROR); + mLevelLayerRenderTargets[key].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } + + ASSERT(outRT); + *outRT = mLevelLayerRenderTargets[key].get(); + return gl::NoError(); } -gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_3D::getSwizzleTexture(const TextureHelper11 **outTexture) { ASSERT(outTexture); - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE3D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.Depth = mTextureDepth; - desc.MipLevels = mMipLevels; - desc.Format = mSwizzleTextureFormat; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = format.texFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture3D(&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); - } + desc.MiscFlags = 0; - d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage3D.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = static_cast(-1); + rtvDesc.Texture3D.WSize = static_cast(-1); - 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); - } - - d3d11::SetDebugName(mSwizzleTexture, "TexStorage3D.SwizzleRTV"); + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &mSwizzleRenderTargets[mipLevel])); + mSwizzleRenderTargets[mipLevel].setDebugName("TexStorage3D.SwizzleRTV"); } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + *outRTV = &mSwizzleRenderTargets[mipLevel]; + return gl::NoError(); } -TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, - GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), - GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels)) +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, + GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), + GetTextureMiscFlags(internalformat, + renderer->getRenderer11DeviceCaps(), + renderTarget, + levels), + internalformat) { - mTexture = NULL; - mSwizzleTexture = NULL; - - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mSwizzleRenderTargets[level] = NULL; - } - - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getRenderer11DeviceCaps()); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; + mMipLevels = mTopLevel + levels; + mTextureWidth = width; mTextureHeight = height; - mTextureDepth = depth; + mTextureDepth = depth; } -TextureStorage11_2DArray::~TextureStorage11_2DArray() +gl::Error TextureStorage11_2DArray::onDestroy(const gl::Context *context) { - for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++) + for (auto iter : mAssociatedImages) { - if (i->second) + if (iter.second) { - bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + iter.second->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - i->second->recoverFromAssociatedStorage(); - } + // We must let the Images recover their data before we delete it from the + // TextureStorage. + ANGLE_TRY(iter.second->recoverFromAssociatedStorage(context)); } } mAssociatedImages.clear(); - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); + InvalidateRenderTargetContainer(context, &mRenderTargets); - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mSwizzleRenderTargets[level]); - } + return gl::NoError(); +} - for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mRenderTargets.clear(); +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ } -void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) +void TextureStorage11_2DArray::associateImage(Image11 *image, const gl::ImageIndex &index) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; ASSERT(0 <= level && level < getLevelCount()); if (0 <= level && level < getLevelCount()) { - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); mAssociatedImages[key] = image; } } -bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2DArray::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + // This validation check should never return false. It means the Image/TextureStorage + // association is broken. + bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && + (mAssociatedImages[key] == expectedImage)); ASSERT(retValue); - return retValue; } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); - bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && + (mAssociatedImages[key] == expectedImage)); ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - mAssociatedImages[key] = NULL; - } + mAssociatedImages[key] = nullptr; } -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image +// recover its data before ending the association. +gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) { - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; + const GLint level = index.mipIndex; + const GLint layerTarget = index.layerIndex; + const GLint numLayers = index.numLayers; - LevelLayerKey key(level, layerTarget); + LevelLayerRangeKey key(level, layerTarget, numLayers); if (mAssociatedImages.find(key) != mAssociatedImages.end()) { - if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) + if (mAssociatedImages[key] != nullptr && mAssociatedImages[key] != incomingImage) { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[key]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); + // Ensure that the Image is still associated with this TextureStorage. + mAssociatedImages[key]->verifyAssociatedStorageValid(this); - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[key]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to nullptr too. + ANGLE_TRY(mAssociatedImages[key]->recoverFromAssociatedStorage(context)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) +gl::Error TextureStorage11_2DArray::getResource(const gl::Context *context, + const TextureHelper11 **outResource) { // if the width, height or depth is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) { ASSERT(mMipLevels > 0); - ID3D11Device *device = mRenderer->getDevice(); - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = mTextureDepth; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mFormatInfo.texFormat; + desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = getMiscFlags(); - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); - d3d11::SetDebugName(mTexture, "TexStorage2DArray.Texture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage2DArray.Texture"); } - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); + *outResource = &mTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const +gl::Error TextureStorage11_2DArray::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = mTextureDepth; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2DArray.SRV"); - 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); - } + return gl::NoError(); +} + +gl::Error TextureStorage11_2DArray::createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = resourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.mipIndex; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = index.layerIndex; + srvDesc.Texture2DArray.ArraySize = index.numLayers; - d3d11::SetDebugName(*outSRV, "TexStorage2DArray.SRV"); + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), srv)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(index.hasLayer()); - int mipLevel = index.mipIndex; - int layer = index.layerIndex; + const int mipLevel = index.mipIndex; + const int layer = index.layerIndex; + const int numLayers = index.numLayers; ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - LevelLayerKey key(mipLevel, layer); + LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + d3d11::SharedSRV srv; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.srvFormat, &srv)); + d3d11::SharedSRV blitSRV; + if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { - return error; + ANGLE_TRY(createRenderTargetSRV(*texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = layer; - srvDesc.Texture2DArray.ArraySize = 1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(texture, &srvDesc, &srv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) + else { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + blitSRV = srv.makeCopy(); } - d3d11::SetDebugName(srv, "TexStorage2DArray.RenderTargetSRV"); + srv.setDebugName("TexStorage2DArray.RenderTargetSRV"); - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = layer; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } + rtvDesc.Texture2DArray.ArraySize = numLayers; - d3d11::SetDebugName(rtv, "TexStorage2DArray.RenderTargetRTV"); + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + rtv.setDebugName("TexStorage2DArray.RenderTargetRTV"); - mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - SafeRelease(srv); + mRenderTargets[key].reset(new TextureRenderTarget11( + std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } else { - UNREACHABLE(); + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + dsvDesc.Texture2DArray.FirstArraySlice = layer; + dsvDesc.Texture2DArray.ArraySize = numLayers; + dsvDesc.Flags = 0; + + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + dsv.setDebugName("TexStorage2DArray.RenderTargetDSV"); + + mRenderTargets[key].reset(new TextureRenderTarget11( + std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } } ASSERT(outRT); - *outRT = mRenderTargets[key]; - return gl::Error(GL_NO_ERROR); + *outRT = mRenderTargets[key].get(); + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) +gl::Error TextureStorage11_2DArray::getSwizzleTexture(const TextureHelper11 **outTexture) { - if (!mSwizzleTexture) + if (!mSwizzleTexture.valid()) { - ID3D11Device *device = mRenderer->getDevice(); + const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = mTextureDepth; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = format.texFormat; + 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); - } + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - d3d11::SetDebugName(*outTexture, "TexStorage2DArray.SwizzleTexture"); + ANGLE_TRY(mRenderer->allocateTexture(desc, format, &mSwizzleTexture)); + mSwizzleTexture.setDebugName("TexStorage2DArray.SwizzleTexture"); } - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); + *outTexture = &mSwizzleTexture; + return gl::NoError(); } -gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); - if (!mSwizzleRenderTargets[mipLevel]) + if (!mSwizzleRenderTargets[mipLevel].valid()) { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); + const TextureHelper11 *swizzleTexture = nullptr; + ANGLE_TRY(getSwizzleTexture(&swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Format = + mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, mSwizzleTexture.get(), + &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::NoError(); +} + +gl::ErrorOrResult TextureStorage11_2DArray::ensureDropStencilTexture( + const gl::Context *context) +{ + if (mDropStencilTexture.valid()) + { + return DropStencil::ALREADY_EXISTS; } - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); + D3D11_TEXTURE2D_DESC dropDesc = {}; + dropDesc.ArraySize = mTextureDepth; + dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; + dropDesc.CPUAccessFlags = 0; + dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; + dropDesc.Height = mTextureHeight; + dropDesc.MipLevels = mMipLevels; + dropDesc.MiscFlags = 0; + dropDesc.SampleDesc.Count = 1; + dropDesc.SampleDesc.Quality = 0; + dropDesc.Usage = D3D11_USAGE_DEFAULT; + dropDesc.Width = mTextureWidth; + + const auto &format = + d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); + ANGLE_TRY(mRenderer->allocateTexture(dropDesc, format, &mDropStencilTexture)); + mDropStencilTexture.setDebugName("TexStorage2DArray.DropStencil"); + + std::vector layerCounts(mMipLevels, mTextureDepth); + + ANGLE_TRY(initDropStencilTexture( + context, gl::ImageIndexIterator::Make2DArray(0, mMipLevels, layerCounts.data()))); + + return DropStencil::CREATED; } +TextureStorage11_2DMultisample::TextureStorage11_2DMultisample(Renderer11 *renderer, + GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) + : TextureStorage11( + renderer, + GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), true), + GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), true, levels), + internalformat), + mTexture(), + mRenderTarget(nullptr) +{ + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); + + mMipLevels = 1; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = 1; + mSamples = samples; + mFixedSampleLocations = fixedSampleLocations; +} + +gl::Error TextureStorage11_2DMultisample::onDestroy(const gl::Context *context) +{ + InvalidateRenderTarget(context, mRenderTarget.get()); + mRenderTarget.reset(); + return gl::NoError(); } + +TextureStorage11_2DMultisample::~TextureStorage11_2DMultisample() +{ +} + +gl::Error TextureStorage11_2DMultisample::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "copyToStorage is unimplemented"; +} + +void TextureStorage11_2DMultisample::associateImage(Image11 *image, const gl::ImageIndex &index) +{ +} + +void TextureStorage11_2DMultisample::verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) +{ +} + +void TextureStorage11_2DMultisample::disassociateImage(const gl::ImageIndex &index, + Image11 *expectedImage) +{ +} + +gl::Error TextureStorage11_2DMultisample::releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) +{ + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getResource(const gl::Context *context, + const TextureHelper11 **outResource) +{ + ANGLE_TRY(ensureTextureExists(1)); + + *outResource = &mTexture; + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::ensureTextureExists(int mipLevels) +{ + // For Multisampled textures, mipLevels always equals 1. + ASSERT(mipLevels == 1); + + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0) + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mFormatInfo.texFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = getMiscFlags(); + + const gl::TextureCaps &textureCaps = + mRenderer->getNativeTextureCaps().get(mFormatInfo.internalFormat); + GLuint supportedSamples = textureCaps.getNearestSamples(mSamples); + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = static_cast(D3D11_STANDARD_MULTISAMPLE_PATTERN); + + ANGLE_TRY(mRenderer->allocateTexture(desc, mFormatInfo, &mTexture)); + mTexture.setDebugName("TexStorage2DMS.Texture"); + } + + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + const int level = index.mipIndex; + ASSERT(level == 0); + + ASSERT(outRT); + if (mRenderTarget) + { + *outRT = mRenderTarget.get(); + return gl::NoError(); + } + + const TextureHelper11 *texture = nullptr; + ANGLE_TRY(getResource(context, &texture)); + + const d3d11::SharedSRV *srv = nullptr; + ANGLE_TRY(getSRVLevel(context, level, false, &srv)); + + const d3d11::SharedSRV *blitSRV = nullptr; + ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); + + if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mFormatInfo.rtvFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + + d3d11::RenderTargetView rtv; + ANGLE_TRY(mRenderer->allocateResource(rtvDesc, texture->get(), &rtv)); + + mRenderTarget.reset(new TextureRenderTarget11( + std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, mSamples)); + + *outRT = mRenderTarget.get(); + return gl::NoError(); + } + + ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mFormatInfo.dsvFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Flags = 0; + + d3d11::DepthStencilView dsv; + ANGLE_TRY(mRenderer->allocateResource(dsvDesc, texture->get(), &dsv)); + + mRenderTarget.reset(new TextureRenderTarget11( + std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), + getLevelWidth(level), getLevelHeight(level), 1, mSamples)); + + *outRT = mRenderTarget.get(); + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + + ANGLE_TRY(mRenderer->allocateResource(srvDesc, texture.get(), outSRV)); + outSRV->setDebugName("TexStorage2DMS.SRV"); + return gl::NoError(); +} + +gl::Error TextureStorage11_2DMultisample::getSwizzleTexture(const TextureHelper11 **outTexture) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "getSwizzleTexture is unimplemented."; +} + +gl::Error TextureStorage11_2DMultisample::getSwizzleRenderTarget( + int mipLevel, + const d3d11::RenderTargetView **outRTV) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "getSwizzleRenderTarget is unimplemented."; +} + +gl::ErrorOrResult +TextureStorage11_2DMultisample::ensureDropStencilTexture(const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::InternalError() << "Drop stencil texture not implemented."; +} + +} // namespace rx 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 a88db2f0af..336aa495a8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h @@ -10,10 +10,13 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ -#include "libANGLE/Texture.h" #include "libANGLE/Error.h" +#include "libANGLE/Texture.h" #include "libANGLE/renderer/d3d/TextureStorage.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include #include namespace gl @@ -31,69 +34,111 @@ class SwapChain11; class Image11; struct Renderer11DeviceCaps; +template +using TexLevelArray = std::array; + +template +using CubeFaceArray = std::array; + class TextureStorage11 : public TextureStorage { public: - virtual ~TextureStorage11(); + ~TextureStorage11() override; 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::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); - - virtual int getTopLevel() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; + const d3d11::Format &getFormatSet() const; + gl::Error getSRVLevels(const gl::Context *context, + GLint baseLevel, + GLint maxLevel, + const d3d11::SharedSRV **outSRV); + gl::Error generateSwizzles(const gl::Context *context, const gl::SwizzleState &swizzleTarget); + void markLevelDirty(int mipLevel); + void markDirty(); + + gl::Error updateSubresourceLevel(const gl::Context *context, + const TextureHelper11 &texture, + unsigned int sourceSubresource, + const gl::ImageIndex &index, + const gl::Box ©Area); + + gl::Error copySubresourceLevel(const gl::Context *context, + const TextureHelper11 &dstTexture, + unsigned int dstSubresource, + const gl::ImageIndex &index, + const gl::Box ®ion); + + // TextureStorage virtual functions + int getTopLevel() const override; + bool isRenderTarget() const override; + bool isManaged() const override; bool supportsNativeMipmapFunction() const override; - virtual int getLevelCount() const; + int getLevelCount() const override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + gl::Error setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) override; + + virtual gl::Error getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV); virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; - - gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); - void invalidateSwizzleCacheLevel(int mipLevel); - void invalidateSwizzleCache(); - - gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, - const gl::ImageIndex &index, const gl::Box ©Area); - - gl::Error copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - const gl::ImageIndex &index, const gl::Box ®ion); - + virtual gl::Error getResource(const gl::Context *context, + const TextureHelper11 **outResource) = 0; virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; - - virtual gl::Error copyToStorage(TextureStorage *destStorage); - 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); + virtual void verifyAssociatedImageValid(const gl::ImageIndex &index, + Image11 *expectedImage) = 0; + virtual gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) = 0; protected: - TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags); + TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags, GLenum internalFormat); int getLevelWidth(int mipLevel) const; int getLevelHeight(int mipLevel) const; int getLevelDepth(int mipLevel) const; // Some classes (e.g. TextureStorage11_2D) will override getMippedResource. - virtual gl::Error getMippedResource(ID3D11Resource **outResource) { return getResource(outResource); } - - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture) = 0; - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; - gl::Error getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV); + virtual gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource); + + virtual gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) = 0; + virtual gl::Error getSwizzleRenderTarget(int mipLevel, + const d3d11::RenderTargetView **outRTV) = 0; + gl::Error getSRVLevel(const gl::Context *context, + int mipLevel, + bool blitSRV, + const d3d11::SharedSRV **outSRV); + + // Get a version of a depth texture with only depth information, not stencil. + enum DropStencil + { + CREATED, + ALREADY_EXISTS + }; + virtual gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context); + gl::Error initDropStencilTexture(const gl::Context *context, const gl::ImageIndexIterator &it); - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const = 0; + // The baseLevel parameter should *not* have mTopLevel applied. + virtual gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) = 0; - void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void verifySwizzleExists(const gl::SwizzleState &swizzleState); // Clear all cached non-swizzle SRVs and invalidate the swizzle cache. void clearSRVCache(); @@ -102,32 +147,13 @@ class TextureStorage11 : public TextureStorage int mTopLevel; unsigned int mMipLevels; - GLenum mInternalFormat; - DXGI_FORMAT mTextureFormat; - DXGI_FORMAT mShaderResourceFormat; - DXGI_FORMAT mRenderTargetFormat; - DXGI_FORMAT mDepthStencilFormat; - DXGI_FORMAT mSwizzleTextureFormat; - DXGI_FORMAT mSwizzleShaderResourceFormat; - DXGI_FORMAT mSwizzleRenderTargetFormat; + const d3d11::Format &mFormatInfo; unsigned int mTextureWidth; unsigned int mTextureHeight; unsigned int mTextureDepth; - struct SwizzleCacheValue - { - GLenum swizzleRed; - GLenum swizzleGreen; - GLenum swizzleBlue; - GLenum swizzleAlpha; - - SwizzleCacheValue(); - SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); - - bool operator ==(const SwizzleCacheValue &other) const; - bool operator !=(const SwizzleCacheValue &other) const; - }; - SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray mSwizzleCache; + TextureHelper11 mDropStencilTexture; private: const UINT mBindFlags; @@ -135,18 +161,24 @@ class TextureStorage11 : public TextureStorage struct SRVKey { - SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + SRVKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil); bool operator<(const SRVKey &rhs) const; - int baseLevel; - int mipLevels; - bool swizzle; + int baseLevel = 0; // Without mTopLevel applied. + int mipLevels = 0; + bool swizzle = false; + bool dropStencil = false; }; - typedef std::map SRVCache; + typedef std::map SRVCache; + + gl::Error getCachedOrCreateSRV(const gl::Context *context, + const SRVKey &key, + const d3d11::SharedSRV **outSRV); SRVCache mSrvCache; - ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray mLevelSRVs; + TexLevelArray mLevelBlitSRVs; }; class TextureStorage11_2D : public TextureStorage11 @@ -154,33 +186,48 @@ class TextureStorage11_2D : public TextureStorage11 public: TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false); - virtual ~TextureStorage11_2D(); + ~TextureStorage11_2D() override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getMippedResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; - virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; gl::Error ensureTextureExists(int mipLevels); private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + TexLevelArray> mRenderTarget; + bool mHasKeyedMutex; // These are members related to the zero max-LOD workaround. // D3D11 Feature Level 9_3 can't disable mipmaps on a mipmapped texture (i.e. solely sample from level zero). @@ -191,108 +238,179 @@ class TextureStorage11_2D : public TextureStorage11 // One example of this is an application that creates a texture, calls glGenerateMipmap, and then disables mipmaps on the texture. // A more likely example is an app that creates an empty texture, renders to it, and then calls glGenerateMipmap // TODO: In this rendering scenario, release the mLevelZeroTexture after mTexture has been created to save memory. - ID3D11Texture2D *mLevelZeroTexture; - RenderTarget11 *mLevelZeroRenderTarget; + TextureHelper11 mLevelZeroTexture; + std::unique_ptr mLevelZeroRenderTarget; bool mUseLevelZeroTexture; // Swizzle-related variables - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; + + TexLevelArray mAssociatedImages; +}; + +class TextureStorage11_External : public TextureStorage11 +{ + public: + TextureStorage11_External(Renderer11 *renderer, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &glDesc); + ~TextureStorage11_External() override; + + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + protected: + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + + TextureHelper11 mTexture; + int mSubresourceIndex; + bool mHasKeyedMutex; - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + Image11 *mAssociatedImage; }; class TextureStorage11_EGLImage final : public TextureStorage11 { public: - TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage); + TextureStorage11_EGLImage(Renderer11 *renderer, + EGLImageD3D *eglImage, + RenderTarget11 *renderTarget11); ~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 getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getSRV(const gl::Context *context, + const gl::TextureState &textureState, + const d3d11::SharedSRV **outSRV) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - gl::Error copyToStorage(TextureStorage *destStorage) override; + gl::Error copyToStorage(const gl::Context *context, 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; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; - gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) override; + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - gl::Error getSwizzleTexture(ID3D11Resource **outTexture) override; - gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) override; + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **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 checkForUpdatedRenderTarget(const gl::Context *context); - gl::Error createSRV(int baseLevel, + gl::Error createSRV(const gl::Context *context, + int baseLevel, int mipLevels, DXGI_FORMAT format, - ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const override; + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; - gl::Error getImageRenderTarget(RenderTarget11 **outRT) const; + gl::Error getImageRenderTarget(const gl::Context *context, RenderTarget11 **outRT) const; EGLImageD3D *mImage; uintptr_t mCurrentRenderTarget; // Swizzle-related variables - ID3D11Texture2D *mSwizzleTexture; - std::vector mSwizzleRenderTargets; + TextureHelper11 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(); + ~TextureStorage11_Cube() override; - virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + gl::Error onDestroy(const gl::Context *context) override; + + UINT getSubresourceIndex(const gl::ImageIndex &index) const override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getMippedResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getMippedResource(const gl::Context *context, + const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; - virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + gl::Error useLevelZeroWorkaroundTexture(const gl::Context *context, + bool useLevelZeroTexture) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; gl::Error ensureTextureExists(int mipLevels); private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; - - static const size_t CUBE_FACE_COUNT = 6; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + gl::Error createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const; - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + CubeFaceArray>> mRenderTarget; // Level-zero workaround members. See TextureStorage11_2D's workaround members for a description. - ID3D11Texture2D *mLevelZeroTexture; - RenderTarget11 *mLevelZeroRenderTarget[CUBE_FACE_COUNT]; + TextureHelper11 mLevelZeroTexture; + CubeFaceArray> mLevelZeroRenderTarget; bool mUseLevelZeroTexture; - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + CubeFaceArray> mAssociatedImages; }; class TextureStorage11_3D : public TextureStorage11 @@ -300,37 +418,46 @@ class TextureStorage11_3D : public TextureStorage11 public: TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual ~TextureStorage11_3D(); + ~TextureStorage11_3D() override; + + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error getResource(ID3D11Resource **outResource); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; // Handles both layer and non-layer RTs - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mLevelLayerRenderTargets; + std::map> mLevelLayerRenderTargets; - RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray> mLevelRenderTargets; - ID3D11Texture3D *mTexture; - ID3D11Texture3D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mTexture; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TexLevelArray mAssociatedImages; }; class TextureStorage11_2DArray : public TextureStorage11 @@ -338,37 +465,125 @@ class TextureStorage11_2DArray : public TextureStorage11 public: TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual ~TextureStorage11_2DArray(); + ~TextureStorage11_2DArray() override; + + gl::Error onDestroy(const gl::Context *context) override; - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; private: - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; + struct LevelLayerRangeKey + { + LevelLayerRangeKey(int mipLevelIn, int layerIn, int numLayersIn) + : mipLevel(mipLevelIn), layer(layerIn), numLayers(numLayersIn) + { + } + bool operator<(const LevelLayerRangeKey &other) const + { + if (mipLevel != other.mipLevel) + { + return mipLevel < other.mipLevel; + } + if (layer != other.layer) + { + return layer < other.layer; + } + return numLayers < other.numLayers; + } + int mipLevel; + int layer; + int numLayers; + }; - typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mRenderTargets; + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + gl::Error createRenderTargetSRV(const TextureHelper11 &texture, + const gl::ImageIndex &index, + DXGI_FORMAT resourceFormat, + d3d11::SharedSRV *srv) const; + + std::map> mRenderTargets; - ID3D11Texture2D *mTexture; + TextureHelper11 mTexture; - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + TextureHelper11 mSwizzleTexture; + TexLevelArray mSwizzleRenderTargets; - typedef std::map ImageMap; + typedef std::map ImageMap; ImageMap mAssociatedImages; }; +class TextureStorage11_2DMultisample : public TextureStorage11 +{ + public: + TextureStorage11_2DMultisample(Renderer11 *renderer, + GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations); + ~TextureStorage11_2DMultisample() override; + + gl::Error onDestroy(const gl::Context *context) override; + + gl::Error getResource(const gl::Context *context, const TextureHelper11 **outResource) override; + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; + + void associateImage(Image11 *image, const gl::ImageIndex &index) override; + void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override; + void verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override; + gl::Error releaseAssociatedImage(const gl::Context *context, + const gl::ImageIndex &index, + Image11 *incomingImage) override; + + protected: + gl::Error getSwizzleTexture(const TextureHelper11 **outTexture) override; + gl::Error getSwizzleRenderTarget(int mipLevel, const d3d11::RenderTargetView **outRTV) override; + + gl::ErrorOrResult ensureDropStencilTexture(const gl::Context *context) override; + + gl::Error ensureTextureExists(int mipLevels); + + private: + gl::Error createSRV(const gl::Context *context, + int baseLevel, + int mipLevels, + DXGI_FORMAT format, + const TextureHelper11 &texture, + d3d11::SharedSRV *outSRV) override; + + TextureHelper11 mTexture; + std::unique_ptr mRenderTarget; + + unsigned int mSamples; + GLboolean mFixedSampleLocations; +}; } #endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp new file mode 100644 index 0000000000..4b08edf71f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp @@ -0,0 +1,124 @@ +// +// 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. +// + +// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers. + +#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state, + Renderer11 *renderer) + : TransformFeedbackImpl(state), + mRenderer(renderer), + mIsDirty(true), + mBuffers(state.getIndexedBuffers().size(), nullptr), + mBufferOffsets(state.getIndexedBuffers().size(), 0), + mSerial(mRenderer->generateSerial()) +{ +} + +TransformFeedback11::~TransformFeedback11() +{ +} + +void TransformFeedback11::begin(GLenum primitiveMode) +{ + // Reset all the cached offsets to the binding offsets + mIsDirty = true; + for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++) + { + const auto &binding = mState.getIndexedBuffer(bindingIdx); + if (binding.get() != nullptr) + { + mBufferOffsets[bindingIdx] = static_cast(binding.getOffset()); + } + else + { + mBufferOffsets[bindingIdx] = 0; + } + } +} + +void TransformFeedback11::end() +{ + if (mRenderer->getWorkarounds().flushAfterEndingTransformFeedback) + { + mRenderer->getDeviceContext()->Flush(); + } +} + +void TransformFeedback11::pause() +{ +} + +void TransformFeedback11::resume() +{ +} + +void TransformFeedback11::bindGenericBuffer(const gl::BindingPointer &binding) +{ +} + +void TransformFeedback11::bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) +{ + mIsDirty = true; + mBufferOffsets[index] = static_cast(binding.getOffset()); +} + +void TransformFeedback11::onApply() +{ + mIsDirty = false; + + // Change all buffer offsets to -1 so that if any of them need to be re-applied, the are set to + // append + std::fill(mBufferOffsets.begin(), mBufferOffsets.end(), -1); +} + +bool TransformFeedback11::isDirty() const +{ + return mIsDirty; +} + +UINT TransformFeedback11::getNumSOBuffers() const +{ + return static_cast(mBuffers.size()); +} + +gl::ErrorOrResult *> TransformFeedback11::getSOBuffers( + const gl::Context *context) +{ + for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++) + { + const auto &binding = mState.getIndexedBuffer(bindingIdx); + if (binding.get() != nullptr) + { + Buffer11 *storage = GetImplAs(binding.get()); + ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + mBuffers[bindingIdx]); + } + } + + return &mBuffers; +} + +const std::vector &TransformFeedback11::getSOBufferOffsets() const +{ + return mBufferOffsets; +} + +Serial TransformFeedback11::getSerial() const +{ + return mSerial; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h new file mode 100644 index 0000000000..cc9fcc335a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TransformFeedback11.h @@ -0,0 +1,60 @@ +// +// 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. +// + +// TransformFeedback11.h: Implements the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_ + +#include "common/platform.h" + +#include "libANGLE/Error.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/TransformFeedbackImpl.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ + +class Renderer11; + +class TransformFeedback11 : public TransformFeedbackImpl +{ + public: + TransformFeedback11(const gl::TransformFeedbackState &state, Renderer11 *renderer); + ~TransformFeedback11() override; + + void begin(GLenum primitiveMode) override; + void end() override; + void pause() override; + void resume() override; + + void bindGenericBuffer(const gl::BindingPointer &binding) override; + void bindIndexedBuffer(size_t index, + const gl::OffsetBindingPointer &binding) override; + + void onApply(); + + bool isDirty() const; + + UINT getNumSOBuffers() const; + gl::ErrorOrResult *> getSOBuffers(const gl::Context *context); + const std::vector &getSOBufferOffsets() const; + + Serial getSerial() const; + + private: + Renderer11 *mRenderer; + + bool mIsDirty; + std::vector mBuffers; + std::vector mBufferOffsets; + + Serial mSerial; +}; +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp index 213ce31817..29185a9d93 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp @@ -11,9 +11,15 @@ #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #if defined (ANGLE_ENABLE_WINDOWS_STORE) -using namespace ABI::Windows::Foundation; +#include +#include +#include +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; #endif namespace rx @@ -41,7 +47,6 @@ void Trim11::trim() #if defined (ANGLE_ENABLE_WINDOWS_STORE) ID3D11Device* device = mRenderer->getDevice(); - // IDXGIDevice3 is only supported on Windows 8.1 and Windows Phone 8.1 and above. IDXGIDevice3 *dxgiDevice3 = d3d11::DynamicCastComObject(device); if (dxgiDevice3) { 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 4741e81601..69fa05a57b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h @@ -13,9 +13,7 @@ #include "libANGLE/angletypes.h" #include "libANGLE/Error.h" -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -typedef void* EventRegistrationToken; -#else +#if defined(ANGLE_ENABLE_WINDOWS_STORE) #include #endif diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp new file mode 100644 index 0000000000..97c29415ed --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp @@ -0,0 +1,413 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// VertexArray11: +// Implementation of rx::VertexArray11. +// + +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" + +#include "common/bitset_utils.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" + +using namespace angle; + +namespace rx +{ + +namespace +{ +OnBufferDataDirtyChannel *GetBufferBroadcastChannel(Buffer11 *buffer11, + IndexStorageType storageType) +{ + switch (storageType) + { + case IndexStorageType::Direct: + return buffer11->getDirectBroadcastChannel(); + case IndexStorageType::Static: + return buffer11->getStaticBroadcastChannel(); + case IndexStorageType::Dynamic: + return buffer11 ? buffer11->getStaticBroadcastChannel() : nullptr; + default: + UNREACHABLE(); + return nullptr; + } +} +} // anonymous namespace + +VertexArray11::VertexArray11(const gl::VertexArrayState &data) + : VertexArrayImpl(data), + mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE), + mTranslatedAttribs(data.getMaxAttribs()), + mCurrentArrayBuffers(data.getMaxAttribs()), + mCurrentElementArrayBuffer(), + mOnArrayBufferDataDirty(), + mOnElementArrayBufferDataDirty(this, mCurrentArrayBuffers.size()), + mAppliedNumViewsToDivisor(1), + mLastElementType(GL_NONE), + mLastDrawElementsOffset(0), + mCurrentElementArrayStorage(IndexStorageType::Invalid), + mCachedIndexInfoValid(false) +{ + for (size_t attribIndex = 0; attribIndex < mCurrentArrayBuffers.size(); ++attribIndex) + { + mOnArrayBufferDataDirty.emplace_back(this, attribIndex); + } +} + +VertexArray11::~VertexArray11() +{ +} + +void VertexArray11::destroy(const gl::Context *context) +{ + for (auto &buffer : mCurrentArrayBuffers) + { + if (buffer.get()) + { + buffer.set(context, nullptr); + } + } + + mCurrentElementArrayBuffer.set(context, nullptr); +} + +void VertexArray11::syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) +{ + ASSERT(dirtyBits.any()); + + // Generate a state serial. This serial is used in the program class to validate the cached + // input layout, and skip recomputation in the fast path. + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + mCurrentStateSerial = renderer->generateSerial(); + + // TODO(jmadill): Individual attribute invalidation. + renderer->getStateManager()->invalidateVertexBuffer(); + + for (auto dirtyBit : dirtyBits) + { + if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER) + { + mCachedIndexInfoValid = false; + mLastElementType = GL_NONE; + } + else + { + size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit); + // TODO(jiawei.shao@intel.com): Vertex Attrib Bindings + ASSERT(index == mState.getBindingIndexFromAttribIndex(index)); + mAttribsToUpdate.set(index); + } + } +} + +bool VertexArray11::flushAttribUpdates(const gl::Context *context) +{ + if (mAttribsToUpdate.any()) + { + const auto &activeLocations = + context->getGLState().getProgram()->getActiveAttribLocationsMask(); + + // Skip attrib locations the program doesn't use. + gl::AttributesMask activeToUpdate = mAttribsToUpdate & activeLocations; + + for (auto toUpdateIndex : activeToUpdate) + { + mAttribsToUpdate.reset(toUpdateIndex); + updateVertexAttribStorage(context, toUpdateIndex); + } + + return true; + } + + return false; +} + +bool VertexArray11::updateElementArrayStorage(const gl::Context *context, + GLenum elementType, + GLenum destElementType, + const void *indices) +{ + unsigned int offset = static_cast(reinterpret_cast(indices)); + + if (mCachedIndexInfoValid && mLastElementType == elementType && + offset == mLastDrawElementsOffset) + { + // Dynamic index buffers must be re-streamed every draw. + return (mCurrentElementArrayStorage == IndexStorageType::Dynamic); + } + + gl::Buffer *newBuffer = mState.getElementArrayBuffer().get(); + gl::Buffer *oldBuffer = mCurrentElementArrayBuffer.get(); + bool needsTranslation = false; + IndexStorageType newStorageType = ClassifyIndexStorage( + context->getGLState(), newBuffer, elementType, destElementType, offset, &needsTranslation); + + if (newBuffer != oldBuffer) + { + mCurrentElementArrayBuffer.set(context, newBuffer); + } + + if (newStorageType != mCurrentElementArrayStorage || newBuffer != oldBuffer) + { + Buffer11 *newBuffer11 = SafeGetImplAs(newBuffer); + + auto *newChannel = GetBufferBroadcastChannel(newBuffer11, newStorageType); + + mCurrentElementArrayStorage = newStorageType; + mOnElementArrayBufferDataDirty.bind(newChannel); + needsTranslation = true; + } + + if (mLastDrawElementsOffset != offset) + { + needsTranslation = true; + mLastDrawElementsOffset = offset; + } + + if (mLastElementType != elementType) + { + needsTranslation = true; + mLastElementType = elementType; + } + + // TODO(jmadill): We should probably promote static usage immediately, because this can change + // the storage type for dynamic buffers. + return needsTranslation || !mCachedIndexInfoValid; +} + +void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex) +{ + const auto &attrib = mState.getVertexAttribute(attribIndex); + const auto &binding = mState.getBindingFromAttribIndex(attribIndex); + + // Note: having an unchanged storage type doesn't mean the attribute is clean. + auto oldStorageType = mAttributeStorageTypes[attribIndex]; + auto newStorageType = ClassifyAttributeStorage(attrib, binding); + + mAttributeStorageTypes[attribIndex] = newStorageType; + + StateManager11 *stateManager = GetImplAs(context)->getRenderer()->getStateManager(); + + if (newStorageType == VertexStorageType::DYNAMIC) + { + if (oldStorageType != VertexStorageType::DYNAMIC) + { + // Sync dynamic attribs in a different set. + mAttribsToTranslate.reset(attribIndex); + mDynamicAttribsMask.set(attribIndex); + } + } + else + { + mAttribsToTranslate.set(attribIndex); + stateManager->invalidateVertexAttributeTranslation(); + + if (oldStorageType == VertexStorageType::DYNAMIC) + { + ASSERT(mDynamicAttribsMask[attribIndex]); + mDynamicAttribsMask.reset(attribIndex); + } + } + + gl::Buffer *oldBufferGL = mCurrentArrayBuffers[attribIndex].get(); + gl::Buffer *newBufferGL = binding.getBuffer().get(); + Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs(oldBufferGL) : nullptr; + Buffer11 *newBuffer11 = newBufferGL ? GetImplAs(newBufferGL) : nullptr; + + if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType) + { + OnBufferDataDirtyChannel *newChannel = nullptr; + + if (newStorageType == VertexStorageType::CURRENT_VALUE) + { + stateManager->invalidateCurrentValueAttrib(attribIndex); + } + else if (newBuffer11 != nullptr) + { + // Note that for static callbacks, promotion to a static buffer from a dynamic buffer + // means we need to tag dynamic buffers with static callbacks. + switch (newStorageType) + { + case VertexStorageType::DIRECT: + newChannel = newBuffer11->getDirectBroadcastChannel(); + break; + case VertexStorageType::STATIC: + case VertexStorageType::DYNAMIC: + newChannel = newBuffer11->getStaticBroadcastChannel(); + break; + default: + UNREACHABLE(); + break; + } + } + + mOnArrayBufferDataDirty[attribIndex].bind(newChannel); + mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get()); + } +} + +bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context) +{ + flushAttribUpdates(context); + const auto &activeLocations = + context->getGLState().getProgram()->getActiveAttribLocationsMask(); + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + return activeDynamicAttribs.any(); +} + +gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context, + VertexDataManager *vertexDataManager, + const DrawCallVertexParams &vertexParams) +{ + flushAttribUpdates(context); + + const auto &glState = context->getGLState(); + const gl::Program *program = glState.getProgram(); + const auto &activeLocations = program->getActiveAttribLocationsMask(); + const auto &attribs = mState.getVertexAttributes(); + const auto &bindings = mState.getVertexBindings(); + mAppliedNumViewsToDivisor = + (program != nullptr && program->usesMultiview()) ? program->getNumViews() : 1; + + if (mAttribsToTranslate.any()) + { + // Skip attrib locations the program doesn't use, saving for the next frame. + gl::AttributesMask dirtyActiveAttribs = (mAttribsToTranslate & activeLocations); + + for (auto dirtyAttribIndex : dirtyActiveAttribs) + { + mAttribsToTranslate.reset(dirtyAttribIndex); + + auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex); + + // Record basic attrib info + translatedAttrib->attribute = &attribs[dirtyAttribIndex]; + translatedAttrib->binding = &bindings[translatedAttrib->attribute->bindingIndex]; + translatedAttrib->currentValueType = currentValue.Type; + translatedAttrib->divisor = + translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; + + switch (mAttributeStorageTypes[dirtyAttribIndex]) + { + case VertexStorageType::DIRECT: + VertexDataManager::StoreDirectAttrib(translatedAttrib); + break; + case VertexStorageType::STATIC: + { + ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib)); + break; + } + case VertexStorageType::CURRENT_VALUE: + // Current value attribs are managed by the StateManager11. + break; + default: + UNREACHABLE(); + break; + } + } + } + + if (mDynamicAttribsMask.any()) + { + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + if (activeDynamicAttribs.none()) + { + return gl::NoError(); + } + + for (auto dynamicAttribIndex : activeDynamicAttribs) + { + auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex]; + const auto ¤tValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex); + + // Record basic attrib info + dynamicAttrib->attribute = &attribs[dynamicAttribIndex]; + dynamicAttrib->binding = &bindings[dynamicAttrib->attribute->bindingIndex]; + dynamicAttrib->currentValueType = currentValue.Type; + dynamicAttrib->divisor = + dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; + } + + ANGLE_TRY(vertexDataManager->storeDynamicAttribs( + context, &mTranslatedAttribs, activeDynamicAttribs, vertexParams.firstVertex(), + vertexParams.vertexCount(), vertexParams.instances())); + } + + return gl::NoError(); +} + +const std::vector &VertexArray11::getTranslatedAttribs() const +{ + return mTranslatedAttribs; +} + +void VertexArray11::signal(size_t channelID, const gl::Context *context) +{ + if (channelID == mAttributeStorageTypes.size()) + { + mCachedIndexInfoValid = false; + mLastElementType = GL_NONE; + mLastDrawElementsOffset = 0; + } + else + { + ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE); + + // This can change a buffer's storage, we'll need to re-check. + mAttribsToUpdate.set(channelID); + + // Changing the vertex attribute state can affect the vertex shader. + Renderer11 *renderer = GetImplAs(context)->getRenderer(); + renderer->getStateManager()->invalidateShaders(); + } +} + +void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, + const DrawCallVertexParams &vertexParams) +{ + const gl::State &state = context->getGLState(); + const gl::Program *program = state.getProgram(); + const auto &activeLocations = program->getActiveAttribLocationsMask(); + mAttribsToUpdate &= ~activeLocations; + + // Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness. + auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); + if (activeDynamicAttribs.any()) + { + VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs, + vertexParams.vertexCount()); + } +} + +void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews) +{ + if (mAppliedNumViewsToDivisor != numViews) + { + mAppliedNumViewsToDivisor = numViews; + mAttribsToUpdate.set(); + } +} + +TranslatedIndexData *VertexArray11::getCachedIndexInfo() +{ + return &mCachedIndexInfo; +} + +void VertexArray11::setCachedIndexInfoValid() +{ + mCachedIndexInfoValid = true; +} + +bool VertexArray11::isCachedIndexInfoValid() const +{ + return mCachedIndexInfoValid; +} + +} // namespace rx 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 b397140e71..4cdc92531d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h @@ -9,23 +9,91 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ #define LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ +#include "libANGLE/Framebuffer.h" #include "libANGLE/renderer/VertexArrayImpl.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/signal_utils.h" namespace rx { class Renderer11; -class VertexArray11 : public VertexArrayImpl +class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver { public: - VertexArray11(const gl::VertexArray::Data &data) - : VertexArrayImpl(data) - { - } - virtual ~VertexArray11() {} + VertexArray11(const gl::VertexArrayState &data); + ~VertexArray11() override; + void destroy(const gl::Context *context) override; + + void syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) override; + // This will flush any pending attrib updates and then check the dynamic attribs mask. + bool hasActiveDynamicAttrib(const gl::Context *context); + gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context, + VertexDataManager *vertexDataManager, + const DrawCallVertexParams &vertexParams); + void clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, + const DrawCallVertexParams &vertexParams); + + const std::vector &getTranslatedAttribs() const; + + // SignalReceiver implementation + void signal(size_t channelID, const gl::Context *context) override; + + Serial getCurrentStateSerial() const { return mCurrentStateSerial; } + + // In case of a multi-view program change, we have to update all attributes so that the divisor + // is adjusted. + void markAllAttributeDivisorsForAdjustment(int numViews); + + bool flushAttribUpdates(const gl::Context *context); + + // Returns true if the element array buffer needs to be translated. + bool updateElementArrayStorage(const gl::Context *context, + GLenum elementType, + GLenum destElementType, + const void *indices); + + TranslatedIndexData *getCachedIndexInfo(); + void setCachedIndexInfoValid(); + bool isCachedIndexInfoValid() const; + + private: + void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex); + + std::vector mAttributeStorageTypes; + std::vector mTranslatedAttribs; + + // The mask of attributes marked as dynamic. + gl::AttributesMask mDynamicAttribsMask; + + // A mask of attributes that need to be re-evaluated. + gl::AttributesMask mAttribsToUpdate; + + // A set of attributes we know are dirty, and need to be re-translated. + gl::AttributesMask mAttribsToTranslate; + + // We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks. + std::vector> mCurrentArrayBuffers; + gl::BindingPointer mCurrentElementArrayBuffer; + + std::vector mOnArrayBufferDataDirty; + OnBufferDataDirtyBinding mOnElementArrayBufferDataDirty; + + Serial mCurrentStateSerial; + + // The numViews value used to adjust the divisor. + int mAppliedNumViewsToDivisor; + + // If the index buffer needs re-streaming. + GLenum mLastElementType; + unsigned int mLastDrawElementsOffset; + IndexStorageType mCurrentElementArrayStorage; + TranslatedIndexData mCachedIndexInfo; + bool mCachedIndexInfoValid; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ 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 098cefcd53..611bd0f18b 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -19,92 +19,88 @@ namespace rx { -VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) + : mRenderer(renderer), + mBuffer(), + mBufferSize(0), + mDynamicUsage(false), + mMappedResourceData(nullptr) { - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; - mMappedResourceData = NULL; } VertexBuffer11::~VertexBuffer11() { - ASSERT(mMappedResourceData == NULL); - SafeRelease(mBuffer); + ASSERT(mMappedResourceData == nullptr); } gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) { - SafeRelease(mBuffer); - + mBuffer.reset(); updateSerial(); if (size > 0) { - ID3D11Device* dxDevice = mRenderer->getDevice(); - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = size; - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; + bufferDesc.ByteWidth = size; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; - HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); - } + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &mBuffer)); if (dynamicUsage) { - d3d11::SetDebugName(mBuffer, "VertexBuffer11 (dynamic)"); + mBuffer.setDebugName("VertexBuffer11 (dynamic)"); } else { - d3d11::SetDebugName(mBuffer, "VertexBuffer11 (static)"); + mBuffer.setDebugName("VertexBuffer11 (static)"); } } - mBufferSize = size; + mBufferSize = size; mDynamicUsage = dynamicUsage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexBuffer11::mapResource() { - if (mMappedResourceData == NULL) + if (mMappedResourceData == nullptr) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + HRESULT result = + dxContext->Map(mBuffer.get(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() + << "Failed to map internal vertex buffer, " << gl::FmtHR(result); } - mMappedResourceData = reinterpret_cast(mappedResource.pData); + mMappedResourceData = reinterpret_cast(mappedResource.pData); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void VertexBuffer11::hintUnmapResource() { - if (mMappedResourceData != NULL) + if (mMappedResourceData != nullptr) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - mMappedResourceData = NULL; + mMappedResourceData = nullptr; } } gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -112,81 +108,33 @@ gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attri unsigned int offset, const uint8_t *sourceData) { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } - int inputStride = static_cast(ComputeVertexAttributeStride(attrib)); + int inputStride = static_cast(ComputeVertexAttributeStride(attrib, binding)); // This will map the resource if it isn't already mapped. - gl::Error error = mapResource(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mapResource()); uint8_t *output = mMappedResourceData + offset; const uint8_t *input = sourceData; - if (instances == 0 || attrib.divisor == 0) + if (instances == 0 || binding.getDivisor() == 0) { input += inputStride * start; } 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); + const D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel; + const d3d11::VertexFormat &vertexFormatInfo = + d3d11::GetVertexFormatInfo(vertexFormatType, featureLevel); + ASSERT(vertexFormatInfo.copyFunction != nullptr); vertexFormatInfo.copyFunction(input, inputStride, count, output); - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, - GLsizei instances, unsigned int *outSpaceRequired) const -{ - unsigned int elementCount = 0; - if (attrib.enabled) - { - if (instances == 0 || attrib.divisor == 0) - { - elementCount = count; - } - else - { - // Round up to divisor, if possible - elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); - } - - 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) - { - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * elementCount; - } - return gl::Error(GL_NO_ERROR); - } - else - { - return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); - } - } - else - { - const unsigned int elementSize = 4; - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * 4; - } - return gl::Error(GL_NO_ERROR); - } + return gl::NoError(); } unsigned int VertexBuffer11::getBufferSize() const @@ -202,34 +150,35 @@ gl::Error VertexBuffer11::setBufferSize(unsigned int size) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } gl::Error VertexBuffer11::discard() { - if (!mBuffer) + if (!mBuffer.valid()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + HRESULT result = dxContext->Map(mBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result); + return gl::OutOfMemory() << "Failed to map internal buffer for discarding, " + << gl::FmtHR(result); } - dxContext->Unmap(mBuffer, 0); + dxContext->Unmap(mBuffer.get(), 0); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -ID3D11Buffer *VertexBuffer11::getBuffer() const +const d3d11::Buffer &VertexBuffer11::getBuffer() const { return mBuffer; } -} +} // namespace rx 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 773c4474e1..ab619ae503 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h @@ -12,6 +12,7 @@ #include #include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" namespace rx { @@ -21,11 +22,13 @@ class VertexBuffer11 : public VertexBuffer { public: explicit VertexBuffer11(Renderer11 *const renderer); - virtual ~VertexBuffer11(); - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + gl::Error initialize(unsigned int size, bool dynamicUsage) override; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -33,29 +36,27 @@ class VertexBuffer11 : public VertexBuffer unsigned int offset, const uint8_t *sourceData) override; - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const; + unsigned int getBufferSize() const override; + gl::Error setBufferSize(unsigned int size) override; + gl::Error discard() override; - virtual unsigned int getBufferSize() const; - virtual gl::Error setBufferSize(unsigned int size); - virtual gl::Error discard(); + void hintUnmapResource() override; - virtual void hintUnmapResource(); - - ID3D11Buffer *getBuffer() const; + const d3d11::Buffer &getBuffer() const; private: + ~VertexBuffer11() override; gl::Error mapResource(); Renderer11 *const mRenderer; - ID3D11Buffer *mBuffer; + d3d11::Buffer mBuffer; unsigned int mBufferSize; bool mDynamicUsage; uint8_t *mMappedResourceData; }; -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ 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 1ec21dee55..7c5c157c6f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl @@ -15,33 +15,42 @@ inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t cou if (attribSize == stride && inputComponentCount == outputComponentCount) { memcpy(output, input, count * attribSize); + return; } - else - { - const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); - const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + if (inputComponentCount == outputComponentCount) + { for (size_t i = 0; i < count; i++) { const T *offsetInput = reinterpret_cast(input + (i * stride)); T *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; - for (size_t j = 0; j < inputComponentCount; j++) - { - offsetOutput[j] = offsetInput[j]; - } + memcpy(offsetOutput, offsetInput, attribSize); + } + return; + } - for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) - { - // Set the remaining G/B channels to 0. - offsetOutput[j] = 0; - } + const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); - if (inputComponentCount < outputComponentCount && outputComponentCount == 4) - { - // Set the remaining alpha channel to the defaultAlphaValue. - offsetOutput[3] = defaultAlphaValue; - } + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (i * stride)); + T *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + memcpy(offsetOutput, offsetInput, attribSize); + + if (inputComponentCount < lastNonAlphaOutputComponent) + { + // Set the remaining G/B channels to 0. + size_t numComponents = (lastNonAlphaOutputComponent - inputComponentCount); + memset(&offsetOutput[inputComponentCount], 0, numComponents * sizeof(T)); + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // Set the remaining alpha channel to the defaultAlphaValue. + offsetOutput[3] = defaultAlphaValue; } } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json new file mode 100644 index 0000000000..891d30d252 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_data.json @@ -0,0 +1,118 @@ +{ + "UNKNOWN": "NONE", + "R32G32B32A32_TYPELESS": "", + "R32G32B32A32_FLOAT": "", + "R32G32B32A32_UINT": "", + "R32G32B32A32_SINT": "", + "R32G32B32_TYPELESS": "", + "R32G32B32_FLOAT": "", + "R32G32B32_UINT": "", + "R32G32B32_SINT": "", + "R16G16B16A16_TYPELESS": "", + "R16G16B16A16_FLOAT": "", + "R16G16B16A16_UNORM": "", + "R16G16B16A16_UINT": "", + "R16G16B16A16_SNORM": "", + "R16G16B16A16_SINT": "", + "R32G32_TYPELESS": "", + "R32G32_FLOAT": "", + "R32G32_UINT": "", + "R32G32_SINT": "", + "R32G8X24_TYPELESS": "", + "D32_FLOAT_S8X24_UINT": "", + "R32_FLOAT_X8X24_TYPELESS": "", + "X32_TYPELESS_G8X24_UINT": "", + "R10G10B10A2_TYPELESS": "", + "R10G10B10A2_UNORM": "", + "R10G10B10A2_UINT": "", + "R11G11B10_FLOAT": "", + "R8G8B8A8_TYPELESS": "", + "R8G8B8A8_UNORM": "", + "R8G8B8A8_UNORM_SRGB": "", + "R8G8B8A8_UINT": "", + "R8G8B8A8_SNORM": "", + "R8G8B8A8_SINT": "", + "R16G16_TYPELESS": "", + "R16G16_FLOAT": "", + "R16G16_UNORM": "", + "R16G16_UINT": "", + "R16G16_SNORM": "", + "R16G16_SINT": "", + "R32_TYPELESS": "", + "D32_FLOAT": "", + "R32_FLOAT": "", + "R32_UINT": "", + "R32_SINT": "", + "R24G8_TYPELESS": "", + "D24_UNORM_S8_UINT": "", + "R24_UNORM_X8_TYPELESS": "", + "X24_TYPELESS_G8_UINT": "", + "R8G8_TYPELESS": "", + "R8G8_UNORM": "", + "R8G8_UINT": "", + "R8G8_SNORM": "", + "R8G8_SINT": "", + "R16_TYPELESS": "", + "R16_FLOAT": "", + "D16_UNORM": "", + "R16_UNORM": "", + "R16_UINT": "", + "R16_SNORM": "", + "R16_SINT": "", + "R8_TYPELESS": "", + "R8_UNORM": "", + "R8_UINT": "", + "R8_SNORM": "", + "R8_SINT": "", + "A8_UNORM": "", + "R1_UNORM": "", + "R9G9B9E5_SHAREDEXP": "", + "R8G8_B8G8_UNORM": "", + "G8R8_G8B8_UNORM": "", + "BC1_TYPELESS": "", + "BC1_UNORM": "BC1_RGBA_UNORM_BLOCK", + "BC1_UNORM_SRGB": "BC1_RGBA_UNORM_SRGB_BLOCK", + "BC2_TYPELESS": "", + "BC2_UNORM": "BC2_RGBA_UNORM_BLOCK", + "BC2_UNORM_SRGB": "BC2_RGBA_UNORM_SRGB_BLOCK", + "BC3_TYPELESS": "", + "BC3_UNORM": "BC3_RGBA_UNORM_BLOCK", + "BC3_UNORM_SRGB": "BC3_RGBA_UNORM_SRGB_BLOCK", + "BC4_TYPELESS": "", + "BC4_UNORM": "", + "BC4_SNORM": "", + "BC5_TYPELESS": "", + "BC5_UNORM": "", + "BC5_SNORM": "", + "B5G6R5_UNORM": "", + "B5G5R5A1_UNORM": "", + "B8G8R8A8_UNORM": "", + "B8G8R8X8_UNORM": "", + "R10G10B10_XR_BIAS_A2_UNORM": "", + "B8G8R8A8_TYPELESS": "", + "B8G8R8A8_UNORM_SRGB": "", + "B8G8R8X8_TYPELESS": "", + "B8G8R8X8_UNORM_SRGB": "", + "BC6H_TYPELESS": "", + "BC6H_UF16": "", + "BC6H_SF16": "", + "BC7_TYPELESS": "", + "BC7_UNORM": "", + "BC7_UNORM_SRGB": "", + "AYUV": "", + "Y410": "", + "Y416": "", + "NV12": "", + "P010": "", + "P016": "", + "420_OPAQUE": "", + "YUY2": "", + "Y210": "", + "Y216": "", + "NV11": "", + "AI44": "", + "IA44": "", + "P8": "", + "A8P8": "", + "B4G4R4A4_UNORM": "" +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp new file mode 100644 index 0000000000..b0697bc5db --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/dxgi_format_map_autogen.cpp @@ -0,0 +1,516 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_dxgi_format_table.py using data from dxgi_format_data.json. +// +// Copyright 2017 The ANGLE Project 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 format info: +// Determining metadata about a DXGI format. + +#include "libANGLE/renderer/Format.h" + +using namespace angle; + +namespace rx +{ + +namespace d3d11 +{ + +GLenum GetComponentType(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + break; + case DXGI_FORMAT_A8P8: + break; + case DXGI_FORMAT_A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_AI44: + break; + case DXGI_FORMAT_AYUV: + break; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B5G5R5A1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B5G6R5_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8X8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC1_TYPELESS: + break; + case DXGI_FORMAT_BC1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC1_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC2_TYPELESS: + break; + case DXGI_FORMAT_BC2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC2_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC3_TYPELESS: + break; + case DXGI_FORMAT_BC3_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC3_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC4_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_BC4_TYPELESS: + break; + case DXGI_FORMAT_BC4_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC5_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_BC5_TYPELESS: + break; + case DXGI_FORMAT_BC5_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC6H_SF16: + break; + case DXGI_FORMAT_BC6H_TYPELESS: + break; + case DXGI_FORMAT_BC6H_UF16: + break; + case DXGI_FORMAT_BC7_TYPELESS: + break; + case DXGI_FORMAT_BC7_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_BC7_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_D16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_D24_UNORM_S8_UINT: + break; + case DXGI_FORMAT_D32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + break; + case DXGI_FORMAT_G8R8_G8B8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_IA44: + break; + case DXGI_FORMAT_NV11: + break; + case DXGI_FORMAT_NV12: + break; + case DXGI_FORMAT_P010: + break; + case DXGI_FORMAT_P016: + break; + case DXGI_FORMAT_P8: + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + break; + case DXGI_FORMAT_R10G10B10A2_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R11G11B10_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16B16A16_SINT: + return GL_INT; + case DXGI_FORMAT_R16G16B16A16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + break; + case DXGI_FORMAT_R16G16B16A16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16G16B16A16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16G16_SINT: + return GL_INT; + case DXGI_FORMAT_R16G16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16G16_TYPELESS: + break; + case DXGI_FORMAT_R16G16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16G16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R16_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R16_SINT: + return GL_INT; + case DXGI_FORMAT_R16_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R16_TYPELESS: + break; + case DXGI_FORMAT_R16_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R16_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R1_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R24G8_TYPELESS: + break; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32B32A32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G32B32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32B32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32B32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32G32_SINT: + return GL_INT; + case DXGI_FORMAT_R32G32_TYPELESS: + break; + case DXGI_FORMAT_R32G32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R32G8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_FLOAT: + return GL_FLOAT; + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + return GL_FLOAT; + case DXGI_FORMAT_R32_SINT: + return GL_INT; + case DXGI_FORMAT_R32_TYPELESS: + break; + case DXGI_FORMAT_R32_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8B8A8_SINT: + return GL_INT; + case DXGI_FORMAT_R8G8B8A8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + break; + case DXGI_FORMAT_R8G8B8A8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8B8A8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_B8G8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_SINT: + return GL_INT; + case DXGI_FORMAT_R8G8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8G8_TYPELESS: + break; + case DXGI_FORMAT_R8G8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8G8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R8_SINT: + return GL_INT; + case DXGI_FORMAT_R8_SNORM: + return GL_SIGNED_NORMALIZED; + case DXGI_FORMAT_R8_TYPELESS: + break; + case DXGI_FORMAT_R8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_R8_UNORM: + return GL_UNSIGNED_NORMALIZED; + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + return GL_FLOAT; + case DXGI_FORMAT_UNKNOWN: + break; + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return GL_UNSIGNED_INT; + case DXGI_FORMAT_Y210: + break; + case DXGI_FORMAT_Y216: + break; + case DXGI_FORMAT_Y410: + break; + case DXGI_FORMAT_Y416: + break; + case DXGI_FORMAT_YUY2: + break; + default: + break; + } + + UNREACHABLE(); + return GL_NONE; +} + +} // namespace d3d11 + +namespace d3d11_angle +{ + +const Format &GetFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + break; + case DXGI_FORMAT_A8P8: + break; + case DXGI_FORMAT_A8_UNORM: + return Format::Get(Format::ID::A8_UNORM); + case DXGI_FORMAT_AI44: + break; + case DXGI_FORMAT_AYUV: + break; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return Format::Get(Format::ID::B4G4R4A4_UNORM); + case DXGI_FORMAT_B5G5R5A1_UNORM: + return Format::Get(Format::ID::B5G5R5A1_UNORM); + case DXGI_FORMAT_B5G6R5_UNORM: + return Format::Get(Format::ID::B5G6R5_UNORM); + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8A8_UNORM: + return Format::Get(Format::ID::B8G8R8A8_UNORM); + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return Format::Get(Format::ID::B8G8R8A8_UNORM_SRGB); + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + break; + case DXGI_FORMAT_B8G8R8X8_UNORM: + return Format::Get(Format::ID::B8G8R8X8_UNORM); + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + break; + case DXGI_FORMAT_BC1_TYPELESS: + break; + case DXGI_FORMAT_BC1_UNORM: + return Format::Get(Format::ID::BC1_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC1_UNORM_SRGB: + return Format::Get(Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC2_TYPELESS: + break; + case DXGI_FORMAT_BC2_UNORM: + return Format::Get(Format::ID::BC2_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC2_UNORM_SRGB: + return Format::Get(Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC3_TYPELESS: + break; + case DXGI_FORMAT_BC3_UNORM: + return Format::Get(Format::ID::BC3_RGBA_UNORM_BLOCK); + case DXGI_FORMAT_BC3_UNORM_SRGB: + return Format::Get(Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK); + case DXGI_FORMAT_BC4_SNORM: + break; + case DXGI_FORMAT_BC4_TYPELESS: + break; + case DXGI_FORMAT_BC4_UNORM: + break; + case DXGI_FORMAT_BC5_SNORM: + break; + case DXGI_FORMAT_BC5_TYPELESS: + break; + case DXGI_FORMAT_BC5_UNORM: + break; + case DXGI_FORMAT_BC6H_SF16: + break; + case DXGI_FORMAT_BC6H_TYPELESS: + break; + case DXGI_FORMAT_BC6H_UF16: + break; + case DXGI_FORMAT_BC7_TYPELESS: + break; + case DXGI_FORMAT_BC7_UNORM: + break; + case DXGI_FORMAT_BC7_UNORM_SRGB: + break; + case DXGI_FORMAT_D16_UNORM: + return Format::Get(Format::ID::D16_UNORM); + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return Format::Get(Format::ID::D24_UNORM_S8_UINT); + case DXGI_FORMAT_D32_FLOAT: + return Format::Get(Format::ID::D32_FLOAT); + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return Format::Get(Format::ID::D32_FLOAT_S8X24_UINT); + case DXGI_FORMAT_G8R8_G8B8_UNORM: + break; + case DXGI_FORMAT_IA44: + break; + case DXGI_FORMAT_NV11: + break; + case DXGI_FORMAT_NV12: + break; + case DXGI_FORMAT_P010: + break; + case DXGI_FORMAT_P016: + break; + case DXGI_FORMAT_P8: + break; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + break; + case DXGI_FORMAT_R10G10B10A2_UINT: + return Format::Get(Format::ID::R10G10B10A2_UINT); + case DXGI_FORMAT_R10G10B10A2_UNORM: + return Format::Get(Format::ID::R10G10B10A2_UNORM); + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + break; + case DXGI_FORMAT_R11G11B10_FLOAT: + return Format::Get(Format::ID::R11G11B10_FLOAT); + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return Format::Get(Format::ID::R16G16B16A16_FLOAT); + case DXGI_FORMAT_R16G16B16A16_SINT: + return Format::Get(Format::ID::R16G16B16A16_SINT); + case DXGI_FORMAT_R16G16B16A16_SNORM: + return Format::Get(Format::ID::R16G16B16A16_SNORM); + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + break; + case DXGI_FORMAT_R16G16B16A16_UINT: + return Format::Get(Format::ID::R16G16B16A16_UINT); + case DXGI_FORMAT_R16G16B16A16_UNORM: + return Format::Get(Format::ID::R16G16B16A16_UNORM); + case DXGI_FORMAT_R16G16_FLOAT: + return Format::Get(Format::ID::R16G16_FLOAT); + case DXGI_FORMAT_R16G16_SINT: + return Format::Get(Format::ID::R16G16_SINT); + case DXGI_FORMAT_R16G16_SNORM: + return Format::Get(Format::ID::R16G16_SNORM); + case DXGI_FORMAT_R16G16_TYPELESS: + break; + case DXGI_FORMAT_R16G16_UINT: + return Format::Get(Format::ID::R16G16_UINT); + case DXGI_FORMAT_R16G16_UNORM: + return Format::Get(Format::ID::R16G16_UNORM); + case DXGI_FORMAT_R16_FLOAT: + return Format::Get(Format::ID::R16_FLOAT); + case DXGI_FORMAT_R16_SINT: + return Format::Get(Format::ID::R16_SINT); + case DXGI_FORMAT_R16_SNORM: + return Format::Get(Format::ID::R16_SNORM); + case DXGI_FORMAT_R16_TYPELESS: + break; + case DXGI_FORMAT_R16_UINT: + return Format::Get(Format::ID::R16_UINT); + case DXGI_FORMAT_R16_UNORM: + return Format::Get(Format::ID::R16_UNORM); + case DXGI_FORMAT_R1_UNORM: + break; + case DXGI_FORMAT_R24G8_TYPELESS: + break; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return Format::Get(Format::ID::R32G32B32A32_FLOAT); + case DXGI_FORMAT_R32G32B32A32_SINT: + return Format::Get(Format::ID::R32G32B32A32_SINT); + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + return Format::Get(Format::ID::R32G32B32A32_UINT); + case DXGI_FORMAT_R32G32B32_FLOAT: + return Format::Get(Format::ID::R32G32B32_FLOAT); + case DXGI_FORMAT_R32G32B32_SINT: + return Format::Get(Format::ID::R32G32B32_SINT); + case DXGI_FORMAT_R32G32B32_TYPELESS: + break; + case DXGI_FORMAT_R32G32B32_UINT: + return Format::Get(Format::ID::R32G32B32_UINT); + case DXGI_FORMAT_R32G32_FLOAT: + return Format::Get(Format::ID::R32G32_FLOAT); + case DXGI_FORMAT_R32G32_SINT: + return Format::Get(Format::ID::R32G32_SINT); + case DXGI_FORMAT_R32G32_TYPELESS: + break; + case DXGI_FORMAT_R32G32_UINT: + return Format::Get(Format::ID::R32G32_UINT); + case DXGI_FORMAT_R32G8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_FLOAT: + return Format::Get(Format::ID::R32_FLOAT); + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + break; + case DXGI_FORMAT_R32_SINT: + return Format::Get(Format::ID::R32_SINT); + case DXGI_FORMAT_R32_TYPELESS: + break; + case DXGI_FORMAT_R32_UINT: + return Format::Get(Format::ID::R32_UINT); + case DXGI_FORMAT_R8G8B8A8_SINT: + return Format::Get(Format::ID::R8G8B8A8_SINT); + case DXGI_FORMAT_R8G8B8A8_SNORM: + return Format::Get(Format::ID::R8G8B8A8_SNORM); + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + break; + case DXGI_FORMAT_R8G8B8A8_UINT: + return Format::Get(Format::ID::R8G8B8A8_UINT); + case DXGI_FORMAT_R8G8B8A8_UNORM: + return Format::Get(Format::ID::R8G8B8A8_UNORM); + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return Format::Get(Format::ID::R8G8B8A8_UNORM_SRGB); + case DXGI_FORMAT_R8G8_B8G8_UNORM: + break; + case DXGI_FORMAT_R8G8_SINT: + return Format::Get(Format::ID::R8G8_SINT); + case DXGI_FORMAT_R8G8_SNORM: + return Format::Get(Format::ID::R8G8_SNORM); + case DXGI_FORMAT_R8G8_TYPELESS: + break; + case DXGI_FORMAT_R8G8_UINT: + return Format::Get(Format::ID::R8G8_UINT); + case DXGI_FORMAT_R8G8_UNORM: + return Format::Get(Format::ID::R8G8_UNORM); + case DXGI_FORMAT_R8_SINT: + return Format::Get(Format::ID::R8_SINT); + case DXGI_FORMAT_R8_SNORM: + return Format::Get(Format::ID::R8_SNORM); + case DXGI_FORMAT_R8_TYPELESS: + break; + case DXGI_FORMAT_R8_UINT: + return Format::Get(Format::ID::R8_UINT); + case DXGI_FORMAT_R8_UNORM: + return Format::Get(Format::ID::R8_UNORM); + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + return Format::Get(Format::ID::R9G9B9E5_SHAREDEXP); + case DXGI_FORMAT_UNKNOWN: + return Format::Get(Format::ID::NONE); + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + break; + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + break; + case DXGI_FORMAT_Y210: + break; + case DXGI_FORMAT_Y216: + break; + case DXGI_FORMAT_Y410: + break; + case DXGI_FORMAT_Y416: + break; + case DXGI_FORMAT_YUY2: + break; + default: + break; + } + + UNREACHABLE(); + return Format::Get(Format::ID::NONE); +} + +} // namespace d3d11_angle + +} // namespace rx 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 index e81b4deea5..942745674f 100644 --- 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 @@ -8,7 +8,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_TYPELESS": { @@ -18,7 +19,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_FLOAT": { @@ -28,27 +30,30 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R32G32B32A32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32A32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_TYPELESS": { @@ -58,7 +63,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_FLOAT": { @@ -68,7 +74,8 @@ "shaderSample": "11_0check", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_UINT": { @@ -78,7 +85,8 @@ "shaderSample": "never", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32B32_SINT": { @@ -88,7 +96,8 @@ "shaderSample": "never", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_TYPELESS": { @@ -98,57 +107,63 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_FLOAT": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "9_3check_10_0always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16B16A16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16B16A16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16B16A16_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16G16B16A16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_TYPELESS": { @@ -158,7 +173,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_FLOAT": { @@ -168,37 +184,41 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R32G32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32G8X24_TYPELESS": { - "texture2D": "always", + "texture2D": "10_0", "texture3D": "never", - "textureCube": "always", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D32_FLOAT_S8X24_UINT": { @@ -208,7 +228,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "10_0", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS": { @@ -218,7 +239,8 @@ "shaderSample": "10_0check10_1always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT": { @@ -228,47 +250,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10A2_TYPELESS": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10A2_UNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R10G10B10A2_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R11G11B10_FLOAT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8B8A8_TYPELESS": { @@ -278,57 +305,63 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8B8A8_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R8G8B8A8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8B8A8_SNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8B8A8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_TYPELESS": { @@ -338,7 +371,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_FLOAT": { @@ -348,57 +382,63 @@ "shaderSample": "10_0", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R16G16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16G16_SNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16G16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_TYPELESS": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D32_FLOAT": { @@ -408,7 +448,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "10_0", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_FLOAT": { @@ -418,27 +459,30 @@ "shaderSample": "10_0check10_1always", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_R32_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R32_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R24G8_TYPELESS": { @@ -448,7 +492,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_D24_UNORM_S8_UINT": { @@ -468,7 +513,8 @@ "shaderSample": "10_0check10_1always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_X24_TYPELESS_G8_UINT": { @@ -478,7 +524,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_TYPELESS": { @@ -488,47 +535,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_UNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", + "shaderSample": "9_3check_10_0always", + "renderTarget": "9_3check_10_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_SNORM": { "texture2D": "always", - "texture3D": "always", - "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "texture3D": "10_0", + "textureCube": "10_0", + "shaderSample": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8G8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_TYPELESS": { @@ -538,17 +590,19 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_FLOAT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_D16_UNORM": { @@ -558,47 +612,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "check", - "depthStencil": "always" + "depthStencil": "always", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "shaderSample": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R16_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R16_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_TYPELESS": { @@ -608,47 +667,52 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", - "renderTarget": "always", + "shaderSample": "always", + "renderTarget": "9_3check_10_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8_UINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8_SNORM": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R8_SINT": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "never", - "renderTarget": "always", + "renderTarget": "10_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_A8_UNORM": { @@ -658,7 +722,8 @@ "shaderSample": "10_0", "renderTarget": "always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "10_0" }, "DXGI_FORMAT_R1_UNORM": { @@ -668,17 +733,19 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R9G9B9E5_SHAREDEXP": { - "texture2D": "always", - "texture3D": "always", - "textureCube": "always", + "texture2D": "10_0", + "texture3D": "10_0", + "textureCube": "10_0", "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R8G8_B8G8_UNORM": { @@ -688,7 +755,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_G8R8_G8B8_UNORM": { @@ -698,7 +766,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_TYPELESS": { @@ -708,27 +777,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC1_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_TYPELESS": { @@ -738,27 +810,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC2_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_TYPELESS": { @@ -768,27 +843,30 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_UNORM": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC3_UNORM_SRGB": { "texture2D": "always", "texture3D": "always", "textureCube": "always", - "shaderSample": "10_0", + "shaderSample": "always", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_TYPELESS": { @@ -798,7 +876,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_UNORM": { @@ -808,7 +887,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC4_SNORM": { @@ -818,7 +898,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_TYPELESS": { @@ -828,7 +909,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_UNORM": { @@ -838,7 +920,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC5_SNORM": { @@ -848,7 +931,8 @@ "shaderSample": "10_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B5G6R5_UNORM": { @@ -858,7 +942,8 @@ "shaderSample": "dxgi1_2", "renderTarget": "dxgi1_2", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" }, "DXGI_FORMAT_B5G5R5A1_UNORM": { @@ -868,17 +953,19 @@ "shaderSample": "dxgi1_2", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" }, "DXGI_FORMAT_B8G8R8A8_UNORM": { "texture2D": "check", "texture3D": "check", "textureCube": "check", - "shaderSample": "10_0check11_0always", - "renderTarget": "10_0check11_0always", + "shaderSample": "9_3always_10_0check11_0always", + "renderTarget": "9_3always_10_0check11_0always", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "always" }, "DXGI_FORMAT_B8G8R8X8_UNORM": { @@ -888,7 +975,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM": { @@ -898,7 +986,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8A8_TYPELESS": { @@ -908,7 +997,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB": { @@ -918,7 +1008,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8X8_TYPELESS": { @@ -928,7 +1019,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB": { @@ -938,7 +1030,8 @@ "shaderSample": "10_0check11_0always", "renderTarget": "11_0", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_TYPELESS": { @@ -948,7 +1041,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_UF16": { @@ -958,7 +1052,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC6H_SF16": { @@ -968,7 +1063,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_TYPELESS": { @@ -978,7 +1074,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_UNORM": { @@ -988,7 +1085,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_BC7_UNORM_SRGB": { @@ -998,7 +1096,8 @@ "shaderSample": "11_0", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_AYUV": { @@ -1008,7 +1107,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y410": { @@ -1018,7 +1118,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y416": { @@ -1028,7 +1129,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_NV12": { @@ -1038,7 +1140,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P010": { @@ -1048,7 +1151,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P016": { @@ -1058,7 +1162,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_420_OPAQUE": { @@ -1068,7 +1173,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_YUY2": { @@ -1078,7 +1184,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y210": { @@ -1088,7 +1195,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_Y216": { @@ -1098,7 +1206,8 @@ "shaderSample": "11_1", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_NV11": { @@ -1108,7 +1217,8 @@ "shaderSample": "11_1", "renderTarget": "11_1", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_AI44": { @@ -1118,7 +1228,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_IA44": { @@ -1128,7 +1239,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_P8": { @@ -1138,7 +1250,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_A8P8": { @@ -1148,7 +1261,8 @@ "shaderSample": "never", "renderTarget": "never", "multisampleRT": "never", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "never" }, "DXGI_FORMAT_B4G4R4A4_UNORM": { @@ -1158,7 +1272,8 @@ "shaderSample": "dxgi1_2", "renderTarget": "check", "multisampleRT": "check", - "depthStencil": "never" + "depthStencil": "never", + "mipAutoGen": "dxgi1_2" } } ] 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 index cbc36445e6..4d7e46bdf2 100644 --- 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 @@ -26,205 +26,205 @@ namespace d3d11 #define F_RT D3D11_FORMAT_SUPPORT_RENDER_TARGET #define F_MS D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET #define F_DS D3D11_FORMAT_SUPPORT_DEPTH_STENCIL +#define F_MIPGEN D3D11_FORMAT_SUPPORT_MIP_AUTOGEN 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 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 | D3D11_FORMAT_SUPPORT_MIP_AUTOGEN; static const DXGISupport defaultSupport(0, 0, AllSupportFlags); return defaultSupport; } -const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_9_3(DXGI_FORMAT dxgiFormat) { + // clang-format off 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_MIPGEN | 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(0, F_DS, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_SF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -234,112 +234,112 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS | F_SAMPLE); 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R16G16_SNORM: @@ -349,157 +349,157 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_R16G16_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | 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); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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_DS, F_MS | F_SAMPLE); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | F_RT, F_DS, F_MS); 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_R8G8B8A8_SNORM: @@ -509,122 +509,122 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_R8G8B8A8_TYPELESS: { - static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MS | F_RT | F_SAMPLE, 0); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS, F_MS | F_RT | F_SAMPLE); 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS, F_MS | F_RT); 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -632,190 +632,192 @@ const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } -const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_10_0(DXGI_FORMAT dxgiFormat) { + // clang-format off 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_MIPGEN, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } case DXGI_FORMAT_BC6H_SF16: { - static const DXGISupport info(0, F_DS | F_MS | F_RT, 0); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -825,397 +827,397 @@ const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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_SAMPLE, F_DS, F_MS); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_SAMPLE, F_3D | F_DS | F_MS | F_RT, 0); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -1223,190 +1225,192 @@ const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } -const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) +const DXGISupport &GetDXGISupport_10_1(DXGI_FORMAT dxgiFormat) { + // clang-format off 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_MIPGEN, 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(F_RT | F_SAMPLE, F_DS, F_2D | F_3D | F_CUBE | F_MS); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, F_2D | F_3D | F_CUBE | F_MS | F_SAMPLE); 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); + static const DXGISupport info(0, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | F_RT | F_SAMPLE, F_MS); return info; } case DXGI_FORMAT_D24_UNORM_S8_UINT: @@ -1416,397 +1420,1583 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) } case DXGI_FORMAT_D32_FLOAT: { - static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_RT | F_SAMPLE, F_MS); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_DS, F_3D | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, 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); + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(0, F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE | F_SAMPLE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_RT, F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_Y210: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y216: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y410: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y416: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_YUY2: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + + default: + UNREACHABLE(); + return GetDefaultSupport(); + } + // clang-format on +} + +const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) +{ + // clang-format off + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8P8: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_AI44: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_AYUV: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_B4G4R4A4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM: + { + static const DXGISupport info(F_MIPGEN | 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_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | 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_MIPGEN, 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_MIPGEN, 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_IA44: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_NV11: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_NV12: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P010: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P016: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P8: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_Y210: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y216: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y410: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_Y416: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_YUY2: + { + static const DXGISupport info(0, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); + return info; + } + + default: + UNREACHABLE(); + return GetDefaultSupport(); + } + // clang-format on +} + +const DXGISupport &GetDXGISupport_11_1(DXGI_FORMAT dxgiFormat) +{ + // clang-format off + switch (dxgiFormat) + { + case DXGI_FORMAT_420_OPAQUE: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_A8P8: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | 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_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_AI44: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_AYUV: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_B4G4R4A4_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_RT | F_SAMPLE, F_DS, F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, F_2D | F_3D | F_CUBE); + return info; + } + case DXGI_FORMAT_B8G8R8A8_UNORM: + { + static const DXGISupport info(F_MIPGEN | 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_MIPGEN, F_2D | F_3D | F_CUBE | F_MS); + return info; + } + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + { + static const DXGISupport info(0, F_DS | F_MIPGEN | 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_MIPGEN, 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_MIPGEN, 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_IA44: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT | F_SAMPLE, 0); + return info; + } + case DXGI_FORMAT_NV11: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_NV12: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P010: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P016: + { + static const DXGISupport info(F_2D | F_RT | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN, F_MS); + return info; + } + case DXGI_FORMAT_P8: + { + static const DXGISupport info(F_2D, F_3D | F_CUBE | F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R10G10B10A2_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16B16A16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16G16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R16_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_MS | F_RT, 0); + return info; + } + case DXGI_FORMAT_R32G32B32A32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32B32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32B32_SINT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS | F_RT); + return info; + } + case DXGI_FORMAT_R32G32_FLOAT: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32G8X24_TYPELESS: + { + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R32_TYPELESS: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE, F_DS | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8B8A8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8G8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_SNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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_MIPGEN | 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_MIPGEN | F_SAMPLE, F_MS); + return info; + } + case DXGI_FORMAT_R8_UNORM: + { + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_3D | F_CUBE | F_SAMPLE, F_DS | F_MIPGEN | 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); + static const DXGISupport info(0, F_2D | F_3D | F_CUBE | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_CUBE, F_3D | F_DS | F_MIPGEN | 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); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 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); + static const DXGISupport info(F_2D | F_SAMPLE, F_3D | F_CUBE | F_DS | F_MIPGEN | F_MS | F_RT, 0); return info; } @@ -1814,6 +3004,7 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) UNREACHABLE(); return GetDefaultSupport(); } + // clang-format on } } @@ -1825,17 +3016,22 @@ const DXGISupport &GetDXGISupport_11_0(DXGI_FORMAT dxgiFormat) #undef F_RT #undef F_MS #undef F_DS +#undef F_MIPGEN const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { + case D3D_FEATURE_LEVEL_9_3: + return GetDXGISupport_9_3(dxgiFormat); 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); + case D3D_FEATURE_LEVEL_11_1: + return GetDXGISupport_11_1(dxgiFormat); default: return GetDefaultSupport(); } 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 index 1d8d68565e..a818f376ef 100644 --- 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 @@ -8,6 +8,9 @@ // version, D3D feature level, and is sometimes guaranteed or optional. // +#ifndef LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ + #include "common/platform.h" namespace rx @@ -42,3 +45,5 @@ const DXGISupport &GetDXGISupport(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL feat } // namespace d3d11 } // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_DXGI_SUPPORT_TABLE_H_ 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 f073e9f46f..ce4edd26db 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp @@ -9,14 +9,15 @@ #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + #include "libANGLE/formatutils.h" -#include "libANGLE/renderer/d3d/copyimage.h" #include "libANGLE/renderer/d3d/d3d11/copyvertex.h" +#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.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/Renderer.h" namespace rx { @@ -24,559 +25,388 @@ namespace rx namespace d3d11 { -typedef std::map DXGIToESFormatMap; - -inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +bool SupportsMipGen(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel) { - map->insert(std::make_pair(key, value)); + const auto &support = GetDXGISupport(dxgiFormat, featureLevel); + ASSERT((support.optionallySupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) == 0); + return ((support.alwaysSupportedFlags & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0); } -static DXGIToESFormatMap BuildDXGIToESFormatMap() +DXGIFormatSize::DXGIFormatSize(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight) + : pixelBytes(pixelBits / 8), blockWidth(blockWidth), blockHeight(blockHeight) { - DXGIToESFormatMap map; - - AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); - - AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); - AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); - AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); - AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); - 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; } -struct D3D11FastCopyFormat +const DXGIFormatSize &GetDXGIFormatSizeInfo(DXGI_FORMAT format) { - GLenum destFormat; - GLenum destType; - ColorCopyFunction copyFunction; - - D3D11FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) - : destFormat(destFormat), destType(destType), copyFunction(copyFunction) - { } - - bool operator<(const D3D11FastCopyFormat& other) const + static const DXGIFormatSize sizeUnknown(0, 0, 0); + static const DXGIFormatSize size128(128, 1, 1); + static const DXGIFormatSize size96(96, 1, 1); + static const DXGIFormatSize size64(64, 1, 1); + static const DXGIFormatSize size32(32, 1, 1); + static const DXGIFormatSize size16(16, 1, 1); + static const DXGIFormatSize size8(8, 1, 1); + static const DXGIFormatSize sizeBC1(64, 4, 4); + static const DXGIFormatSize sizeBC2(128, 4, 4); + static const DXGIFormatSize sizeBC3(128, 4, 4); + static const DXGIFormatSize sizeBC4(64, 4, 4); + static const DXGIFormatSize sizeBC5(128, 4, 4); + static const DXGIFormatSize sizeBC6H(128, 4, 4); + static const DXGIFormatSize sizeBC7(128, 4, 4); + switch (format) { - return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + case DXGI_FORMAT_UNKNOWN: + return sizeUnknown; + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return size128; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return size96; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return size64; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + return size32; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + return size16; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return size8; + case DXGI_FORMAT_R1_UNORM: + UNREACHABLE(); + return sizeUnknown; + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + return size32; + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return sizeBC1; + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return sizeBC2; + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return sizeBC3; + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return sizeBC4; + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + return sizeBC5; + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + return size16; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return size32; + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + return sizeBC6H; + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return sizeBC7; + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_YUY2: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + case DXGI_FORMAT_NV11: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + UNREACHABLE(); + return sizeUnknown; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return size16; + default: + UNREACHABLE(); + return sizeUnknown; } -}; - -typedef std::multimap D3D11FastCopyMap; - -static D3D11FastCopyMap BuildFastCopyMap() -{ - D3D11FastCopyMap map; - - map.insert(std::make_pair(DXGI_FORMAT_B8G8R8A8_UNORM, D3D11FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); - - return map; -} - -struct DXGIColorFormatInfo -{ - size_t redBits; - size_t greenBits; - size_t blueBits; - - size_t luminanceBits; - - size_t alphaBits; - size_t sharedBits; -}; - -typedef std::map ColorFormatInfoMap; -typedef std::pair ColorFormatInfoPair; - -static inline void InsertDXGIColorFormatInfo(ColorFormatInfoMap *map, DXGI_FORMAT format, size_t redBits, size_t greenBits, - size_t blueBits, size_t alphaBits, size_t sharedBits) -{ - DXGIColorFormatInfo info; - info.redBits = redBits; - info.greenBits = greenBits; - info.blueBits = blueBits; - info.alphaBits = alphaBits; - info.sharedBits = sharedBits; - - map->insert(std::make_pair(format, info)); -} - -static ColorFormatInfoMap BuildColorFormatInfoMap() -{ - ColorFormatInfoMap map; - - // | DXGI format | R | G | B | A | S | - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_A8_UNORM, 0, 0, 0, 8, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UNORM, 8, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UNORM, 8, 8, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 8, 8, 8, 8, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, 8, 8, 8, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 8, 8, 8, 8, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SNORM, 8, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SNORM, 8, 8, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 8, 8, 8, 8, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UINT, 8, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_UINT, 16, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_UINT, 32, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UINT, 8, 8, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_UINT, 16, 16, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_UINT, 32, 32, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_UINT, 32, 32, 32, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UINT, 8, 8, 8, 8, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_UINT, 16, 16, 16, 16, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_UINT, 32, 32, 32, 32, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SINT, 8, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_SINT, 16, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_SINT, 32, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SINT, 8, 8, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_SINT, 16, 16, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_SINT, 32, 32, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_SINT, 32, 32, 32, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SINT, 8, 8, 8, 8, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_SINT, 16, 16, 16, 16, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_SINT, 32, 32, 32, 32, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 10, 10, 10, 2, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UINT, 10, 10, 10, 2, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_FLOAT, 16, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_FLOAT, 16, 16, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 16, 16, 16, 16, 0); - - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_FLOAT, 32, 32, 0, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_FLOAT, 32, 32, 32, 0, 0); - InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 32, 32, 32, 32, 0); - - 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; -} - -struct DXGIDepthStencilInfo -{ - unsigned int depthBits; - unsigned int depthOffset; - unsigned int stencilBits; - unsigned int stencilOffset; -}; - -typedef std::map DepthStencilInfoMap; -typedef std::pair DepthStencilInfoPair; - -static inline void InsertDXGIDepthStencilInfo(DepthStencilInfoMap *map, DXGI_FORMAT format, unsigned int depthBits, - unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) -{ - DXGIDepthStencilInfo info; - info.depthBits = depthBits; - info.depthOffset = depthOffset; - info.stencilBits = stencilBits; - info.stencilOffset = stencilOffset; - - map->insert(std::make_pair(format, info)); } -static DepthStencilInfoMap BuildDepthStencilInfoMap() +constexpr VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), nativeFormat(DXGI_FORMAT_UNKNOWN), copyFunction(nullptr) { - DepthStencilInfoMap map; - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_TYPELESS, 16, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_UNORM, 16, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D16_UNORM, 16, 0, 0, 0); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24G8_TYPELESS, 24, 0, 8, 24); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 24, 0, 8, 24); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 24, 0, 8, 24); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_TYPELESS, 32, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT, 32, 0, 0, 0); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 32, 0, 8, 32); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 32, 0, 8, 32); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, 0, 8, 32); - - return map; -} - -typedef std::map DXGIFormatInfoMap; - -DXGIFormat::DXGIFormat() - : pixelBytes(0), - blockWidth(0), - blockHeight(0), - redBits(0), - greenBits(0), - blueBits(0), - alphaBits(0), - sharedBits(0), - depthBits(0), - depthOffset(0), - stencilBits(0), - stencilOffset(0), - internalFormat(GL_NONE), - componentType(GL_NONE), - mipGenerationFunction(NULL), - colorReadFunction(NULL), - 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 +constexpr VertexFormat::VertexFormat(VertexConversionType conversionTypeIn, + DXGI_FORMAT nativeFormatIn, + VertexCopyFunction copyFunctionIn) + : conversionType(conversionTypeIn), nativeFormat(nativeFormatIn), copyFunction(copyFunctionIn) { - FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); - return (iter != fastCopyFunctions.end()) ? iter->second : NULL; } -void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, - GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc, NativeMipmapGenerationSupportFunction nativeMipmapSupport) +const VertexFormat *GetVertexFormatInfo_FL_9_3(gl::VertexFormatType vertexFormatType) { - DXGIFormat info; - info.pixelBytes = pixelBits / 8; - info.blockWidth = blockWidth; - info.blockHeight = blockHeight; - - static const ColorFormatInfoMap colorInfoMap = BuildColorFormatInfoMap(); - ColorFormatInfoMap::const_iterator colorInfoIter = colorInfoMap.find(dxgiFormat); - if (colorInfoIter != colorInfoMap.end()) - { - const DXGIColorFormatInfo &colorInfo = colorInfoIter->second; - 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(); - DepthStencilInfoMap::const_iterator dsInfoIter = dsInfoMap.find(dxgiFormat); - if (dsInfoIter != dsInfoMap.end()) - { - const DXGIDepthStencilInfo &dsInfo = dsInfoIter->second; - info.depthBits = dsInfo.depthBits; - info.depthOffset = dsInfo.depthOffset; - info.stencilBits = dsInfo.stencilBits; - info.stencilOffset = dsInfo.stencilOffset; - } - - static const DXGIToESFormatMap dxgiToESMap = BuildDXGIToESFormatMap(); - DXGIToESFormatMap::const_iterator dxgiToESIter = dxgiToESMap.find(dxgiFormat); - info.internalFormat = (dxgiToESIter != dxgiToESMap.end()) ? dxgiToESIter->second : GL_NONE; - - info.componentType = componentType; - - info.mipGenerationFunction = mipFunc; - info.colorReadFunction = readFunc; + // D3D11 Feature Level 9_3 doesn't support as many formats for vertex buffer resource as Feature + // Level 10_0+. + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff471324(v=vs.85).aspx - static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); - std::pair fastCopyIter = fastCopyMap.equal_range(dxgiFormat); - for (D3D11FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + switch (vertexFormatType) { - 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)); -} - -// A map to determine the pixel size and mipmap generation function of a given DXGI format -static DXGIFormatInfoMap BuildDXGIFormatInfoMap() -{ - DXGIFormatInfoMap map; - - // | 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); + // GL_BYTE -- unnormalized + case gl::VERTEX_FORMAT_SBYTE1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &Copy8SintTo16SintVertexData<1, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &Copy8SintTo16SintVertexData<2, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE3: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, + &Copy8SintTo16SintVertexData<3, 4>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE4: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, + &Copy8SintTo16SintVertexData<4, 4>); + return &info; + } - 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); + // GL_BYTE -- normalized + case gl::VERTEX_FORMAT_SBYTE1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &Copy8SnormTo16SnormVertexData<1, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &Copy8SnormTo16SnormVertexData<2, 2>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE3_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, + &Copy8SnormTo16SnormVertexData<3, 4>); + return &info; + } + case gl::VERTEX_FORMAT_SBYTE4_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, + &Copy8SnormTo16SnormVertexData<4, 4>); + return &info; + } - 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); + // GL_UNSIGNED_BYTE -- un-normalized + // NOTE: 3 and 4 component unnormalized GL_UNSIGNED_BYTE should use the default format + // table. + case gl::VERTEX_FORMAT_UBYTE1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); + return &info; + } + case gl::VERTEX_FORMAT_UBYTE2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); + return &info; + } - 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); + // GL_UNSIGNED_BYTE -- normalized + // NOTE: 3 and 4 component normalized GL_UNSIGNED_BYTE should use the default format table. - 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); + // GL_UNSIGNED_BYTE -- normalized + case gl::VERTEX_FORMAT_UBYTE1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); + return &info; + } + case gl::VERTEX_FORMAT_UBYTE2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); + return &info; + } - 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); + // GL_SHORT -- un-normalized + // NOTE: 2, 3 and 4 component unnormalized GL_SHORT should use the default format table. + case gl::VERTEX_FORMAT_SSHORT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, + &CopyNativeVertexData); + return &info; + } - 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); + // GL_SHORT -- normalized + // NOTE: 2, 3 and 4 component normalized GL_SHORT should use the default format table. + case gl::VERTEX_FORMAT_SSHORT1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, + &CopyNativeVertexData); + return &info; + } - 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); + // GL_UNSIGNED_SHORT -- un-normalized + case gl::VERTEX_FORMAT_USHORT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT2: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT3: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT4: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); + return &info; + } - // 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); + // GL_UNSIGNED_SHORT -- normalized + case gl::VERTEX_FORMAT_USHORT1_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT2_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT3_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, + &CopyTo32FVertexData); + return &info; + } + case gl::VERTEX_FORMAT_USHORT4_NORM: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); + return &info; + } - // Useful formats for vertex buffers - 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); + // GL_FIXED + // TODO: Add test to verify that this works correctly. + // NOTE: 2, 3 and 4 component GL_FIXED should use the default format table. + case gl::VERTEX_FORMAT_FIXED1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &Copy32FixedTo32FVertexData<1, 2>); + return &info; + } - return map; -} + // GL_FLOAT + // TODO: Add test to verify that this works correctly. + // NOTE: 2, 3 and 4 component GL_FLOAT should use the default format table. + case gl::VERTEX_FORMAT_FLOAT1: + { + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, + &CopyNativeVertexData); + return &info; + } -const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format) -{ - static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); - DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); - if (iter != infoMap.end()) - { - return iter->second; - } - else - { - static DXGIFormat defaultInfo; - return defaultInfo; + default: + return nullptr; } } -typedef std::map D3D11VertexFormatInfoMap; -typedef std::pair D3D11VertexFormatPair; - -VertexFormat::VertexFormat() - : conversionType(VERTEX_CONVERT_NONE), - nativeFormat(DXGI_FORMAT_UNKNOWN), - copyFunction(NULL) -{ -} - -VertexFormat::VertexFormat(VertexConversionType conversionTypeIn, - DXGI_FORMAT nativeFormatIn, - VertexCopyFunction copyFunctionIn) - : conversionType(conversionTypeIn), - nativeFormat(nativeFormatIn), - copyFunction(copyFunctionIn) -{ -} - -static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, - GLenum inputType, - GLboolean normalized, - GLuint componentCount, - VertexConversionType conversionType, - DXGI_FORMAT nativeFormat, - VertexCopyFunction copyFunction) -{ - gl::VertexFormatType formatType = gl::GetVertexFormatType(inputType, normalized, componentCount, false); - - VertexFormat info; - info.conversionType = conversionType; - info.nativeFormat = nativeFormat; - info.copyFunction = copyFunction; - - map->insert(D3D11VertexFormatPair(formatType, info)); -} - -static D3D11VertexFormatInfoMap BuildD3D11_FL9_3VertexFormatInfoOverrideMap() -{ - // D3D11 Feature Level 9_3 doesn't support as many formats for vertex buffer resource as Feature Level 10_0+. - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff471324(v=vs.85).aspx - - D3D11VertexFormatInfoMap map; - - // GL_BYTE -- unnormalized - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<1, 2>); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<2, 2>); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<3, 4>); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<4, 4>); - - // GL_BYTE -- normalized - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<1, 2>); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<2, 2>); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<3, 4>); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<4, 4>); - - // GL_UNSIGNED_BYTE -- unnormalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - // NOTE: 3 and 4 component unnormalized GL_UNSIGNED_BYTE should use the default format table. - - // GL_UNSIGNED_BYTE -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); - // NOTE: 3 and 4 component normalized GL_UNSIGNED_BYTE should use the default format table. - - // GL_SHORT -- unnormalized - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); - // NOTE: 2, 3 and 4 component unnormalized GL_SHORT should use the default format table. - - // GL_SHORT -- normalized - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); - // NOTE: 2, 3 and 4 component normalized GL_SHORT should use the default format table. - - // GL_UNSIGNED_SHORT -- unnormalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); - - // GL_UNSIGNED_SHORT -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); - - // GL_FIXED - // TODO: Add test to verify that this works correctly. - AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<1, 2>); - // NOTE: 2, 3 and 4 component GL_FIXED should use the default format table. - - // GL_FLOAT - // TODO: Add test to verify that this works correctly. - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); - // NOTE: 2, 3 and 4 component GL_FLOAT should use the default format table. - - return map; -} - const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D3D_FEATURE_LEVEL featureLevel) { if (featureLevel == D3D_FEATURE_LEVEL_9_3) { - static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override = - BuildD3D11_FL9_3VertexFormatInfoOverrideMap(); - - // First see if the format has a special mapping for FL9_3 - auto iter = vertexFormatMapFL9_3Override.find(vertexFormatType); - if (iter != vertexFormatMapFL9_3Override.end()) + const VertexFormat *result = GetVertexFormatInfo_FL_9_3(vertexFormatType); + if (result) { - return iter->second; + return *result; } } @@ -589,354 +419,418 @@ const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D // GL_BYTE -- un-normalized case gl::VERTEX_FORMAT_SBYTE1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, + &CopyNativeVertexData); return info; } // GL_BYTE -- normalized case gl::VERTEX_FORMAT_SBYTE1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_BYTE -- un-normalized case gl::VERTEX_FORMAT_UBYTE1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_BYTE -- normalized case gl::VERTEX_FORMAT_UBYTE1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, + &CopyNativeVertexData); return info; } // GL_SHORT -- un-normalized case gl::VERTEX_FORMAT_SSHORT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, + &CopyNativeVertexData); return info; } // GL_SHORT -- normalized case gl::VERTEX_FORMAT_SSHORT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_SHORT -- un-normalized case gl::VERTEX_FORMAT_USHORT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_SHORT -- normalized case gl::VERTEX_FORMAT_USHORT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, + &CopyNativeVertexData); return info; } // GL_INT -- un-normalized case gl::VERTEX_FORMAT_SINT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, + &CopyNativeVertexData); return info; } // GL_INT -- normalized case gl::VERTEX_FORMAT_SINT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); return info; } // GL_UNSIGNED_INT -- un-normalized case gl::VERTEX_FORMAT_UINT1: { - static const VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, + &CopyNativeVertexData); return info; } // GL_UNSIGNED_INT -- normalized case gl::VERTEX_FORMAT_UINT1_NORM: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, 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); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &CopyTo32FVertexData); return info; } // GL_FIXED case gl::VERTEX_FORMAT_FIXED1: { - static const VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>); + static constexpr 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>); + static constexpr 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>); + static constexpr 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>); + static constexpr VertexFormat info(VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, + &Copy32FixedTo32FVertexData<4, 4>); return info; } // GL_HALF_FLOAT case gl::VERTEX_FORMAT_HALF1: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, + &CopyNativeVertexData); return info; } // GL_FLOAT case gl::VERTEX_FORMAT_FLOAT1: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, + &CopyNativeVertexData); return info; } @@ -947,157 +841,183 @@ const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D // GL_BYTE case gl::VERTEX_FORMAT_SBYTE1_INT: { - static const VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr 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); + static constexpr VertexFormat info(VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, + &CopyNativeVertexData); return info; } default: { - static const VertexFormat info; + static constexpr VertexFormat info; return info; } } } -} +} // namespace d3d11 -} +} // namespace rx 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 7b97527140..883d338377 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h @@ -15,6 +15,7 @@ #include "common/platform.h" #include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" namespace rx @@ -24,58 +25,47 @@ struct Renderer11DeviceCaps; namespace d3d11 { -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; -typedef bool (*NativeMipmapGenerationSupportFunction)(D3D_FEATURE_LEVEL); +// A texture might be stored as DXGI_FORMAT_R16_TYPELESS but store integer components, +// which are accessed through an DXGI_FORMAT_R16_SINT view. It's easy to write code which queries +// information about the wrong format. Therefore, use of this should be avoided where possible. -struct DXGIFormat +bool SupportsMipGen(DXGI_FORMAT dxgiFormat, D3D_FEATURE_LEVEL featureLevel); + +struct DXGIFormatSize { - DXGIFormat(); + DXGIFormatSize(GLuint pixelBits, GLuint blockWidth, GLuint blockHeight); GLuint pixelBytes; GLuint blockWidth; GLuint blockHeight; - - GLuint redBits; - GLuint greenBits; - GLuint blueBits; - GLuint alphaBits; - GLuint sharedBits; - - GLuint depthBits; - GLuint depthOffset; - GLuint stencilBits; - GLuint stencilOffset; - - GLenum internalFormat; - GLenum componentType; - - MipGenerationFunction mipGenerationFunction; - ColorReadFunction colorReadFunction; - - FastCopyFunctionMap fastCopyFunctions; - - NativeMipmapGenerationSupportFunction nativeMipmapSupport; - - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; }; -const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format); +const DXGIFormatSize &GetDXGIFormatSizeInfo(DXGI_FORMAT format); -struct VertexFormat +struct VertexFormat : private angle::NonCopyable { - VertexFormat(); - VertexFormat(VertexConversionType conversionType, - DXGI_FORMAT nativeFormat, - VertexCopyFunction copyFunction); + constexpr VertexFormat(); + constexpr VertexFormat(VertexConversionType conversionType, + DXGI_FORMAT nativeFormat, + VertexCopyFunction copyFunction); VertexConversionType conversionType; DXGI_FORMAT nativeFormat; VertexCopyFunction copyFunction; }; + const VertexFormat &GetVertexFormatInfo(gl::VertexFormatType vertexFormatType, D3D_FEATURE_LEVEL featureLevel); +// Auto-generated in dxgi_format_map_autogen.cpp. +GLenum GetComponentType(DXGI_FORMAT dxgiFormat); + } // namespace d3d11 +namespace d3d11_angle +{ +const angle::Format &GetFormat(DXGI_FORMAT dxgiFormat); +} + } // 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 deleted file mode 100644 index e69de29bb2..0000000000 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 deleted file mode 100644 index adb20a5e60..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// -// 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 deleted file mode 100644 index 2d538e1d82..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/internal_format_initializer_table.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// 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 deleted file mode 100644 index c85393e06b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_data.json +++ /dev/null @@ -1,1116 +0,0 @@ -{ - "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 deleted file mode 100644 index b17062f68d..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// 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 deleted file mode 100644 index acb48b9573..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/load_functions_table_autogen.cpp +++ /dev/null @@ -1,2098 +0,0 @@ -// 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 a1175db9af..d059b36120 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 @@ -12,369 +12,414 @@ #include #include "common/debug.h" -#include "libANGLE/formatutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.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/d3d/WorkaroundsD3D.h" - -#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY -# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 -#endif -#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT -# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 -#endif -#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT -# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 -#endif -#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT -# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 -#endif -#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT -# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION -# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 -#endif -#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION -# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION -# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 -#endif -#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION -# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 -#endif -#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION -# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 -#endif -#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION -# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 -#endif -#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 -#endif -#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP -# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 -#endif -#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP -# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 -#endif -#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT -# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 -#endif -#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT -# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 -#endif -#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT -# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 -#endif -#ifndef D3D11_SO_BUFFER_SLOT_COUNT -# define D3D11_SO_BUFFER_SLOT_COUNT 4 -#endif -#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT -# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 -#endif -#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT -# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 -#endif -#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 -#endif -#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE -# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 -#endif -#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT -# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 -#endif -#ifndef D3D11_PS_INPUT_REGISTER_COUNT -# define D3D11_PS_INPUT_REGISTER_COUNT 32 -#endif -#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT -# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 -#endif -#if defined(ANGLE_MINGW32_COMPAT) -static const IID WKPDID_D3DDebugObjectName = { 0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00 }; -#endif +#include "libANGLE/renderer/driver_utils.h" +#include "platform/Platform.h" +#include "platform/WorkaroundsD3D.h" namespace rx { -namespace gl_d3d11 +namespace d3d11_gl { - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +namespace { - D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; +// Standard D3D sample positions from +// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx +using SamplePositionsArray = std::array; +static constexpr std::array kSamplePositions = { + {{{0.5f, 0.5f}}, + {{0.75f, 0.75f, 0.25f, 0.25f}}, + {{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}}, + {{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f, + 0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}}, + {{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f, + 0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f, + 0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f, + 0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}}; - switch (glBlend) +// 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) { - case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; - case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; - case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; - case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; - case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; - case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; - case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; - case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; - case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; - case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; - case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; - default: UNREACHABLE(); } - return d3dBlend; -} + bool query(DXGI_FORMAT dxgiFormat, UINT supportMask) + { + if (dxgiFormat == DXGI_FORMAT_UNKNOWN) + return false; -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) -{ - D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + auto dxgiSupport = d3d11::GetDXGISupport(dxgiFormat, mFeatureLevel); - switch (glBlendOp) - { - case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; - case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; - case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; - case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; - case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; - default: UNREACHABLE(); + 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" << std::hex << dxgiFormat; + } + } + + return ((supportedBits & supportMask) == supportMask); } - return d3dBlendOp; -} + private: + ID3D11Device *mDevice; + D3D_FEATURE_LEVEL mFeatureLevel; +}; -UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +gl::TextureCaps GenerateTextureFormatCaps(gl::Version maxClientVersion, + GLenum internalFormat, + ID3D11Device *device, + const Renderer11DeviceCaps &renderer11DeviceCaps) { - UINT8 mask = 0; - if (red) + gl::TextureCaps textureCaps; + + DXGISupportHelper support(device, renderer11DeviceCaps.featureLevel); + const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); + + const gl::InternalFormat &internalFormatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + + UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D; + if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0) { - mask |= D3D11_COLOR_WRITE_ENABLE_RED; + texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE; + if (maxClientVersion.major > 2) + { + texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + } } - if (green) + + 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)); + + DXGI_FORMAT renderFormat = DXGI_FORMAT_UNKNOWN; + if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { - mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + renderFormat = formatInfo.dsvFormat; } - if (blue) + else if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { - mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + renderFormat = formatInfo.rtvFormat; } - if (alpha) + if (renderFormat != DXGI_FORMAT_UNKNOWN && + support.query(renderFormat, D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) { - mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; - } - return mask; -} - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) -{ - D3D11_CULL_MODE cull = D3D11_CULL_NONE; + // Assume 1x + textureCaps.sampleCounts.insert(1); - if (cullEnabled) - { - switch (cullMode) + for (unsigned int sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; + sampleCount *= 2) { - case GL_FRONT: cull = D3D11_CULL_FRONT; break; - case GL_BACK: cull = D3D11_CULL_BACK; break; - case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; - default: UNREACHABLE(); + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(renderFormat, sampleCount, + &qualityCount))) + { + // Assume we always support lower sample counts + if (qualityCount == 0) + { + break; + } + textureCaps.sampleCounts.insert(sampleCount); + } } } - else - { - cull = D3D11_CULL_NONE; - } - return cull; + return textureCaps; } -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) { - D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; - switch (comparison) + switch (featureLevel) { - case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; - case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; - case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; - case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; - case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; - case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; - case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; - case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; - default: UNREACHABLE(); - } + 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 true; - return d3dComp; + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; + } } -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) { - return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_MAX_MAXANISOTROPY; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + return 16; + + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + + default: + UNREACHABLE(); + return 0; + } } -UINT8 ConvertStencilMask(GLuint stencilmask) +bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) { - return static_cast(stencilmask); + 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 true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateQuery + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + return true; + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; + } } -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) { - D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateQuery - switch (stencilOp) + switch (featureLevel) { - case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; - case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; - case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; - case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; - case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; - case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; - case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; - case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; - default: UNREACHABLE(); - } + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return true; - return d3dStencilOp; + default: + UNREACHABLE(); + return false; + } } -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) { - bool comparison = comparisonMode != GL_NONE; + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateInputLayout - if (maxAnisotropy > 1.0f) - { - return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); - } - else + switch (featureLevel) { - D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; - D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; - switch (minFilter) - { - case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } + 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 true; + + // Feature Level 9_3 supports instancing, but slot 0 in the input layout must not be + // instanced. + // D3D9 has a similar restriction, where stream 0 must not be instanced. + // This restriction can be worked around by remapping any non-instanced slot to slot + // 0. + // This works because HLSL uses shader semantics to match the vertex inputs to the + // elements in the input layout, rather than the slots. + // Note that we only support instancing via ANGLE_instanced_array on 9_3, since 9_3 + // doesn't support OpenGL ES 3.0 + case D3D_FEATURE_LEVEL_9_3: + return true; - D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; - switch (magFilter) - { - case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; - return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast(comparison)); + default: + UNREACHABLE(); + return false; } } -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) { - switch (wrap) + switch (featureLevel) { - case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; - case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; - case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; - default: UNREACHABLE(); - } + 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 true; - return D3D11_TEXTURE_ADDRESS_WRAP; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; + } } -D3D11_QUERY ConvertQueryType(GLenum queryType) +bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) { - switch (queryType) + switch (featureLevel) { - 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; + 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 true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; } } -} // namespace gl_d3d11 - -namespace d3d11_gl +bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) { + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that + // shader model + // ps_2_x is required for the ddx (and other derivative functions). -namespace -{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that + // feature level + // 9.3 supports shader model ps_2_x. -// 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) + 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: + case D3D_FEATURE_LEVEL_9_3: + return true; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return false; + + default: + UNREACHABLE(); + return false; } +} - bool query(DXGI_FORMAT dxgiFormat, UINT supportMask) +bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) { - if (dxgiFormat == DXGI_FORMAT_UNKNOWN) + 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 true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; - auto dxgiSupport = d3d11::GetDXGISupport(dxgiFormat, mFeatureLevel); + default: + UNREACHABLE(); + return false; + } +} - UINT supportedBits = dxgiSupport.alwaysSupportedFlags; +size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx + // ID3D11Device::CreateInputLayout - 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); - } - } + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; - return ((supportedBits & supportMask) == supportMask); - } + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; - private: - ID3D11Device *mDevice; - D3D_FEATURE_LEVEL mFeatureLevel; -}; + case D3D_FEATURE_LEVEL_9_3: + return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; -} // anonymous namespace + default: + UNREACHABLE(); + return 0; + } +} -unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return 0; + return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; case D3D_FEATURE_LEVEL_9_3: + return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return 3; // dx_ViewAdjust, dx_ViewCoords and dx_ViewScale + return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; default: UNREACHABLE(); @@ -382,20 +427,23 @@ unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) } } -unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: - return 0; + return D3D10_REQ_TEXTURECUBE_DIMENSION; case D3D_FEATURE_LEVEL_9_3: + return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: - return 3; + return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; default: UNREACHABLE(); @@ -403,757 +451,829 @@ unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) } } -GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximum2DTextureArraySize(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 3; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 2; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; + + default: + UNREACHABLE(); + return 0; } } -static gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device, const Renderer11DeviceCaps &renderer11DeviceCaps) +size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) { - gl::TextureCaps textureCaps; + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - DXGISupportHelper support(device, renderer11DeviceCaps.featureLevel); - const d3d11::TextureFormat &formatInfo = - d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - UINT texSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D; - if (internalFormatInfo.depthBits == 0 && internalFormatInfo.stencilBits == 0) + default: + UNREACHABLE(); + return 0; + } +} + +size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) { - texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURECUBE; - if (maxClientVersion > 2) - { - texSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; - } + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_VIEWPORT_BOUNDS_MAX; + + // No constants for D3D11 Feature Level 9 viewport size limits, use the maximum + // texture sizes + case D3D_FEATURE_LEVEL_9_3: + return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: + UNREACHABLE(); + return 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)); +size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +{ + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since + // that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, + "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, + "Unexpected D3D11 constant value."); - if (support.query(formatInfo.renderFormat, D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) + switch (featureLevel) { - // Assume 1x - textureCaps.sampleCounts.insert(1); + 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 std::numeric_limits::max(); - for (unsigned int sampleCount = 2; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; - sampleCount *= 2) - { - UINT 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); - } - } - } + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - return textureCaps; + default: + UNREACHABLE(); + return 0; + } } -static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) { + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since + // that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + 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 true; + 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 std::numeric_limits::max(); - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_10_0: + return D3D10_STANDARD_VERTEX_ELEMENT_COUNT; - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return 16; + // From http://http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + // "Max Input Slots" + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 16; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + default: + UNREACHABLE(); + return 0; + } +} + +size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + // 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 - d3d11_gl::GetReservedVertexUniformVectors(featureLevel); - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexUniformBlocks(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 true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return true; - case D3D_FEATURE_LEVEL_9_1: return false; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + // According to The OpenGL ES Shading Language specifications + // (Language Version 1.00 section 10.16, Language Version 3.10 section 12.21) + // built-in special variables (e.g. gl_FragCoord, or gl_PointCoord) + // which are statically used in the shader should be included in the variable packing + // algorithm. + // Therefore, we should not reserve output vectors for them. 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: - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return true; + // 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. + 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 2; + + // Just reserve dx_Position on Feature Level 9, since we don't ever need to output + // gl_Position. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 1; - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, + "Unexpected D3D11 constant value."); 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 true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - // Feature Level 9_3 supports instancing, but slot 0 in the input layout must not be instanced. - // D3D9 has a similar restriction, where stream 0 must not be instanced. - // This restriction can be worked around by remapping any non-instanced slot to slot 0. - // This works because HLSL uses shader semantics to match the vertex inputs to the elements in the input layout, rather than the slots. - // Note that we only support instancing via ANGLE_instanced_array on 9_3, since 9_3 doesn't support OpenGL ES 3.0 - case D3D_FEATURE_LEVEL_9_3: return true; + case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_10_0: + return D3D10_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 8 - GetReservedVertexOutputVectors(featureLevel); - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumVertexTextureUnits(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 true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // Vertex textures not supported on D3D11 Feature Level 9 according to + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx + // ID3D11DeviceContext::VSSetSamplers and ID3D11DeviceContext::VSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) { + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass 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 true; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; - - default: UNREACHABLE(); return false; - } -} - -static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) -{ - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model - // ps_2_x is required for the ddx (and other derivative functions). + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level - // 9.3 supports shader model ps_2_x. + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - 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: - case D3D_FEATURE_LEVEL_9_3: return true; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // 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 - d3d11_gl::GetReservedFragmentUniformVectors(featureLevel); - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelUniformBlocks(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 true; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return false; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout - switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: + return 8 - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 8 - GetReservedVertexOutputVectors(featureLevel); - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx + // ID3D11DeviceContext::PSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 16; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +std::array GetMaxComputeWorkGroupCount(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_TEXTURECUBE_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return {{D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, + D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, + D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION}}; + break; + default: + return {{0, 0, 0}}; } } -static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +std::array GetMaxComputeWorkGroupSize(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_ARRAY_AXIS_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return {{D3D11_CS_THREAD_GROUP_MAX_X, D3D11_CS_THREAD_GROUP_MAX_Y, + D3D11_CS_THREAD_GROUP_MAX_Z}}; + break; + default: + return {{0, 0, 0}}; } } -static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaxComputeWorkGroupInvocations(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; + default: + return 0; } } -static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; - - // No constants for D3D11 Feature Level 9 viewport size limits, use the maximum texture sizes - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + default: + return 0; } } -static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { - // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's - // returned from glGetInteger - static_assert(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); - static_assert(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); - 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 std::numeric_limits::max(); - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - + d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT; + default: + return 0; } } -static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeTextureUnits(D3D_FEATURE_LEVEL featureLevel) { - // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's - // returned from glGetInteger - static_assert(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); - static_assert(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); - 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 std::numeric_limits::max(); - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + default: + return 0; } } -static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumImageUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; - case D3D_FEATURE_LEVEL_10_0: return D3D10_STANDARD_VERTEX_ELEMENT_COUNT; - - // From http://http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx "Max Input Slots" - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 16; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + // TODO(xinghua.cao@intel.com): Get a more accurate limit. For now using + // the minimum requirement for GLES 3.1. + return 4; + default: + return 0; } } -static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumComputeImageUniforms(D3D_FEATURE_LEVEL featureLevel) { - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - // 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 - d3d11_gl::GetReservedVertexUniformVectors(featureLevel); - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + // TODO(xinghua.cao@intel.com): Get a more accurate limit. For now using + // the minimum requirement for GLES 3.1. + return 4; + default: + return 0; } } -static size_t GetReservedVertexUniformBuffers() -{ - // Reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - // Uniform blocks not supported on D3D11 Feature Level 9 - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { - // According to The OpenGL ES Shading Language specifications - // (Language Version 1.00 section 10.16, Language Version 3.10 section 12.21) - // built-in special variables (e.g. gl_FragCoord, or gl_PointCoord) - // which are statically used in the shader should be included in the variable packing algorithm. - // Therefore, we should not reserve output vectors for them. - switch (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. - 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 2; + case D3D_FEATURE_LEVEL_11_1: + 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; - // Just reserve dx_Position on Feature Level 9, since we don't ever need to output gl_Position. - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 1; + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } - - return 1; } -static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) { - static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, "Unexpected D3D11 constant value."); + // Returns a size_t despite the limit being a GLuint64 because size_t is the maximum + // size of + // any buffer that could be allocated. + + const size_t bytesPerComponent = 4 * sizeof(float); switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - case D3D_FEATURE_LEVEL_10_0: return D3D10_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - // Use Shader Model 2.X limits - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + // Limits from http://msdn.microsoft.com/en-us/library/windows/desktop/ff476501.aspx + // remarks section + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 4096 * bytesPerComponent; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_SO_BUFFER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_1: + return D3D10_1_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_0: + return D3D10_SO_BUFFER_SLOT_COUNT; - // Vertex textures not supported on D3D11 Feature Level 9 according to - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx - // ID3D11DeviceContext::VSSetSamplers and ID3D11DeviceContext::VSSetShaderResources - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) { - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + 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 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return GetMaximumVertexOutputVectors(featureLevel) * 4; - // 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 - d3d11_gl::GetReservedFragmentUniformVectors(featureLevel); + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetReservedPixelUniformBuffers() -{ - // Reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return GetMaximumStreamOutputInterleavedComponents(featureLevel) / + GetMaximumStreamOutputBuffers(featureLevel); - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + // D3D 10 and 10.1 only allow one output per output slot if an output slot other + // than zero is used. + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 4; - // Uniform blocks not supported on D3D11 Feature Level 9 - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) +size_t GetMaximumRenderToBufferWindowSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH; - // Use Shader Model 2.X limits - case D3D_FEATURE_LEVEL_9_3: return 8 - GetReservedVertexOutputVectors(featureLevel); - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + // REQ_RENDER_TO_BUFFER_WINDOW_WIDTH not supported on D3D11 Feature Level 9, + // use the maximum texture sizes + case D3D_FEATURE_LEVEL_9_3: + return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) +IntelDriverVersion GetIntelDriverVersion(const Optional driverVersion) { - switch (featureLevel) - { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + if (!driverVersion.valid()) + return IntelDriverVersion(0); - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetShaderResources - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 16; - - default: UNREACHABLE(); return 0; - } + // According to http://www.intel.com/content/www/us/en/support/graphics-drivers/000005654.html, + // only the fourth part is necessary since it stands for the driver specific unique version + // number. + WORD part = LOWORD(driverVersion.value().LowPart); + return IntelDriverVersion(part); } -static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +} // anonymous namespace + +unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + 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; - // Sampling functions with offsets are not available below shader model 4.0. - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: 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; + default: + UNREACHABLE(); + return 0; } } -static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; + 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; - // Sampling functions with offsets are not available below shader model 4.0. - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: 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; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) +gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) { - // Returns a size_t despite the limit being a GLuint64 because size_t is the maximum size of - // any buffer that could be allocated. - - const size_t bytesPerComponent = 4 * sizeof(float); - switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return gl::Version(3, 1); + case D3D_FEATURE_LEVEL_10_1: + return gl::Version(3, 0); - // Limits from http://msdn.microsoft.com/en-us/library/windows/desktop/ff476501.aspx remarks section - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 4096 * bytesPerComponent; + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return gl::Version(2, 0); - default: UNREACHABLE(); return 0; + default: + UNREACHABLE(); + return gl::Version(0, 0); } } -static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetMaxViewportAndScissorRectanglesPerPipeline(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - 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; - case D3D_FEATURE_LEVEL_10_0: return D3D10_SO_BUFFER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 1; + default: + UNREACHABLE(); + return 0; } } -static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) +bool IsMultiviewSupported(D3D_FEATURE_LEVEL featureLevel) { + // The ANGLE_multiview extension can always be supported in D3D11 through geometry shaders. 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 GetMaximumVertexOutputVectors(featureLevel) * 4; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return true; + default: + return false; } } -static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) +unsigned int GetMaxSampleMaskWords(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / - GetMaximumStreamOutputBuffers(featureLevel); - - - // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used. - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 4; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; + // D3D10+ only allows 1 sample mask. + 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 1u; + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 0u; + default: + UNREACHABLE(); + return 0u; } } void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations) { - 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) + for (GLenum internalFormat : allFormats) { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device, renderer11DeviceCaps); - textureCapsMap->insert(*internalFormat, textureCaps); - - maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + gl::TextureCaps textureCaps = GenerateTextureFormatCaps( + GetMaximumClientVersion(featureLevel), internalFormat, device, renderer11DeviceCaps); + textureCapsMap->insert(internalFormat, textureCaps); - if (gl::GetInternalFormatInfo(*internalFormat).compressed) + if (gl::GetSizedInternalFormatInfo(internalFormat).compressed) { - caps->compressedTextureFormats.push_back(*internalFormat); + caps->compressedTextureFormats.push_back(internalFormat); } } @@ -1226,6 +1346,14 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons caps->maxVertexTextureImageUnits = static_cast(GetMaximumVertexTextureUnits(featureLevel)); + // Vertex Attribute Bindings are emulated on D3D11. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; + // Experimental testing confirmed there is no explicit limit on maximum buffer offset in D3D11. + caps->maxVertexAttribRelativeOffset = std::numeric_limits::max(); + // Experimental testing confirmed 2048 is the maximum stride that D3D11 can support on all + // platforms. + caps->maxVertexAttribStride = 2048; + // Fragment shader limits caps->maxFragmentUniformComponents = static_cast(GetMaximumPixelUniformVectors(featureLevel)) * 4; @@ -1239,108 +1367,504 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel); - // Aggregate shader limits - caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; - caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + // Compute shader limits + caps->maxComputeWorkGroupCount = GetMaxComputeWorkGroupCount(featureLevel); + caps->maxComputeWorkGroupSize = GetMaxComputeWorkGroupSize(featureLevel); + caps->maxComputeWorkGroupInvocations = + static_cast(GetMaxComputeWorkGroupInvocations(featureLevel)); + caps->maxComputeUniformComponents = + static_cast(GetMaximumComputeUniformVectors(featureLevel)) * 4; + caps->maxComputeUniformBlocks = + static_cast(GetMaximumComputeUniformBlocks(featureLevel)); + caps->maxComputeTextureImageUnits = + static_cast(GetMaximumComputeTextureUnits(featureLevel)); + caps->maxImageUnits = static_cast(GetMaximumImageUnits(featureLevel)); + caps->maxComputeImageUniforms = + static_cast(GetMaximumComputeImageUniforms(featureLevel)); + + // Aggregate shader limits + caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + + // TODO(oetuaho): Get a more accurate limit. For now using the minimum requirement for GLES 3.1. + caps->maxUniformLocations = 1024; + + // 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->maxCombinedComputeUniformComponents = + static_cast(caps->maxComputeUniformBlocks * (caps->maxUniformBlockSize / 4) + + caps->maxComputeUniformComponents); + caps->maxVaryingComponents = + static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; + caps->maxVaryingVectors = static_cast(GetMaximumVertexOutputVectors(featureLevel)); + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = + static_cast(GetMaximumStreamOutputInterleavedComponents(featureLevel)); + caps->maxTransformFeedbackSeparateAttributes = + static_cast(GetMaximumStreamOutputBuffers(featureLevel)); + caps->maxTransformFeedbackSeparateComponents = + static_cast(GetMaximumStreamOutputSeparateComponents(featureLevel)); + + // Defer the computation of multisample limits to Context::updateCaps() where max*Samples values + // are determined according to available sample counts for each individual format. + caps->maxSamples = std::numeric_limits::max(); + caps->maxColorTextureSamples = std::numeric_limits::max(); + caps->maxDepthTextureSamples = std::numeric_limits::max(); + caps->maxIntegerSamples = std::numeric_limits::max(); + + // Sample mask words limits + caps->maxSampleMaskWords = GetMaxSampleMaskWords(featureLevel); + + // Framebuffer limits + caps->maxFramebufferSamples = std::numeric_limits::max(); + caps->maxFramebufferWidth = + static_cast(GetMaximumRenderToBufferWindowSize(featureLevel)); + caps->maxFramebufferHeight = caps->maxFramebufferWidth; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = true; + extensions->mapBuffer = true; + extensions->mapBufferRange = true; + extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); + extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; + extensions->textureStorage = true; + extensions->textureFilterAnisotropic = true; + extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); + extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); + extensions->fence = GetEventQuerySupport(featureLevel); + extensions->disjointTimerQuery = true; + extensions->queryCounterBitsTimeElapsed = 64; + extensions->queryCounterBitsTimestamp = + 0; // Timestamps cannot be supported due to D3D11 limitations + extensions->robustness = true; + // Direct3D guarantees to return zero for any resource that is accessed out of bounds. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ff476332(v=vs.85).aspx + // and https://msdn.microsoft.com/en-us/library/windows/desktop/ff476900(v=vs.85).aspx + extensions->robustBufferAccessBehavior = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); + extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel); + extensions->fragDepth = true; + extensions->multiview = IsMultiviewSupported(featureLevel); + if (extensions->multiview) + { + extensions->maxViews = + std::min(static_cast(gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS), + std::min(static_cast(GetMaximum2DTextureArraySize(featureLevel)), + GetMaxViewportAndScissorRectanglesPerPipeline(featureLevel))); + } + 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->eglImageExternal = true; + extensions->eglImageExternalEssl3 = true; + extensions->eglStreamConsumerExternal = true; + extensions->unpackSubimage = true; + extensions->packSubimage = true; + extensions->lossyETCDecode = true; + extensions->syncQuery = GetEventQuerySupport(featureLevel); + extensions->copyTexture = true; + extensions->copyCompressedTexture = 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 +} + +void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy) +{ + size_t indexKey = static_cast(ceil(log(sampleCount))); + ASSERT(indexKey < kSamplePositions.size() && + (2 * index + 1) < kSamplePositions[indexKey].size()); + + xy[0] = kSamplePositions[indexKey][2 * index]; + xy[1] = kSamplePositions[indexKey][2 * index + 1]; +} + +} // namespace d3d11_gl + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +{ + D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; + + switch (glBlend) + { + case GL_ZERO: + d3dBlend = D3D11_BLEND_ZERO; + break; + case GL_ONE: + d3dBlend = D3D11_BLEND_ONE; + break; + case GL_SRC_COLOR: + d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); + break; + case GL_ONE_MINUS_SRC_COLOR: + d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); + break; + case GL_DST_COLOR: + d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); + break; + case GL_ONE_MINUS_DST_COLOR: + d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); + break; + case GL_SRC_ALPHA: + d3dBlend = D3D11_BLEND_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; + break; + case GL_DST_ALPHA: + d3dBlend = D3D11_BLEND_DEST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; + break; + case GL_CONSTANT_COLOR: + d3dBlend = D3D11_BLEND_BLEND_FACTOR; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; + break; + case GL_CONSTANT_ALPHA: + d3dBlend = D3D11_BLEND_BLEND_FACTOR; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; + break; + case GL_SRC_ALPHA_SATURATE: + d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; + break; + default: + UNREACHABLE(); + } + + return d3dBlend; +} + +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) +{ + D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + + switch (glBlendOp) + { + case GL_FUNC_ADD: + d3dBlendOp = D3D11_BLEND_OP_ADD; + break; + case GL_FUNC_SUBTRACT: + d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; + break; + case GL_FUNC_REVERSE_SUBTRACT: + d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; + break; + case GL_MIN: + d3dBlendOp = D3D11_BLEND_OP_MIN; + break; + case GL_MAX: + d3dBlendOp = D3D11_BLEND_OP_MAX; + break; + default: + UNREACHABLE(); + } + + return d3dBlendOp; +} + +UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + UINT8 mask = 0; + if (red) + { + mask |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (green) + { + mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (blue) + { + mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (alpha) + { + mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return mask; +} + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, gl::CullFaceMode cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case gl::CullFaceMode::Front: + cull = D3D11_CULL_FRONT; + break; + case gl::CullFaceMode::Back: + cull = D3D11_CULL_BACK; + break; + case gl::CullFaceMode::FrontAndBack: + cull = D3D11_CULL_NONE; + break; + default: + UNREACHABLE(); + } + } + else + { + cull = D3D11_CULL_NONE; + } + + return cull; +} + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +{ + D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; + switch (comparison) + { + case GL_NEVER: + d3dComp = D3D11_COMPARISON_NEVER; + break; + case GL_ALWAYS: + d3dComp = D3D11_COMPARISON_ALWAYS; + break; + case GL_LESS: + d3dComp = D3D11_COMPARISON_LESS; + break; + case GL_LEQUAL: + d3dComp = D3D11_COMPARISON_LESS_EQUAL; + break; + case GL_EQUAL: + d3dComp = D3D11_COMPARISON_EQUAL; + break; + case GL_GREATER: + d3dComp = D3D11_COMPARISON_GREATER; + break; + case GL_GEQUAL: + d3dComp = D3D11_COMPARISON_GREATER_EQUAL; + break; + case GL_NOTEQUAL: + d3dComp = D3D11_COMPARISON_NOT_EQUAL; + break; + default: + UNREACHABLE(); + } + + return d3dComp; +} - // 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; +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} - 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 = - static_cast(GetMaximumVertexOutputVectors(featureLevel)) * 4; - caps->maxVaryingVectors = static_cast(GetMaximumVertexOutputVectors(featureLevel)); - caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast(stencilmask); +} - // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = - static_cast(GetMaximumStreamOutputInterleavedComponents(featureLevel)); - caps->maxTransformFeedbackSeparateAttributes = - static_cast(GetMaximumStreamOutputBuffers(featureLevel)); - caps->maxTransformFeedbackSeparateComponents = - static_cast(GetMaximumStreamOutputSeparateComponents(featureLevel)); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; - // Multisample limits - caps->maxSamples = maxSamples; + switch (stencilOp) + { + case GL_ZERO: + d3dStencilOp = D3D11_STENCIL_OP_ZERO; + break; + case GL_KEEP: + d3dStencilOp = D3D11_STENCIL_OP_KEEP; + break; + case GL_REPLACE: + d3dStencilOp = D3D11_STENCIL_OP_REPLACE; + break; + case GL_INCR: + d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; + break; + case GL_DECR: + d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; + break; + case GL_INVERT: + d3dStencilOp = D3D11_STENCIL_OP_INVERT; + break; + case GL_INCR_WRAP: + d3dStencilOp = D3D11_STENCIL_OP_INCR; + break; + case GL_DECR_WRAP: + d3dStencilOp = D3D11_STENCIL_OP_DECR; + break; + default: + UNREACHABLE(); + } - // GL extension support - extensions->setTextureExtensionSupport(*textureCapsMap); - extensions->elementIndexUint = true; - extensions->getProgramBinary = true; - extensions->rgb8rgba8 = true; - extensions->readFormatBGRA = true; - extensions->pixelBufferObject = true; - extensions->mapBuffer = true; - extensions->mapBufferRange = true; - extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); - extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; - extensions->textureStorage = true; - extensions->textureFilterAnisotropic = true; - extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); - 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->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; + return d3dStencilOp; +} - // 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_FILTER ConvertFilter(GLenum minFilter, + GLenum magFilter, + float maxAnisotropy, + GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; - // D3D11 Feature Level 9_3 doesn't support alpha-to-coverage - limitations->noSampleAlphaToCoverageSupport = (renderer11DeviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + if (maxAnisotropy > 1.0f) + { + return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); + } + else + { + D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; + D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; + switch (minFilter) + { + case GL_NEAREST: + dxMin = D3D11_FILTER_TYPE_POINT; + dxMip = D3D11_FILTER_TYPE_POINT; + break; + case GL_LINEAR: + dxMin = D3D11_FILTER_TYPE_LINEAR; + dxMip = D3D11_FILTER_TYPE_POINT; + break; + case GL_NEAREST_MIPMAP_NEAREST: + dxMin = D3D11_FILTER_TYPE_POINT; + dxMip = D3D11_FILTER_TYPE_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + dxMin = D3D11_FILTER_TYPE_LINEAR; + dxMip = D3D11_FILTER_TYPE_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + dxMin = D3D11_FILTER_TYPE_POINT; + dxMip = D3D11_FILTER_TYPE_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + dxMin = D3D11_FILTER_TYPE_LINEAR; + dxMip = D3D11_FILTER_TYPE_LINEAR; + break; + default: + UNREACHABLE(); + } - // 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_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; + switch (magFilter) + { + case GL_NEAREST: + dxMag = D3D11_FILTER_TYPE_POINT; + break; + case GL_LINEAR: + dxMag = D3D11_FILTER_TYPE_LINEAR; + break; + default: + UNREACHABLE(); + } - // D3D11 has no concept of separate masks and refs for front and back faces in the depth stencil - // state. - limitations->noSeparateStencilRefsAndMasks = true; + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, + static_cast(comparison)); + } +} - // D3D11 cannot support constant color and alpha blend funcs together - limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + return D3D11_TEXTURE_ADDRESS_WRAP; + case GL_CLAMP_TO_EDGE: + return D3D11_TEXTURE_ADDRESS_CLAMP; + case GL_MIRRORED_REPEAT: + return D3D11_TEXTURE_ADDRESS_MIRROR; + default: + UNREACHABLE(); + } -#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 + return D3D11_TEXTURE_ADDRESS_WRAP; } -} // namespace d3d11_gl +UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel) +{ + return static_cast(std::min(maxAnisotropy, d3d11_gl::GetMaximumAnisotropy(featureLevel))); +} + +D3D11_QUERY ConvertQueryType(GLenum queryType) +{ + switch (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; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return D3D11_QUERY_EVENT; + default: + UNREACHABLE(); + return D3D11_QUERY_EVENT; + } +} + +// Get the D3D11 write mask covering all color channels of a given format +UINT8 GetColorMask(const gl::InternalFormat &format) +{ + return ConvertColorMask(format.redBits > 0, format.greenBits > 0, format.blueBits > 0, + format.alphaBits > 0); +} + +} // namespace gl_d3d11 namespace d3d11 { @@ -1352,9 +1876,7 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) IDXGIDevice *dxgiDevice = nullptr; IDXGIAdapter *dxgiAdapter = nullptr; -#if defined(ANGLE_ENABLE_D3D11_1) IDXGIAdapter2 *dxgiAdapter2 = nullptr; -#endif ANGLED3D11DeviceType retDeviceType = ANGLE_D3D11_DEVICE_TYPE_UNKNOWN; @@ -1365,7 +1887,6 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) if (SUCCEEDED(hr)) { std::wstring adapterString; -#if defined(ANGLE_ENABLE_D3D11_1) HRESULT adapter2hr = dxgiAdapter->QueryInterface(__uuidof(dxgiAdapter2), (void **)&dxgiAdapter2); if (SUCCEEDED(adapter2hr)) @@ -1378,7 +1899,6 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) adapterString = std::wstring(adapterDesc2.Description); } else -#endif { DXGI_ADAPTER_DESC adapterDesc; dxgiAdapter->GetDesc(&adapterDesc); @@ -1410,16 +1930,14 @@ ANGLED3D11DeviceType GetDeviceType(ID3D11Device *device) 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); + const DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(format); int upsampleCount = 0; // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. @@ -1433,7 +1951,10 @@ void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsi upsampleCount++; } } - *levelOffset = upsampleCount; + if (levelOffset) + { + *levelOffset = upsampleCount; + } } void GenerateInitialTextureData(GLint internalFormat, @@ -1445,10 +1966,11 @@ void GenerateInitialTextureData(GLint internalFormat, std::vector *outSubresourceData, std::vector> *outData) { - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, renderer11DeviceCaps); - ASSERT(d3dFormatInfo.dataInitializerFunction != NULL); + const d3d11::Format &d3dFormatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); + ASSERT(d3dFormatInfo.dataInitializerFunction != nullptr); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat); + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(d3dFormatInfo.texFormat); outSubresourceData->resize(mipLevels); outData->resize(mipLevels); @@ -1495,6 +2017,36 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo vertex->s = s; } +BlendStateKey::BlendStateKey() +{ + memset(this, 0, sizeof(BlendStateKey)); +} + +bool operator==(const BlendStateKey &a, const BlendStateKey &b) +{ + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; +} + +bool operator!=(const BlendStateKey &a, const BlendStateKey &b) +{ + return !(a == b); +} + +RasterizerStateKey::RasterizerStateKey() +{ + memset(this, 0, sizeof(RasterizerStateKey)); +} + +bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; +} + +bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return !(a == b); +} + HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) { #if defined(_DEBUG) @@ -1533,34 +2085,66 @@ HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) #endif } +// Keep this in cpp file where it has visibility of Renderer11.h, otherwise calling +// allocateResource is only compatible with Clang and MSVS, which support calling a +// method on a forward declared class in a template. +template +gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const GetDescType &desc, + GetInitDataType *initData, + const char *name) +{ + if (!mResource.valid()) + { + ANGLE_TRY(renderer->allocateResource(desc, initData, &mResource)); + mResource.setDebugName(name); + } + return gl::NoError(); +} + +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const D3D11_BLEND_DESC &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl( + Renderer11 *renderer, + const ShaderData &desc, + const std::vector *initData, + const char *name); +template gl::Error LazyResource::resolveImpl( + Renderer11 *renderer, + const InputElementArray &desc, + const ShaderData *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); +template gl::Error LazyResource::resolveImpl(Renderer11 *renderer, + const ShaderData &desc, + void *initData, + const char *name); + 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) + : mInputDesc(inputDesc, inputDescLen), mByteCode(byteCode, byteCodeLen), mDebugName(debugName) { - memcpy(&mInputDesc[0], inputDesc, sizeof(D3D11_INPUT_ELEMENT_DESC) * inputDescLen); } -ID3D11InputLayout *LazyInputLayout::resolve(ID3D11Device *device) +LazyInputLayout::~LazyInputLayout() { - 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; +gl::Error LazyInputLayout::resolve(Renderer11 *renderer) +{ + return resolveImpl(renderer, mInputDesc, &mByteCode, mDebugName); } LazyBlendState::LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName) @@ -1568,213 +2152,270 @@ LazyBlendState::LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugNa { } -ID3D11BlendState *LazyBlendState::resolve(ID3D11Device *device) +gl::Error LazyBlendState::resolve(Renderer11 *renderer) { - checkAssociatedDevice(device); + return resolveImpl(renderer, mDesc, nullptr, mDebugName); +} + +angle::WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, + const DXGI_ADAPTER_DESC &adapterDesc) +{ + bool is9_3 = (deviceCaps.featureLevel <= D3D_FEATURE_LEVEL_9_3); + + angle::WorkaroundsD3D workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; + workarounds.zeroMaxLodWorkaround = is9_3; + workarounds.useInstancedPointSpriteEmulation = is9_3; + + // TODO(jmadill): Narrow problematic driver range. + if (IsNvidia(adapterDesc.VendorId)) + { + if (deviceCaps.driverVersion.valid()) + { + WORD part1 = HIWORD(deviceCaps.driverVersion.value().LowPart); + WORD part2 = LOWORD(deviceCaps.driverVersion.value().LowPart); + + // Disable the workaround to fix a second driver bug on newer NVIDIA. + workarounds.depthStencilBlitExtraCopy = (part1 <= 13u && part2 < 6881); + } + else + { + workarounds.depthStencilBlitExtraCopy = true; + } + } + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + workarounds.expandIntegerPowExpressions = true; + + workarounds.flushAfterEndingTransformFeedback = IsNvidia(adapterDesc.VendorId); + workarounds.getDimensionsIgnoresBaseLevel = IsNvidia(adapterDesc.VendorId); - if (mResource == nullptr) + if (IsIntel(adapterDesc.VendorId)) { - HRESULT result = device->CreateBlendState(&mDesc, &mResource); - ASSERT(SUCCEEDED(result)); - UNUSED_ASSERTION_VARIABLE(result); - d3d11::SetDebugName(mResource, mDebugName); + IntelDriverVersion capsVersion = d3d11_gl::GetIntelDriverVersion(deviceCaps.driverVersion); + + workarounds.preAddTexelFetchOffsets = true; + workarounds.useSystemMemoryForConstantBuffers = true; + workarounds.disableB5G6R5Support = capsVersion < IntelDriverVersion(4539); + workarounds.addDummyTextureNoRenderTarget = capsVersion < IntelDriverVersion(4815); + if (IsSkylake(adapterDesc.DeviceId)) + { + workarounds.callClearTwice = capsVersion < IntelDriverVersion(4771); + workarounds.emulateIsnanFloat = capsVersion < IntelDriverVersion(4542); + } + else if (IsBroadwell(adapterDesc.DeviceId) || IsHaswell(adapterDesc.DeviceId)) + { + workarounds.rewriteUnaryMinusOperator = capsVersion < IntelDriverVersion(4624); + } + } + + // TODO(jmadill): Disable when we have a fixed driver version. + workarounds.emulateTinyStencilTextures = IsAMD(adapterDesc.VendorId); + + // The tiny stencil texture workaround involves using CopySubresource or UpdateSubresource on a + // depth stencil texture. This is not allowed until feature level 10.1 but since it is not + // possible to support ES3 on these devices, there is no need for the workaround to begin with + // (anglebug.com/1572). + if (deviceCaps.featureLevel < D3D_FEATURE_LEVEL_10_1) + { + workarounds.emulateTinyStencilTextures = false; } - return mResource; + // If the VPAndRTArrayIndexFromAnyShaderFeedingRasterizer feature is not available, we have to + // select the viewport / RT array index in the geometry shader. + workarounds.selectViewInGeometryShader = + (deviceCaps.supportsVpRtIndexWriteFromVertexShader == false); + + // Call platform hooks for testing overrides. + auto *platform = ANGLEPlatformCurrent(); + platform->overrideWorkaroundsD3D(platform, &workarounds); + + return workarounds; } -WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel) +void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth) { - WorkaroundsD3D workarounds; - workarounds.mrtPerfWorkaround = true; - workarounds.setDataFasterThanImageUpload = true; - workarounds.zeroMaxLodWorkaround = (featureLevel <= D3D_FEATURE_LEVEL_9_3); - workarounds.useInstancedPointSpriteEmulation = (featureLevel <= D3D_FEATURE_LEVEL_9_3); - return workarounds; + constantBufferDescription->ByteWidth = static_cast(byteWidth); + constantBufferDescription->Usage = D3D11_USAGE_DYNAMIC; + constantBufferDescription->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDescription->MiscFlags = 0; + constantBufferDescription->StructureByteStride = 0; } } // namespace d3d11 -TextureHelper11::TextureHelper11() - : mTextureType(GL_NONE), - mFormat(DXGI_FORMAT_UNKNOWN), - mSampleCount(0), - mTexture2D(nullptr), - mTexture3D(nullptr) +// TextureHelper11 implementation. +TextureHelper11::TextureHelper11() : mFormatSet(nullptr), mSampleCount(0) { } -TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy) - : mTextureType(toCopy.mTextureType), - mExtents(toCopy.mExtents), - mFormat(toCopy.mFormat), - mSampleCount(toCopy.mSampleCount), - mTexture2D(toCopy.mTexture2D), - mTexture3D(toCopy.mTexture3D) +TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy) : TextureHelper11() { - toCopy.reset(); + *this = std::move(toCopy); } -// static -TextureHelper11 TextureHelper11::MakeAndReference(ID3D11Resource *genericResource) +TextureHelper11::TextureHelper11(const TextureHelper11 &other) + : mFormatSet(other.mFormatSet), mExtents(other.mExtents), mSampleCount(other.mSampleCount) { - 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; + mData = other.mData; } -// static -TextureHelper11 TextureHelper11::MakeAndPossess2D(ID3D11Texture2D *texToOwn) +TextureHelper11::~TextureHelper11() { - TextureHelper11 newHelper; - newHelper.mTexture2D = texToOwn; - newHelper.mTextureType = GL_TEXTURE_2D; - newHelper.initDesc(); - return newHelper; } -// static -TextureHelper11 TextureHelper11::MakeAndPossess3D(ID3D11Texture3D *texToOwn) +void TextureHelper11::getDesc(D3D11_TEXTURE2D_DESC *desc) const { - TextureHelper11 newHelper; - newHelper.mTexture3D = texToOwn; - newHelper.mTextureType = GL_TEXTURE_3D; - newHelper.initDesc(); - return newHelper; + static_cast(mData->object)->GetDesc(desc); } -void TextureHelper11::initDesc() +void TextureHelper11::getDesc(D3D11_TEXTURE3D_DESC *desc) const { - if (mTextureType == GL_TEXTURE_2D) - { - ASSERT(!mTexture3D); - D3D11_TEXTURE2D_DESC desc2D; - mTexture2D->GetDesc(&desc2D); + static_cast(mData->object)->GetDesc(desc); +} - 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); +void TextureHelper11::initDesc(const D3D11_TEXTURE2D_DESC &desc2D) +{ + mData->resourceType = ResourceType::Texture2D; + mExtents.width = static_cast(desc2D.Width); + mExtents.height = static_cast(desc2D.Height); + mExtents.depth = 1; + mSampleCount = desc2D.SampleDesc.Count; +} - mExtents.width = static_cast(desc3D.Width); - mExtents.height = static_cast(desc3D.Height); - mExtents.depth = static_cast(desc3D.Depth); - mFormat = desc3D.Format; - mSampleCount = 1; - } +void TextureHelper11::initDesc(const D3D11_TEXTURE3D_DESC &desc3D) +{ + mData->resourceType = ResourceType::Texture3D; + mExtents.width = static_cast(desc3D.Width); + mExtents.height = static_cast(desc3D.Height); + mExtents.depth = static_cast(desc3D.Depth); + mSampleCount = 1; } -TextureHelper11::~TextureHelper11() +TextureHelper11 &TextureHelper11::operator=(TextureHelper11 &&other) { - SafeRelease(mTexture2D); - SafeRelease(mTexture3D); + std::swap(mData, other.mData); + std::swap(mExtents, other.mExtents); + std::swap(mFormatSet, other.mFormatSet); + std::swap(mSampleCount, other.mSampleCount); + return *this; } -ID3D11Resource *TextureHelper11::getResource() const +TextureHelper11 &TextureHelper11::operator=(const TextureHelper11 &other) { - return mTexture2D ? static_cast(mTexture2D) - : static_cast(mTexture3D); + mData = other.mData; + mExtents = other.mExtents; + mFormatSet = other.mFormatSet; + mSampleCount = other.mSampleCount; + return *this; } -TextureHelper11 &TextureHelper11::operator=(TextureHelper11 &&texture) +bool TextureHelper11::operator==(const TextureHelper11 &other) const { - SafeRelease(mTexture2D); - SafeRelease(mTexture3D); + return mData->object == other.mData->object; +} - mTextureType = texture.mTextureType; - mExtents = texture.mExtents; - mFormat = texture.mFormat; - mSampleCount = texture.mSampleCount; - mTexture2D = texture.mTexture2D; - mTexture3D = texture.mTexture3D; - texture.reset(); - return *this; +bool TextureHelper11::operator!=(const TextureHelper11 &other) const +{ + return mData->object != other.mData->object; +} + +bool UsePresentPathFast(const Renderer11 *renderer, + const gl::FramebufferAttachment *framebufferAttachment) +{ + if (framebufferAttachment == nullptr) + { + return false; + } + + return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT && + renderer->presentPathFastEnabled()); } -void TextureHelper11::reset() +bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type) { - mTextureType = GL_NONE; - mExtents = gl::Extents(); - mFormat = DXGI_FORMAT_UNKNOWN; - mSampleCount = 0; - mTexture2D = nullptr; - mTexture3D = nullptr; + // We should never have to deal with primitive restart workaround issue with GL_UNSIGNED_INT + // indices, since we restrict it via MAX_ELEMENT_INDEX. + return (!primitiveRestartFixedIndexEnabled && type == GL_UNSIGNED_SHORT); } -gl::ErrorOrResult CreateStagingTexture(GLenum textureType, - DXGI_FORMAT dxgiFormat, - const gl::Extents &size, - ID3D11Device *device) +bool IsStreamingIndexData(const gl::Context *context, GLenum srcType) { - if (textureType == GL_TEXTURE_2D) + const auto &glState = context->getGLState(); + gl::Buffer *glBuffer = glState.getVertexArray()->getElementArrayBuffer().get(); + + // Case 1: the indices are passed by pointer, which forces the streaming of index data + if (glBuffer == nullptr) { - 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; + return true; + } - 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); - } + bool primitiveRestartWorkaround = + UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType); + + BufferD3D *buffer = GetImplAs(glBuffer); + const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) + ? GL_UNSIGNED_INT + : GL_UNSIGNED_SHORT; - return TextureHelper11::MakeAndPossess2D(stagingTex); + // Case 2a: the buffer can be used directly + if (buffer->supportsDirectBinding() && dstType == srcType) + { + return false; } - 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; + // Case 2b: use a static translated copy or fall back to streaming + StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer(); + if (staticBuffer == nullptr) + { + return true; + } - ID3D11Texture3D *stagingTex = nullptr; - HRESULT result = device->CreateTexture3D(&stagingDesc, nullptr, &stagingTex); - if (FAILED(result)) + if ((staticBuffer->getBufferSize() == 0) || (staticBuffer->getIndexType() != dstType)) { - return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.", - result); + return true; } - return TextureHelper11::MakeAndPossess3D(stagingTex); + return false; } -bool UsePresentPathFast(const Renderer11 *renderer, - const gl::FramebufferAttachment *framebufferAttachment) +IndexStorageType ClassifyIndexStorage(const gl::State &glState, + const gl::Buffer *elementArrayBuffer, + GLenum elementType, + GLenum destElementType, + unsigned int offset, + bool *needsTranslation) { - if (framebufferAttachment == nullptr) + // No buffer bound means we are streaming from a client pointer. + if (!elementArrayBuffer || !IsOffsetAligned(elementType, offset)) { - return false; + *needsTranslation = true; + return IndexStorageType::Dynamic; } - return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT && - renderer->presentPathFastEnabled()); + // The buffer can be used directly if the storage supports it and no translation needed. + BufferD3D *bufferD3D = GetImplAs(elementArrayBuffer); + if (bufferD3D->supportsDirectBinding() && destElementType == elementType) + { + *needsTranslation = false; + return IndexStorageType::Direct; + } + + // Use a static copy when available. + StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer(); + if (staticBuffer != nullptr) + { + // Need to re-translate the static data if has never been used, or changed type. + *needsTranslation = + (staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != destElementType); + return IndexStorageType::Static; + } + + // Static buffer not available, fall back to streaming. + *needsTranslation = true; + return IndexStorageType::Dynamic; } } // 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 4925a2d227..3af51bb0f6 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 @@ -11,12 +11,16 @@ #define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ #include +#include #include -#include "libANGLE/angletypes.h" +#include "common/Color.h" + #include "libANGLE/Caps.h" #include "libANGLE/Error.h" #include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" namespace gl { @@ -27,10 +31,10 @@ namespace rx { class Renderer11; class RenderTarget11; -struct WorkaroundsD3D; struct Renderer11DeviceCaps; -using RenderTargetArray = std::array; +using RenderTargetArray = std::array; +using RTVArray = std::array; namespace gl_d3d11 { @@ -39,7 +43,7 @@ D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, gl::CullFaceMode cullMode); D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); @@ -48,9 +52,12 @@ D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); +UINT ConvertMaxAnisotropy(float maxAnisotropy, D3D_FEATURE_LEVEL featureLevel); D3D11_QUERY ConvertQueryType(GLenum queryType); +UINT8 GetColorMask(const gl::InternalFormat &formatInfo); + } // namespace gl_d3d11 namespace d3d11_gl @@ -60,10 +67,12 @@ unsigned int GetReservedVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel); unsigned int GetReservedFragmentUniformVectors(D3D_FEATURE_LEVEL featureLevel); -GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); +gl::Version GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, const Renderer11DeviceCaps &renderer11DeviceCaps, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Limitations *limitations); +void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy); + } // namespace d3d11_gl namespace d3d11 @@ -108,32 +117,45 @@ struct PositionLayerTexCoord3DVertex void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, unsigned int layer, float u, float v, float s); -template -struct PositionDepthColorVertex +struct PositionVertex { - float x, y, z; - T r, g, b, a; + float x, y, z, w; }; -template -void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, - const gl::Color &color) +struct BlendStateKey final { - vertex->x = x; - vertex->y = y; - vertex->z = z; - vertex->r = color.red; - vertex->g = color.green; - vertex->b = color.blue; - vertex->a = color.alpha; -} + // This will zero-initialize the struct, including padding. + BlendStateKey(); + + gl::BlendState blendState; + + // An int so struct size rounds nicely. + uint32_t rtvMax; + + uint8_t rtvMasks[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; +}; + +bool operator==(const BlendStateKey &a, const BlendStateKey &b); +bool operator!=(const BlendStateKey &a, const BlendStateKey &b); + +struct RasterizerStateKey final +{ + // This will zero-initialize the struct, including padding. + RasterizerStateKey(); + + gl::RasterizerState rasterizerState; -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + // Use a 32-bit int to round the struct nicely. + uint32_t scissorEnabled; +}; + +bool operator==(const RasterizerStateKey &a, const RasterizerStateKey &b); +bool operator!=(const RasterizerStateKey &a, const RasterizerStateKey &b); template outType* DynamicCastComObject(IUnknown* object) { - outType *outObject = NULL; + outType *outObject = nullptr; HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast(&outObject)); if (SUCCEEDED(result)) { @@ -142,7 +164,7 @@ outType* DynamicCastComObject(IUnknown* object) else { SafeRelease(outObject); - return NULL; + return nullptr; } } @@ -161,143 +183,63 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name) -{ - ID3D11VertexShader *vs = nullptr; - HRESULT result = device->CreateVertexShader(byteCode, N, nullptr, &vs); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - SetDebugName(vs, name); - return vs; - } - return nullptr; -} - -template -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 = nullptr; - HRESULT result = device->CreateGeometryShader(byteCode, N, nullptr, &gs); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - SetDebugName(gs, name); - return gs; - } - return nullptr; -} - -template -ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +template +class LazyResource : angle::NonCopyable { - return CompileGS(device, byteCode, N, name); -} + public: + constexpr LazyResource() : mResource() {} + virtual ~LazyResource() {} -inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE *byteCode, size_t N, const char *name) -{ - ID3D11PixelShader *ps = nullptr; - HRESULT result = device->CreatePixelShader(byteCode, N, nullptr, &ps); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) + virtual gl::Error resolve(Renderer11 *renderer) = 0; + void reset() { mResource.reset(); } + GetD3D11Type *get() const { - SetDebugName(ps, name); - return ps; + ASSERT(mResource.valid()); + return mResource.get(); } - return nullptr; -} - -template -ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - return CompilePS(device, byteCode, N, name); -} - -template -class LazyResource : public angle::NonCopyable -{ - public: - LazyResource() : mResource(nullptr), mAssociatedDevice(nullptr) {} - virtual ~LazyResource() { release(); } - virtual ResourceType *resolve(ID3D11Device *device) = 0; - void release() { SafeRelease(mResource); } + const Resource11> &getObj() const { return mResource; } protected: - void checkAssociatedDevice(ID3D11Device *device); + LazyResource(LazyResource &&other) : mResource(std::move(other.mResource)) {} - ResourceType *mResource; - ID3D11Device *mAssociatedDevice; -}; + // Specialized in the cpp file to avoid MSVS/Clang specific code. + gl::Error resolveImpl(Renderer11 *renderer, + const GetDescType &desc, + GetInitDataType *initData, + const char *name); -template -void LazyResource::checkAssociatedDevice(ID3D11Device *device) -{ - ASSERT(mAssociatedDevice == nullptr || device == mAssociatedDevice); - mAssociatedDevice = device; -} + Resource11> mResource; +}; template -class LazyShader final : public LazyResource +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) + constexpr LazyShader(const BYTE *byteCode, size_t byteCodeSize, const char *name) + : mByteCode(byteCode, byteCodeSize), mName(name) { } - 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) + constexpr LazyShader(LazyShader &&shader) + : LazyResource()>(std::move(shader)), + mByteCode(std::move(shader.mByteCode)), + mName(shader.mName) { - mResource = CompileVS(device, mByteCode, mByteCodeSize, mName); } - return mResource; -} -template <> -inline ID3D11GeometryShader *LazyShader::resolve(ID3D11Device *device) -{ - checkAssociatedDevice(device); - if (mResource == nullptr) + gl::Error resolve(Renderer11 *renderer) override { - mResource = CompileGS(device, mByteCode, mByteCodeSize, mName); + return this->resolveImpl(renderer, mByteCode, nullptr, mName); } - return mResource; -} -template <> -inline ID3D11PixelShader *LazyShader::resolve(ID3D11Device *device) -{ - checkAssociatedDevice(device); - if (mResource == nullptr) - { - mResource = CompilePS(device, mByteCode, mByteCodeSize, mName); - } - return mResource; -} + private: + ShaderData mByteCode; + const char *mName; +}; -class LazyInputLayout final : public LazyResource +class LazyInputLayout final : public LazyResource { public: LazyInputLayout(const D3D11_INPUT_ELEMENT_DESC *inputDesc, @@ -305,22 +247,22 @@ class LazyInputLayout final : public LazyResource const BYTE *byteCode, size_t byteCodeLen, const char *debugName); + ~LazyInputLayout() override; - ID3D11InputLayout *resolve(ID3D11Device *device) override; + gl::Error resolve(Renderer11 *renderer) override; private: - std::vector mInputDesc; - size_t mByteCodeLen; - const BYTE *mByteCode; + InputElementArray mInputDesc; + ShaderData mByteCode; const char *mDebugName; }; -class LazyBlendState final : public LazyResource +class LazyBlendState final : public LazyResource { public: LazyBlendState(const D3D11_BLEND_DESC &desc, const char *debugName); - ID3D11BlendState *resolve(ID3D11Device *device) override; + gl::Error resolve(Renderer11 *renderer) override; private: D3D11_BLEND_DESC mDesc; @@ -342,48 +284,147 @@ void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, c } } -WorkaroundsD3D GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel); +angle::WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, + const DXGI_ADAPTER_DESC &adapterDesc); + +enum ReservedConstantBufferSlot +{ + RESERVED_CONSTANT_BUFFER_SLOT_DEFAULT_UNIFORM_BLOCK = 0, + RESERVED_CONSTANT_BUFFER_SLOT_DRIVER = 1, + + RESERVED_CONSTANT_BUFFER_SLOT_COUNT = 2 +}; + +void InitConstantBufferDesc(D3D11_BUFFER_DESC *constantBufferDescription, size_t byteWidth); } // namespace d3d11 +struct GenericData +{ + GenericData() {} + ~GenericData() + { + if (object) + { + // We can have a nullptr factory when holding passed-in resources. + if (manager) + { + manager->onReleaseGeneric(resourceType, object); + manager = nullptr; + } + object->Release(); + object = nullptr; + } + } + + ResourceType resourceType = ResourceType::Last; + ID3D11Resource *object = nullptr; + ResourceManager11 *manager = nullptr; +}; + // A helper class which wraps a 2D or 3D texture. -class TextureHelper11 : angle::NonCopyable +class TextureHelper11 : public Resource11Base { 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; } + TextureHelper11(TextureHelper11 &&other); + TextureHelper11(const TextureHelper11 &other); + ~TextureHelper11() override; + TextureHelper11 &operator=(TextureHelper11 &&other); + TextureHelper11 &operator=(const TextureHelper11 &other); + + bool is2D() const { return mData->resourceType == ResourceType::Texture2D; } + bool is3D() const { return mData->resourceType == ResourceType::Texture3D; } + ResourceType getTextureType() const { return mData->resourceType; } gl::Extents getExtents() const { return mExtents; } - DXGI_FORMAT getFormat() const { return mFormat; } + DXGI_FORMAT getFormat() const { return mFormatSet->texFormat; } + const d3d11::Format &getFormatSet() const { return *mFormatSet; } int getSampleCount() const { return mSampleCount; } - ID3D11Texture2D *getTexture2D() const { return mTexture2D; } - ID3D11Texture3D *getTexture3D() const { return mTexture3D; } - ID3D11Resource *getResource() const; + + template + void init(Resource11 &&texture, const DescT &desc, const d3d11::Format &format) + { + std::swap(mData->manager, texture.mData->manager); + + // Can't use std::swap because texture is typed, and here we use ID3D11Resource. + ID3D11Resource *temp = mData->object; + mData->object = texture.mData->object; + texture.mData->object = static_cast(temp); + + mFormatSet = &format; + initDesc(desc); + } + + template + void set(ResourceT *object, const d3d11::Format &format) + { + ASSERT(!valid()); + mFormatSet = &format; + mData->object = object; + mData->manager = nullptr; + + GetDescFromD3D11 desc; + getDesc(&desc); + initDesc(desc); + } + + bool operator==(const TextureHelper11 &other) const; + bool operator!=(const TextureHelper11 &other) const; + + void getDesc(D3D11_TEXTURE2D_DESC *desc) const; + void getDesc(D3D11_TEXTURE3D_DESC *desc) const; private: - void reset(); - void initDesc(); + void initDesc(const D3D11_TEXTURE2D_DESC &desc2D); + void initDesc(const D3D11_TEXTURE3D_DESC &desc3D); - GLenum mTextureType; + const d3d11::Format *mFormatSet; 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); +enum class StagingAccess +{ + READ, + READ_WRITE, +}; bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer); +bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type); +bool IsStreamingIndexData(const gl::Context *context, GLenum srcType); + +enum class IndexStorageType +{ + // Dynamic indexes are re-streamed every frame. They come from a client data pointer or + // from buffers that are updated frequently. + Dynamic, + + // Static indexes are translated from the original storage once, and re-used multiple times. + Static, + + // Direct indexes are never transated and are used directly from the source buffer. They are + // the fastest available path. + Direct, + + // Not a real storage type. + Invalid, +}; + +IndexStorageType ClassifyIndexStorage(const gl::State &glState, + const gl::Buffer *elementArrayBuffer, + GLenum elementType, + GLenum destElementType, + unsigned int offset, + bool *needsTranslation); + +// Used for state change notifications between buffers and vertex arrays. +using OnBufferDataDirtyBinding = angle::ChannelBinding; +using OnBufferDataDirtyChannel = angle::BroadcastChannel; +using OnBufferDataDirtyReceiver = angle::SignalReceiver; + +// Used for state change notifications between RenderTarget11 and Framebuffer11. +using OnRenderTargetDirtyBinding = angle::ChannelBinding; +using OnRenderTargetDirtyChannel = angle::BroadcastChannel; +using OnRenderTargetDirtyReceiver = angle::SignalReceiver; } // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl index 2b3e1ebe4c..48f5b427ec 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -1,13 +1,152 @@ -// Assume we are in SM4+, which has 8 color outputs +// +// Copyright (c) 2017 The ANGLE Project. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// -void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +// Clear11.hlsl: Shaders for clearing RTVs and DSVs using draw calls and +// specifying float depth values and either float, uint or sint clear colors. +// Notes: +// - UINT & SINT clears can only be compiled with FL10+ +// - VS_Clear_FL9 requires a VB to be bound with vertices to create +// a primitive covering the entire surface (in clip co-ordinates) + +// Constants +static const float2 g_Corners[6] = +{ + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, 1.0f), + float2( 1.0f, -1.0f), +}; + +// Vertex Shaders +void VS_Clear(in uint id : SV_VertexID, + out float4 outPosition : SV_POSITION) +{ + float2 corner = g_Corners[id]; + outPosition = float4(corner.x, corner.y, 0.0f, 1.0f); +} + +void VS_Multiview_Clear(in uint id : SV_VertexID, + in uint instanceID : SV_InstanceID, + out float4 outPosition : SV_POSITION, + out uint outLayerID : TEXCOORD0) +{ + float2 corner = g_Corners[id]; + outPosition = float4(corner.x, corner.y, 0.0f, 1.0f); + outLayerID = instanceID; +} + +void VS_Clear_FL9( in float4 inPosition : POSITION, + out float4 outPosition : SV_POSITION) +{ + outPosition = inPosition; +} + +// Geometry shader for clearing multiview layered textures +struct GS_INPUT +{ + float4 inPosition : SV_Position; + uint inLayerID : TEXCOORD0; +}; + +struct GS_OUTPUT { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; + float4 outPosition : SV_Position; + uint outLayerID : SV_RenderTargetArrayIndex; +}; + +[maxvertexcount(3)] +void GS_Multiview_Clear(triangle GS_INPUT input[3], inout TriangleStream outStream) +{ + GS_OUTPUT output = (GS_OUTPUT)0; + for (int i = 0; i < 3; i++) + { + output.outPosition = input[i].inPosition; + output.outLayerID = input[i].inLayerID; + outStream.Append(output); + } + outStream.RestartStrip(); +} + +// Pixel Shader Constant Buffers +cbuffer ColorAndDepthDataFloat : register(b0) +{ + float4 color_Float : packoffset(c0); + float zValueF_Float : packoffset(c1); +} + +cbuffer ColorAndDepthDataSint : register(b0) +{ + int4 color_Sint : packoffset(c0); + float zValueF_Sint : packoffset(c1); +} + +cbuffer ColorAndDepthDataUint : register(b0) +{ + uint4 color_Uint : packoffset(c0); + float zValueF_Uint : packoffset(c1); } -struct PS_OutputFloat +cbuffer DepthOnlyData : register(b0) +{ + float zValue_Depth : packoffset(c1); +} + +// Pixel Shader Output Structs +struct PS_OutputFloat_FL9 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat1 +{ + float4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat2 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat3 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat4 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat5 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputFloat6 { float4 color0 : SV_TARGET0; float4 color1 : SV_TARGET1; @@ -15,50 +154,98 @@ struct PS_OutputFloat float4 color3 : SV_TARGET3; float4 color4 : SV_TARGET4; float4 color5 : SV_TARGET5; - float4 color6 : SV_TARGET6; - float4 color7 : SV_TARGET7; + float depth : SV_DEPTH; }; -PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +struct PS_OutputFloat7 { - PS_OutputFloat outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; - return outColor; -} + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float depth : SV_DEPTH; +}; -struct PS_OutputFloat_FL9 +struct PS_OutputFloat8 { float4 color0 : SV_TARGET0; float4 color1 : SV_TARGET1; float4 color2 : SV_TARGET2; float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float4 color7 : SV_TARGET7; + float depth : SV_DEPTH; }; -PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +struct PS_OutputUint1 { - PS_OutputFloat_FL9 outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - return outColor; -} + uint4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; -void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +struct PS_OutputUint2 { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint3 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint4 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint5 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint6 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + float depth : SV_DEPTH; +}; + +struct PS_OutputUint7 +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + uint4 color6 : SV_TARGET6; + float depth : SV_DEPTH; +}; -struct PS_OutputUint +struct PS_OutputUint8 { uint4 color0 : SV_TARGET0; uint4 color1 : SV_TARGET1; @@ -68,31 +255,73 @@ struct PS_OutputUint uint4 color5 : SV_TARGET5; uint4 color6 : SV_TARGET6; uint4 color7 : SV_TARGET7; + float depth : SV_DEPTH; }; -PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +struct PS_OutputSint1 { - PS_OutputUint outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; - return outColor; -} + int4 color0 : SV_TARGET0; + float depth : SV_DEPTH; +}; +struct PS_OutputSint2 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + float depth : SV_DEPTH; +}; -void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +struct PS_OutputSint3 { - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint4 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint5 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint6 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + float depth : SV_DEPTH; +}; + +struct PS_OutputSint7 +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + int4 color6 : SV_TARGET6; + float depth : SV_DEPTH; +}; -struct PS_OutputSint +struct PS_OutputSint8 { int4 color0 : SV_TARGET0; int4 color1 : SV_TARGET1; @@ -102,18 +331,305 @@ struct PS_OutputSint int4 color5 : SV_TARGET5; int4 color6 : SV_TARGET6; int4 color7 : SV_TARGET7; + float depth : SV_DEPTH; +}; + +struct PS_OutputDepth +{ + float depth : SV_DEPTH; }; -PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +// Pixel Shaders +PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat_FL9 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat1 PS_ClearFloat1(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat1 outData; + outData.color0 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat2 PS_ClearFloat2(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat2 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat3 PS_ClearFloat3(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat3 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat4 PS_ClearFloat4(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat4 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat5 PS_ClearFloat5(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat5 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat6 PS_ClearFloat6(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat6 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat7 PS_ClearFloat7(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat7 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.color6 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputFloat8 PS_ClearFloat8(in float4 inPosition : SV_POSITION) +{ + PS_OutputFloat8 outData; + outData.color0 = color_Float; + outData.color1 = color_Float; + outData.color2 = color_Float; + outData.color3 = color_Float; + outData.color4 = color_Float; + outData.color5 = color_Float; + outData.color6 = color_Float; + outData.color7 = color_Float; + outData.depth = zValueF_Float; + return outData; +} + +PS_OutputUint1 PS_ClearUint1(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint1 outData; + outData.color0 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint2 PS_ClearUint2(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint2 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint3 PS_ClearUint3(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint3 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint4 PS_ClearUint4(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint4 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint5 PS_ClearUint5(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint5 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint6 PS_ClearUint6(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint6 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint7 PS_ClearUint7(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint7 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.color6 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputUint8 PS_ClearUint8(in float4 inPosition : SV_POSITION) +{ + PS_OutputUint8 outData; + outData.color0 = color_Uint; + outData.color1 = color_Uint; + outData.color2 = color_Uint; + outData.color3 = color_Uint; + outData.color4 = color_Uint; + outData.color5 = color_Uint; + outData.color6 = color_Uint; + outData.color7 = color_Uint; + outData.depth = zValueF_Uint; + return outData; +} + +PS_OutputSint1 PS_ClearSint1(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint1 outData; + outData.color0 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint2 PS_ClearSint2(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint2 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint3 PS_ClearSint3(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint3 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint4 PS_ClearSint4(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint4 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint5 PS_ClearSint5(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint5 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint6 PS_ClearSint6(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint6 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint7 PS_ClearSint7(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint7 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.color6 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputSint8 PS_ClearSint8(in float4 inPosition : SV_POSITION) +{ + PS_OutputSint8 outData; + outData.color0 = color_Sint; + outData.color1 = color_Sint; + outData.color2 = color_Sint; + outData.color3 = color_Sint; + outData.color4 = color_Sint; + outData.color5 = color_Sint; + outData.color6 = color_Sint; + outData.color7 = color_Sint; + outData.depth = zValueF_Sint; + return outData; +} + +PS_OutputDepth PS_ClearDepth(in float4 inPosition : SV_POSITION) { - PS_OutputSint outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; - return outColor; + PS_OutputDepth outData; + outData.depth = zValue_Depth; + return outData; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl new file mode 100644 index 0000000000..0d10b8eafa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/MultiplyAlpha.hlsl @@ -0,0 +1,131 @@ +Texture2D TextureF : register(t0); +Texture2D TextureUI : register(t0); + +SamplerState Sampler : register(s0); + +// Notation: +// PM: premultiply, UM: unmulitply, PT: passthrough +// F: float, U: uint + +// Float to float LUMA +float4 PS_FtoF_PM_LUMA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb = color.r * color.a; + color.a = 1.0f; + return color; +} +float4 PS_FtoF_UM_LUMA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb = color.r / color.a; + } + color.a = 1.0f; + return color; +} + +// Float to float LUMAALPHA +float4 PS_FtoF_PM_LUMAALPHA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb = color.r * color.a; + return color; +} + +float4 PS_FtoF_UM_LUMAALPHA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb = color.r / color.a; + } + return color; +} + +// Float to float RGBA +float4 PS_FtoF_PM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return color; +} + +float4 PS_FtoF_UM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return color; +} + +// Float to float RGB +float4 PS_FtoF_PM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + color.a = 1.0f; + return color; +} + +float4 PS_FtoF_UM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + color.a = 1.0f; + return color; +} + +// Float to uint RGBA +uint4 PS_FtoU_PT_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + return uint4(color * 255); +} + +uint4 PS_FtoU_PM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return uint4(color * 255); +} + +uint4 PS_FtoU_UM_RGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return uint4(color * 255); +} + +// Float to uint RGB +uint4 PS_FtoU_PT_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + return uint4(color.rgb * 255, 1); +} + +uint4 PS_FtoU_PM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + color.rgb *= color.a; + return uint4(color.rgb * 255, 1); +} + +uint4 PS_FtoU_UM_RGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + float4 color = TextureF.Sample(Sampler, inTexCoord).rgba; + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return uint4(color.rgb * 255, 1); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl index 8671c39fb7..0b1a5ad169 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -1,4 +1,5 @@ Texture2D TextureF : register(t0); +Texture2DMS TextureF_MS: register(t0); Texture2D TextureUI : register(t0); Texture2D TextureI : register(t0); @@ -21,6 +22,16 @@ float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexC return TextureF.Sample(Sampler, inTexCoord).rgba; } +float4 PS_PassthroughA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(0.0f, 0.0f, 0.0f, TextureF.Sample(Sampler, inTexCoord).a); +} + +float4 PS_PassthroughRGBA2DMS(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCORD0, in uint inSampleIndex : SV_SAMPLEINDEX) : SV_TARGET0 +{ + return TextureF_MS.sample[inSampleIndex][inTexCoord].rgba; +} + uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 { uint2 size; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl new file mode 100644 index 0000000000..7dc40d4b6a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/ResolveDepthStencil.hlsl @@ -0,0 +1,56 @@ +static const float2 g_Corners[6] = +{ + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, 1.0f), + float2( 1.0f, -1.0f), +}; + +void VS_ResolveDepthStencil(in uint id : SV_VertexID, + out float4 position : SV_Position, + out float2 texCoord : TEXCOORD0) +{ + float2 corner = g_Corners[id]; + position = float4(corner.x, corner.y, 0.0f, 1.0f); + texCoord = float2((corner.x + 1.0f) * 0.5f, (-corner.y + 1.0f) * 0.5f); +} + +Texture2DMS Depth : register(t0); +Texture2DMS Stencil : register(t1); + +void PS_ResolveDepth(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float depth : SV_Depth) +{ + // MS samplers must use Load + uint width, height, samples; + Depth.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + depth = Depth.Load(coord, 0).r; +} + +void PS_ResolveDepthStencil(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float2 depthStencil : SV_Target0) +{ + // MS samplers must use Load + uint width, height, samples; + Depth.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + depthStencil.r = Depth.Load(coord, 0).r; + depthStencil.g = float(Stencil.Load(coord, 0).g); +} + +void PS_ResolveStencil(in float4 position : SV_Position, + in float2 texCoord : TEXCOORD0, + out float2 stencil : SV_Target0) +{ + // MS samplers must use Load + uint width, height, samples; + Stencil.GetDimensions(width, height, samples); + uint2 coord = uint2(texCoord.x * float(width), texCoord.y * float(height)); + stencil.r = 0.0f; + stencil.g = float(Stencil.Load(coord, 0).g); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h new file mode 100644 index 0000000000..a5cccdc98e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dms11ps.h @@ -0,0 +1,155 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// TextureF_MS texture float4 2dMS t0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float +// TEXCORD 0 xy 1 NONE float xy +// SV_SAMPLEINDEX 0 x 2 SAMPLE uint x +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_TARGET 0 xyzw 0 TARGET float xyzw +// +// Pixel Shader runs at sample frequency +// +ps_4_1 +dcl_globalFlags refactoringAllowed +dcl_resource_texture2dms(0) (float,float,float,float) t0 +dcl_input_ps linear v1.xy +dcl_input_ps_sgv constant v2.x, sampleIndex +dcl_output o0.xyzw +dcl_temps 1 +ftou r0.xy, v1.xyxx +mov r0.zw, l(0,0,0,0) +ldms o0.xyzw, r0.xyzw, t0.xyzw, v2.x +ret +// Approximately 4 instruction slots used +#endif + +const BYTE g_PS_PassthroughRGBA2DMS[] = +{ + 68, 88, 66, 67, 206, 115, + 73, 27, 160, 237, 59, 223, + 179, 180, 28, 146, 74, 174, + 29, 197, 1, 0, 0, 0, + 136, 2, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 172, 0, 0, 0, 40, 1, + 0, 0, 92, 1, 0, 0, + 12, 2, 0, 0, 82, 68, + 69, 70, 112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 28, 0, 0, 0, 1, 4, + 255, 255, 0, 1, 0, 0, + 72, 0, 0, 0, 60, 0, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 84, 101, 120, 116, 117, 114, + 101, 70, 95, 77, 83, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 49, + 48, 46, 49, 0, 73, 83, + 71, 78, 116, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 100, 0, 0, 0, + 0, 0, 0, 0, 10, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 1, 1, + 0, 0, 83, 86, 95, 80, + 79, 83, 73, 84, 73, 79, + 78, 0, 84, 69, 88, 67, + 79, 82, 68, 0, 83, 86, + 95, 83, 65, 77, 80, 76, + 69, 73, 78, 68, 69, 88, + 0, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 65, 82, + 71, 69, 84, 0, 171, 171, + 83, 72, 68, 82, 168, 0, + 0, 0, 65, 0, 0, 0, + 42, 0, 0, 0, 106, 8, + 0, 1, 88, 32, 0, 4, + 0, 112, 16, 0, 0, 0, + 0, 0, 85, 85, 0, 0, + 98, 16, 0, 3, 50, 16, + 16, 0, 1, 0, 0, 0, + 99, 8, 0, 4, 18, 16, + 16, 0, 2, 0, 0, 0, + 10, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 104, 0, + 0, 2, 1, 0, 0, 0, + 28, 0, 0, 5, 50, 0, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 8, + 194, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, + 0, 9, 242, 32, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 10, 16, 16, 0, + 2, 0, 0, 0, 62, 0, + 0, 1, 83, 84, 65, 84, + 116, 0, 0, 0, 4, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0 +}; 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 deleted file mode 100644 index 3e9e6877d9..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_data.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "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 deleted file mode 100644 index df9a30ff50..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// 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 deleted file mode 100644 index 84d6fada97..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/swizzle_format_info_autogen.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// 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 index 87d303437f..61cd44a62b 100644 --- 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 @@ -1,692 +1,523 @@ { - "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": [ - { + "NONE": { + }, + "A8_UNORM": { + "texFormat": "DXGI_FORMAT_A8_UNORM", + "srvFormat": "DXGI_FORMAT_A8_UNORM", + "rtvFormat": "DXGI_FORMAT_A8_UNORM", + "channels": "a", + "componentType": "unorm", + "bits": { "alpha": 8 }, + "supportTest": "OnlyFL10Plus(deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_UNORM": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8" + }, + "R16G16B16A16_UNORM": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16_EXT" + }, + "R16G16B16A16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT", + "channels": "rgba", + "componentType": "float", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16F" + }, + "R32G32B32A32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_FLOAT", + "channels": "rgba", + "componentType": "float", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32F" + }, + "B8G8R8A8_UNORM": { + "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_BGRA8_EXT" + }, + "B8G8R8A8_UNORM_SRGB": { + "texFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "rtvFormat": "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB", + "channels": "bgra", + "componentType": "unorm", + "bits": {"red": 8, "green": 8, "blue": 8,"alpha": 8}, + "siwzzleFormat": "GL_RGBA8" + }, + "BC1_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM", + "srvFormat": "DXGI_FORMAT_BC1_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGB_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM", + "srvFormat": "DXGI_FORMAT_BC1_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC2_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC2_UNORM", + "srvFormat": "DXGI_FORMAT_BC2_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC3_RGBA_UNORM_BLOCK": { + "texFormat": "DXGI_FORMAT_BC3_UNORM", + "srvFormat": "DXGI_FORMAT_BC3_UNORM", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC1_RGB_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC1_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC2_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC2_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC2_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "BC3_RGBA_UNORM_SRGB_BLOCK": { + "texFormat": "DXGI_FORMAT_BC3_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_BC3_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "swizzleFormat": "GL_RGBA8" + }, + "D24_UNORM_S8_UINT": { + "FL10Plus": { "texFormat": "DXGI_FORMAT_R24G8_TYPELESS", - "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL10Plus" + "srvFormat": "DXGI_FORMAT_R24_UNORM_X8_TYPELESS" }, - { - "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" + "FL9_3": { + "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT" }, - { - "requirementsFcn": "OnlyFL9_3" - } - ], - "GL_DEPTH_COMPONENT16": [ - { + "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", + "channels": "ds", + "bits": { "depth": 24, "stencil": 8 }, + "glInternalFormat": "GL_DEPTH24_STENCIL8_OES" + }, + "D32_FLOAT_S8X24_UINT": { + "texFormat": "DXGI_FORMAT_R32G8X24_TYPELESS", + "srvFormat": "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS", + "dsvFormat": "DXGI_FORMAT_D32_FLOAT_S8X24_UINT", + "channels": "ds", + "bits": { "depth": 32, "stencil": 8 }, + "glInternalFormat": "GL_DEPTH32F_STENCIL8" + }, + "D16_UNORM": { + "FL10Plus": { "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" + "srvFormat": "DXGI_FORMAT_R16_UNORM" }, - { - "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" + "FL9_3": { + "texFormat": "DXGI_FORMAT_D16_UNORM" }, - { - "texFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "dsvFormat": "DXGI_FORMAT_D24_UNORM_S8_UINT", - "requirementsFcn": "OnlyFL9_3" - } - ] + "dsvFormat": "DXGI_FORMAT_D16_UNORM", + "channels": "d", + "componentType": "unorm", + "bits": { "depth": 16 }, + "glInternalFormat": "GL_DEPTH_COMPONENT16" + }, + "D32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32_TYPELESS", + "srvFormat": "DXGI_FORMAT_R32_FLOAT", + "dsvFormat": "DXGI_FORMAT_D32_FLOAT", + "channels": "d", + "componentType": "float", + "bits": { "depth": 32 }, + "glInternalFormat": "GL_DEPTH_COMPONENT32F" + }, + "R11G11B10_FLOAT": { + "texFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "srvFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "rtvFormat": "DXGI_FORMAT_R11G11B10_FLOAT", + "channels": "rgb", + "componentType": "float", + "bits": { "red": 11, "green": 11, "blue": 10 }, + "glInternalFormat": "GL_R11F_G11F_B10F" + }, + "R16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16_FLOAT", + "channels": "r", + "componentType": "float", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16F" + }, + "R16_SINT": { + "texFormat": "DXGI_FORMAT_R16_SINT", + "srvFormat": "DXGI_FORMAT_R16_SINT", + "rtvFormat": "DXGI_FORMAT_R16_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16I" + }, + "R16_UINT": { + "texFormat": "DXGI_FORMAT_R16_UINT", + "srvFormat": "DXGI_FORMAT_R16_UINT", + "rtvFormat": "DXGI_FORMAT_R16_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16UI" + }, + "R32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32_FLOAT", + "channels": "r", + "componentType": "float", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32F" + }, + "R32_SINT": { + "texFormat": "DXGI_FORMAT_R32_SINT", + "srvFormat": "DXGI_FORMAT_R32_SINT", + "rtvFormat": "DXGI_FORMAT_R32_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32I" + }, + "R32_UINT": { + "texFormat": "DXGI_FORMAT_R32_UINT", + "srvFormat": "DXGI_FORMAT_R32_UINT", + "rtvFormat": "DXGI_FORMAT_R32_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 32 }, + "glInternalFormat": "GL_R32UI" + }, + "R8_UNORM": { + "texFormat": "DXGI_FORMAT_R8_UNORM", + "srvFormat": "DXGI_FORMAT_R8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8_UNORM", + "channels": "r", + "componentType": "unorm", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8" + }, + "R8_SINT": { + "texFormat": "DXGI_FORMAT_R8_SINT", + "srvFormat": "DXGI_FORMAT_R8_SINT", + "rtvFormat": "DXGI_FORMAT_R8_SINT", + "channels": "r", + "componentType": "int", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8I" + }, + "R8_UINT": { + "texFormat": "DXGI_FORMAT_R8_UINT", + "srvFormat": "DXGI_FORMAT_R8_UINT", + "rtvFormat": "DXGI_FORMAT_R8_UINT", + "channels": "r", + "componentType": "uint", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8UI" + }, + "R8_SNORM": { + "texFormat": "DXGI_FORMAT_R8_SNORM", + "srvFormat": "DXGI_FORMAT_R8_SNORM", + "channels": "r", + "componentType": "snorm", + "bits": { "red": 8 }, + "glInternalFormat": "GL_R8_SNORM" + }, + "R16G16_FLOAT": { + "texFormat": "DXGI_FORMAT_R16G16_FLOAT", + "srvFormat": "DXGI_FORMAT_R16G16_FLOAT", + "rtvFormat": "DXGI_FORMAT_R16G16_FLOAT", + "channels": "rg", + "componentType": "float", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16F" + }, + "R16G16_SINT": { + "texFormat": "DXGI_FORMAT_R16G16_SINT", + "srvFormat": "DXGI_FORMAT_R16G16_SINT", + "rtvFormat": "DXGI_FORMAT_R16G16_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16I" + }, + "R16G16_UINT": { + "texFormat": "DXGI_FORMAT_R16G16_UINT", + "srvFormat": "DXGI_FORMAT_R16G16_UINT", + "rtvFormat": "DXGI_FORMAT_R16G16_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16UI" + }, + "R32G32_FLOAT": { + "texFormat": "DXGI_FORMAT_R32G32_FLOAT", + "srvFormat": "DXGI_FORMAT_R32G32_FLOAT", + "rtvFormat": "DXGI_FORMAT_R32G32_FLOAT", + "channels": "rg", + "componentType": "float", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32F" + }, + "R32G32_SINT": { + "texFormat": "DXGI_FORMAT_R32G32_SINT", + "srvFormat": "DXGI_FORMAT_R32G32_SINT", + "rtvFormat": "DXGI_FORMAT_R32G32_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32I" + }, + "R32G32_UINT": { + "texFormat": "DXGI_FORMAT_R32G32_UINT", + "srvFormat": "DXGI_FORMAT_R32G32_UINT", + "rtvFormat": "DXGI_FORMAT_R32G32_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 32, "green": 32 }, + "glInternalFormat": "GL_RG32UI" + }, + "R8G8_UNORM": { + "texFormat": "DXGI_FORMAT_R8G8_UNORM", + "srvFormat": "DXGI_FORMAT_R8G8_UNORM", + "rtvFormat": "DXGI_FORMAT_R8G8_UNORM", + "channels": "rg", + "componentType": "unorm", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8" + }, + "R8G8_SINT": { + "texFormat": "DXGI_FORMAT_R8G8_SINT", + "srvFormat": "DXGI_FORMAT_R8G8_SINT", + "rtvFormat": "DXGI_FORMAT_R8G8_SINT", + "channels": "rg", + "componentType": "int", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8I" + }, + "R8G8_UINT": { + "texFormat": "DXGI_FORMAT_R8G8_UINT", + "srvFormat": "DXGI_FORMAT_R8G8_UINT", + "rtvFormat": "DXGI_FORMAT_R8G8_UINT", + "channels": "rg", + "componentType": "uint", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8UI" + }, + "R8G8_SNORM": { + "texFormat": "DXGI_FORMAT_R8G8_SNORM", + "srvFormat": "DXGI_FORMAT_R8G8_SNORM", + "channels": "rg", + "componentType": "snorm", + "bits": { "red": 8, "green": 8 }, + "glInternalFormat": "GL_RG8_SNORM" + }, + "R10G10B10A2_UNORM": { + "texFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "srvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UNORM", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 10, "green": 10, "blue": 10, "alpha": 2 }, + "glInternalFormat": "GL_RGB10_A2" + }, + "R10G10B10A2_UINT": { + "texFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "srvFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "rtvFormat": "DXGI_FORMAT_R10G10B10A2_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 10, "green": 10, "blue": 10, "alpha": 2 }, + "glInternalFormat": "GL_RGB10_A2UI" + }, + "R16G16B16A16_SINT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16I" + }, + "R16G16B16A16_UINT": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "rtvFormat": "DXGI_FORMAT_R16G16B16A16_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16UI" + }, + "R32G32B32A32_SINT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32I" + }, + "R32G32B32A32_UINT": { + "texFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "srvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "rtvFormat": "DXGI_FORMAT_R32G32B32A32_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 32, "green": 32, "blue": 32, "alpha": 32 }, + "glInternalFormat": "GL_RGBA32UI" + }, + "B5G6R5_UNORM": { + "texFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "srvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G6R5_UNORM", + "channels": "bgr", + "componentType": "unorm", + "bits": { "red": 5, "green": 6, "blue": 5 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "B5G5R5A1_UNORM": { + "texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "srvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "rtvFormat": "DXGI_FORMAT_B5G5R5A1_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 5, "green": 5, "blue": 5, "alpha": 1 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B5G5R5A1_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_SINT": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_SINT", + "channels": "rgba", + "componentType": "int", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8I" + }, + "R8G8B8A8_UINT": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UINT", + "channels": "rgba", + "componentType": "uint", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8UI" + }, + "R8G8B8A8_SNORM": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_SNORM", + "channels": "rgba", + "componentType": "snorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_RGBA8_SNORM" + }, + "R9G9B9E5_SHAREDEXP": { + "texFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "srvFormat": "DXGI_FORMAT_R9G9B9E5_SHAREDEXP", + "channels": "rgb", + "componentType": "float", + "bits": { "red": 9, "green": 9, "blue": 9, "shared": 5 } + }, + "B4G4R4A4_UNORM": { + "texFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "srvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "rtvFormat": "DXGI_FORMAT_B4G4R4A4_UNORM", + "channels": "bgra", + "componentType": "unorm", + "bits": { "red": 4, "green": 4, "blue": 4, "alpha": 4 }, + "supportTest": "SupportsFormat(DXGI_FORMAT_B4G4R4A4_UNORM, deviceCaps)", + "fallbackFormat": "R8G8B8A8_UNORM" + }, + "R8G8B8A8_UNORM_SRGB": { + "texFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "srvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "rtvFormat": "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB", + "channels": "rgba", + "componentType": "unorm", + "bits": { "red": 8, "green": 8, "blue": 8, "alpha": 8 }, + "glInternalFormat": "GL_SRGB8_ALPHA8" + }, + "R16_UNORM": { + "texFormat": "DXGI_FORMAT_R16_UNORM", + "srvFormat": "DXGI_FORMAT_R16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16_UNORM", + "channels": "r", + "componentType": "unorm", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16_EXT" + }, + "R16G16_UNORM": { + "texFormat": "DXGI_FORMAT_R16G16_UNORM", + "srvFormat": "DXGI_FORMAT_R16G16_UNORM", + "rtvFormat": "DXGI_FORMAT_R16G16_UNORM", + "channels": "rg", + "componentType": "unorm", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16_EXT" + }, + "R16_SNORM": { + "texFormat": "DXGI_FORMAT_R16_SNORM", + "srvFormat": "DXGI_FORMAT_R16_SNORM", + "channels": "r", + "componentType": "snorm", + "bits": { "red": 16 }, + "glInternalFormat": "GL_R16_SNORM_EXT" + }, + "R16G16_SNORM": { + "texFormat": "DXGI_FORMAT_R16G16_SNORM", + "srvFormat": "DXGI_FORMAT_R16G16_SNORM", + "channels": "rg", + "componentType": "snorm", + "bits": { "red": 16, "green": 16 }, + "glInternalFormat": "GL_RG16_SNORM_EXT" + }, + "R16G16B16A16_SNORM": { + "texFormat": "DXGI_FORMAT_R16G16B16A16_SNORM", + "srvFormat": "DXGI_FORMAT_R16G16B16A16_SNORM", + "channels": "rgba", + "componentType": "snorm", + "bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }, + "glInternalFormat": "GL_RGBA16_SNORM_EXT" + } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json new file mode 100644 index 0000000000..3ef2355645 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_map.json @@ -0,0 +1,78 @@ +{ + "GL_ALPHA16F_EXT": "R16G16B16A16_FLOAT", + "GL_ALPHA32F_EXT": "R32G32B32A32_FLOAT", + "GL_BGR5_A1_ANGLEX": "B8G8R8A8_UNORM", + "GL_BGRA4_ANGLEX": "B8G8R8A8_UNORM", + "GL_BGRA8_SRGB_ANGLEX": "B8G8R8A8_UNORM_SRGB", + "GL_COMPRESSED_R11_EAC": "R8_UNORM", + "GL_COMPRESSED_RG11_EAC": "R8G8_UNORM", + "GL_COMPRESSED_RGB8_ETC2": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGBA8_ETC2_EAC": "R8G8B8A8_UNORM", + "GL_COMPRESSED_RGBA_ASTC_4x4_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_5x4_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_5x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_6x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_6x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_8x8_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x5_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x6_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x8_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_10x10_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_12x10_KHR": "NONE", + "GL_COMPRESSED_RGBA_ASTC_12x12_KHR": "NONE", + "GL_COMPRESSED_SIGNED_R11_EAC": "R8_SNORM", + "GL_COMPRESSED_SIGNED_RG11_EAC": "R8G8_SNORM", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR": "NONE", + "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": "R8G8B8A8_UNORM_SRGB", + "GL_COMPRESSED_SRGB8_ETC2": "R8G8B8A8_UNORM_SRGB", + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": "R8G8B8A8_UNORM_SRGB", + "GL_DEPTH_COMPONENT24": "D24_UNORM_S8_UINT", + "GL_DEPTH_COMPONENT32_OES": "D24_UNORM_S8_UINT", + "GL_ETC1_RGB8_OES": "R8G8B8A8_UNORM", + "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": "BC1_RGB_UNORM_BLOCK", + "GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGB_UNORM_BLOCK", + "GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGB_UNORM_SRGB_BLOCK", + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGBA_UNORM_BLOCK", + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": "BC1_RGBA_UNORM_SRGB_BLOCK", + "GL_LUMINANCE16F_EXT": "R16G16B16A16_FLOAT", + "GL_LUMINANCE32F_EXT": "R32G32B32A32_FLOAT", + "GL_LUMINANCE8_ALPHA8_EXT": "R8G8B8A8_UNORM", + "GL_LUMINANCE8_EXT": "R8G8B8A8_UNORM", + "GL_LUMINANCE_ALPHA16F_EXT": "R16G16B16A16_FLOAT", + "GL_LUMINANCE_ALPHA32F_EXT": "R32G32B32A32_FLOAT", + "GL_RGB": "R8G8B8A8_UNORM", + "GL_RGB16F": "R16G16B16A16_FLOAT", + "GL_RGB16I": "R16G16B16A16_SINT", + "GL_RGB16UI": "R16G16B16A16_UINT", + "GL_RGB565": "B5G6R5_UNORM", + "GL_RGB5_A1": "B5G5R5A1_UNORM", + "GL_RGB8": "R8G8B8A8_UNORM", + "GL_RGB8I": "R8G8B8A8_SINT", + "GL_RGB8UI": "R8G8B8A8_UINT", + "GL_RGB8_SNORM": "R8G8B8A8_SNORM", + "GL_RGBA4": "B4G4R4A4_UNORM", + "GL_SRGB8": "R8G8B8A8_UNORM_SRGB", + "GL_STENCIL_INDEX8": "D24_UNORM_S8_UINT", + "GL_RGB16_EXT": "R16G16B16A16_UNORM", + "GL_RGBA16_EXT": "R16G16B16A16_UNORM", + "GL_RGB16_SNORM_EXT": "R16G16B16A16_SNORM", + "GL_RGB32F": "R32G32B32A32_FLOAT", + "GL_RGB32I": "R32G32B32A32_SINT", + "GL_RGB32UI": "R32G32B32A32_UINT" +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp new file mode 100644 index 0000000000..a9dfec56b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table.cpp @@ -0,0 +1,35 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Helper routines for the D3D11 texture format table. + +#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" + +#include "libANGLE/renderer/load_functions_table.h" + +namespace rx +{ + +namespace d3d11 +{ + +const Format &Format::getSwizzleFormat(const Renderer11DeviceCaps &deviceCaps) const +{ + return (swizzleFormat == internalFormat ? *this : Format::Get(swizzleFormat, deviceCaps)); +} + +LoadFunctionMap Format::getLoadFunctions() const +{ + return GetLoadFunctionsMap(internalFormat, formatID); +} + +const angle::Format &Format::format() const +{ + return angle::Format::Get(formatID); +} + +} // namespace d3d11 + +} // namespace rx 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 index 1606a28a73..3efcb81adb 100644 --- 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 @@ -12,50 +12,91 @@ #include +#include "common/angleutils.h" #include "common/platform.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" namespace rx { -namespace d3d11 -{ +struct Renderer11DeviceCaps; -struct LoadImageFunctionInfo +namespace d3d11 { - LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} - LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) - : loadFunction(loadFunction), requiresConversion(requiresConversion) - { - } - - LoadImageFunction loadFunction; - bool requiresConversion; -}; -struct TextureFormat +// For sized GL internal formats, there are several possible corresponding D3D11 formats depending +// on device capabilities. +// This structure allows querying for the DXGI texture formats to use for textures, SRVs, RTVs and +// DSVs given a GL internal format. +struct Format final : private angle::NonCopyable { - TextureFormat(); + constexpr Format(); + constexpr Format(GLenum internalFormat, + angle::Format::ID formatID, + DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, + DXGI_FORMAT rtvFormat, + DXGI_FORMAT dsvFormat, + DXGI_FORMAT blitSRVFormat, + GLenum swizzleFormat, + InitializeTextureDataFunction internalFormatInitializer); + + static const Format &Get(GLenum internalFormat, const Renderer11DeviceCaps &deviceCaps); + + const Format &getSwizzleFormat(const Renderer11DeviceCaps &deviceCaps) const; + LoadFunctionMap getLoadFunctions() const; + const angle::Format &format() const; + + GLenum internalFormat; + angle::Format::ID formatID; DXGI_FORMAT texFormat; DXGI_FORMAT srvFormat; DXGI_FORMAT rtvFormat; DXGI_FORMAT dsvFormat; - DXGI_FORMAT renderFormat; - DXGI_FORMAT swizzleTexFormat; - DXGI_FORMAT swizzleSRVFormat; - DXGI_FORMAT swizzleRTVFormat; + DXGI_FORMAT blitSRVFormat; - InitializeTextureDataFunction dataInitializerFunction; - typedef std::map LoadFunctionMap; + GLenum swizzleFormat; - LoadFunctionMap loadFunctions; + InitializeTextureDataFunction dataInitializerFunction; }; -const TextureFormat &GetTextureFormatInfo(GLenum internalformat, - const Renderer11DeviceCaps &renderer11DeviceCaps); +constexpr Format::Format() + : internalFormat(GL_NONE), + formatID(angle::Format::ID::NONE), + texFormat(DXGI_FORMAT_UNKNOWN), + srvFormat(DXGI_FORMAT_UNKNOWN), + rtvFormat(DXGI_FORMAT_UNKNOWN), + dsvFormat(DXGI_FORMAT_UNKNOWN), + blitSRVFormat(DXGI_FORMAT_UNKNOWN), + swizzleFormat(GL_NONE), + dataInitializerFunction(nullptr) +{ +} + +constexpr Format::Format(GLenum internalFormat, + angle::Format::ID formatID, + DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, + DXGI_FORMAT rtvFormat, + DXGI_FORMAT dsvFormat, + DXGI_FORMAT blitSRVFormat, + GLenum swizzleFormat, + InitializeTextureDataFunction internalFormatInitializer) + : internalFormat(internalFormat), + formatID(formatID), + texFormat(texFormat), + srvFormat(srvFormat), + rtvFormat(rtvFormat), + dsvFormat(dsvFormat), + blitSRVFormat(blitSRVFormat), + swizzleFormat(swizzleFormat), + dataInitializerFunction(internalFormatInitializer) +{ +} } // namespace d3d11 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 index 0b214c9756..3c1c2bcd50 100644 --- 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 @@ -1,7 +1,7 @@ // 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. +// Copyright 2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -11,12 +11,15 @@ #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.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" +#include "libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h" + +using namespace angle; namespace rx { @@ -24,1756 +27,1899 @@ 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) +// static +const Format &Format::Get(GLenum internalFormat, const Renderer11DeviceCaps &deviceCaps) { // 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; - } + static constexpr Format info(GL_ALPHA16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_ALPHA32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } 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)) + if (OnlyFL10Plus(deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_ALPHA8_EXT, + angle::Format::ID::A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_A8_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_ALPHA8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } - case GL_BGR5_A1_ANGLEX: + case GL_BGR565_ANGLEX: { - if (AnyDevice(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_BGR565_ANGLEX, + angle::Format::ID::B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G6R5_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_BGR565_ANGLEX, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } - case GL_BGRA4_ANGLEX: + 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; - } + static constexpr Format info(GL_BGR5_A1_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; } - case GL_BGRA8_EXT: + 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; - } + static constexpr Format info(GL_BGRA4_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; } - case GL_BGRA_EXT: + 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; - } + static constexpr Format info(GL_BGRA8_EXT, + angle::Format::ID::B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM, + GL_BGRA8_EXT, + nullptr); + return info; + } + case GL_BGRA8_SRGB_ANGLEX: + { + static constexpr Format info(GL_BGRA8_SRGB_ANGLEX, + angle::Format::ID::B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + GL_BGRA8_SRGB_ANGLEX, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_R11_EAC, + angle::Format::ID::R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RG11_EAC, + angle::Format::ID::R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGB8_ETC2, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGBA8_ETC2_EAC, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, + angle::Format::ID::BC2_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC2_UNORM, + DXGI_FORMAT_BC2_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC2_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, + angle::Format::ID::BC3_RGBA_UNORM_BLOCK, + DXGI_FORMAT_BC3_UNORM, + DXGI_FORMAT_BC3_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC3_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_SIGNED_R11_EAC, + angle::Format::ID::R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_SIGNED_RG11_EAC, + angle::Format::ID::R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_ETC2, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + Initialize4ComponentData); + return info; + } + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + static constexpr Format info(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE, + angle::Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, + angle::Format::ID::BC2_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC2_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, + angle::Format::ID::BC3_RGBA_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC3_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; + } + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + { + static constexpr Format info(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, + angle::Format::ID::BC1_RGB_UNORM_SRGB_BLOCK, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM_SRGB, + GL_RGBA8, + nullptr); + return info; } 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)) + if (OnlyFL10Plus(deviceCaps)) { - 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; + static constexpr Format info(GL_DEPTH24_STENCIL8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH24_STENCIL8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } 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; - } + static constexpr Format info(GL_DEPTH32F_STENCIL8, + angle::Format::ID::D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_R32G8X24_TYPELESS, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } case GL_DEPTH_COMPONENT16: { - if (OnlyFL9_3(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - 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; + static constexpr Format info(GL_DEPTH_COMPONENT16, + angle::Format::ID::D16_UNORM, + DXGI_FORMAT_R16_TYPELESS, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_R16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT16, + angle::Format::ID::D16_UNORM, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_UNKNOWN, + GL_RGBA16_EXT, + nullptr); + return info; } } 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)) + if (OnlyFL10Plus(deviceCaps)) { - 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; + static constexpr Format info(GL_DEPTH_COMPONENT24, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT24, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } 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; - } + static constexpr Format info(GL_DEPTH_COMPONENT32F, + angle::Format::ID::D32_FLOAT, + DXGI_FORMAT_R32_TYPELESS, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } case GL_DEPTH_COMPONENT32_OES: { - if (OnlyFL10Plus(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - 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; + static constexpr Format info(GL_DEPTH_COMPONENT32_OES, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_DEPTH_COMPONENT32_OES, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } 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; - } + static constexpr Format info(GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, + angle::Format::ID::BC1_RGB_UNORM_BLOCK, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_BC1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_BC1_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_ETC1_RGB8_OES, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE8_ALPHA8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE8_EXT, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE_ALPHA16F_EXT, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_LUMINANCE_ALPHA32F_EXT, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_NONE, + angle::Format::ID::NONE, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + GL_NONE, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R11F_G11F_B10F, + angle::Format::ID::R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_R11G11B10_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R11G11B10_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R16F, + angle::Format::ID::R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R16I, + angle::Format::ID::R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_SINT, + GL_RGBA16I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R16UI, + angle::Format::ID::R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_R16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_UINT, + GL_RGBA16I, + nullptr); + return info; + } + case GL_R16_EXT: + { + static constexpr Format info(GL_R16_EXT, + angle::Format::ID::R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_R16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_R16_SNORM_EXT: + { + static constexpr Format info(GL_R16_SNORM_EXT, + angle::Format::ID::R16_SNORM, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R32F, + angle::Format::ID::R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R32I, + angle::Format::ID::R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_R32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_SINT, + GL_RGBA32I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R32UI, + angle::Format::ID::R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_R32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32_UINT, + GL_RGBA32I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R8, + angle::Format::ID::R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R8I, + angle::Format::ID::R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_R8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SINT, + GL_RGBA8I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R8UI, + angle::Format::ID::R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_R8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_UINT, + GL_RGBA8I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_R8_SNORM, + angle::Format::ID::R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_R8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG16F, + angle::Format::ID::R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_FLOAT, + GL_RGBA16F_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG16I, + angle::Format::ID::R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_SINT, + GL_RGBA16I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG16UI, + angle::Format::ID::R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_UINT, + GL_RGBA16I, + nullptr); + return info; + } + case GL_RG16_EXT: + { + static constexpr Format info(GL_RG16_EXT, + angle::Format::ID::R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_RG16_SNORM_EXT: + { + static constexpr Format info(GL_RG16_SNORM_EXT, + angle::Format::ID::R16G16_SNORM, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG32F, + angle::Format::ID::R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG32I, + angle::Format::ID::R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_R32G32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_SINT, + GL_RGBA32I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG32UI, + angle::Format::ID::R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_R32G32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32_UINT, + GL_RGBA32I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG8, + angle::Format::ID::R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG8I, + angle::Format::ID::R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_R8G8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SINT, + GL_RGBA8I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG8UI, + angle::Format::ID::R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_R8G8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_UINT, + GL_RGBA8I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RG8_SNORM, + angle::Format::ID::R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_R8G8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGB, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB10_A2, + angle::Format::ID::R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_R10G10B10A2_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R10G10B10A2_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGB10_A2UI, + angle::Format::ID::R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_R10G10B10A2_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R10G10B10A2_UINT, + GL_RGBA16I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGB16F, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB16I, + angle::Format::ID::R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SINT, + GL_RGBA16I, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB16UI, + angle::Format::ID::R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UINT, + GL_RGBA16UI, + Initialize4ComponentData); + return info; + } + case GL_RGB16_EXT: + { + static constexpr Format info(GL_RGB16_EXT, + angle::Format::ID::R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UNORM, + GL_RGBA16_EXT, + Initialize4ComponentData); + return info; + } + case GL_RGB16_SNORM_EXT: + { + static constexpr Format info(GL_RGB16_SNORM_EXT, + angle::Format::ID::R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SNORM, + GL_RGBA16_SNORM_EXT, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB32F, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB32I, + angle::Format::ID::R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_SINT, + GL_RGBA32I, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB32UI, + angle::Format::ID::R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_UINT, + GL_RGBA32UI, + Initialize4ComponentData); + return info; } case GL_RGB565: { - if (SupportsFormat(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B5G6R5_UNORM, deviceCaps)) { - 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; + static constexpr Format info(GL_RGB565, + angle::Format::ID::B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_B5G6R5_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G6R5_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGB565, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } } 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)) + if (SupportsFormat(DXGI_FORMAT_B5G5R5A1_UNORM, deviceCaps)) { - static const TextureFormat textureFormat = GetD3D11FormatInfo(internalFormat, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_B5G5R5A1_UNORM, - DXGI_FORMAT_UNKNOWN); - return textureFormat; + static constexpr Format info(GL_RGB5_A1, + angle::Format::ID::B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_B5G5R5A1_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B5G5R5A1_UNORM, + GL_RGBA8, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGB5_A1, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } 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; - } + static constexpr Format info(GL_RGB8, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB8I, + angle::Format::ID::R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SINT, + GL_RGBA8I, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB8UI, + angle::Format::ID::R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UINT, + GL_RGBA8UI, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB8_SNORM, + angle::Format::ID::R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SNORM, + GL_RGBA8_SNORM, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_RGB9_E5, + angle::Format::ID::R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + GL_RGBA16F_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA16F, + angle::Format::ID::R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_FLOAT, + GL_RGBA16F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA16I, + angle::Format::ID::R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SINT, + GL_RGBA16I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA16UI, + angle::Format::ID::R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_R16G16B16A16_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UINT, + GL_RGBA16UI, + nullptr); + return info; + } + case GL_RGBA16_EXT: + { + static constexpr Format info(GL_RGBA16_EXT, + angle::Format::ID::R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_UNORM, + GL_RGBA16_EXT, + nullptr); + return info; + } + case GL_RGBA16_SNORM_EXT: + { + static constexpr Format info(GL_RGBA16_SNORM_EXT, + angle::Format::ID::R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R16G16B16A16_SNORM, + GL_RGBA16_SNORM_EXT, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA32F, + angle::Format::ID::R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_FLOAT, + GL_RGBA32F, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA32I, + angle::Format::ID::R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_R32G32B32A32_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_SINT, + GL_RGBA32I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA32UI, + angle::Format::ID::R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_R32G32B32A32_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32A32_UINT, + GL_RGBA32UI, + nullptr); + return info; } case GL_RGBA4: { - if (SupportsFormat(renderer11DeviceCaps)) + if (SupportsFormat(DXGI_FORMAT_B4G4R4A4_UNORM, deviceCaps)) { - 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; + static constexpr Format info(GL_RGBA4, + angle::Format::ID::B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_B4G4R4A4_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_B4G4R4A4_UNORM, + GL_RGBA4, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_RGBA4, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } } 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; - } + static constexpr Format info(GL_RGBA8, + angle::Format::ID::R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM, + GL_RGBA8, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA8I, + angle::Format::ID::R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_R8G8B8A8_SINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SINT, + GL_RGBA8I, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA8UI, + angle::Format::ID::R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UINT, + GL_RGBA8UI, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_RGBA8_SNORM, + angle::Format::ID::R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_R8G8B8A8_SNORM, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_SNORM, + GL_RGBA8_SNORM, + nullptr); + return info; } 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; - } + static constexpr Format info(GL_SRGB8, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + Initialize4ComponentData); + return info; } 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; - } + static constexpr Format info(GL_SRGB8_ALPHA8, + angle::Format::ID::R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + GL_SRGB8_ALPHA8, + nullptr); + return info; } case GL_STENCIL_INDEX8: { - if (OnlyFL9_3(renderer11DeviceCaps)) + if (OnlyFL10Plus(deviceCaps)) { - 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; + static constexpr Format info(GL_STENCIL_INDEX8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_R24G8_TYPELESS, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, + GL_RGBA32F, + nullptr); + return info; } else { - break; + static constexpr Format info(GL_STENCIL_INDEX8, + angle::Format::ID::D24_UNORM_S8_UINT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_UNKNOWN, + GL_RGBA32F, + nullptr); + return info; } } @@ -1782,9 +1928,10 @@ const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, } // clang-format on - static const TextureFormat defaultInfo; + UNREACHABLE(); + static constexpr Format defaultInfo; return defaultInfo; -} // GetTextureFormatInfo +} } // namespace d3d11 diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h new file mode 100644 index 0000000000..d5351ff882 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/texture_format_table_utils.h @@ -0,0 +1,85 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Helper routines for the D3D11 texture format table. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +namespace d3d11 +{ + +using FormatSupportFunction = bool (*)(const Renderer11DeviceCaps &); + +inline bool OnlyFL10Plus(const Renderer11DeviceCaps &deviceCaps) +{ + return (deviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0); +} + +inline bool OnlyFL9_3(const Renderer11DeviceCaps &deviceCaps) +{ + return (deviceCaps.featureLevel == D3D_FEATURE_LEVEL_9_3); +} + +inline bool SupportsFormat(DXGI_FORMAT format, 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; + UINT minimumRequiredSamples = 0; + + if (d3d11_gl::GetMaximumClientVersion(deviceCaps.featureLevel).major > 2) + { + mustSupport |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + + // RGBA4, RGB5A1 and RGB565 are all required multisampled renderbuffer formats in ES3 and + // need to support a minimum of 4 samples. + minimumRequiredSamples = 4; + } + + 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) && + deviceCaps.B5G6R5maxSamples >= minimumRequiredSamples; + } + else if (format == DXGI_FORMAT_B4G4R4A4_UNORM) + { + fullSupport = ((deviceCaps.B4G4R4A4support & mustSupport) == mustSupport) && + deviceCaps.B4G4R4A4maxSamples >= minimumRequiredSamples; + } + else if (format == DXGI_FORMAT_B5G5R5A1_UNORM) + { + fullSupport = ((deviceCaps.B5G5R5A1support & mustSupport) == mustSupport) && + deviceCaps.B5G5R5A1maxSamples >= minimumRequiredSamples; + } + else + { + UNREACHABLE(); + return false; + } + + // 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; +} + +} // namespace d3d11 + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURE_FORMAT_TABLE_UTILS_H_ 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 deleted file mode 100644 index da6460b136..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// -// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// 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, - 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; -} - -bool NativeWindow::getClientRect(LPRECT rect) -{ - return GetClientRect(mWindow, rect) == TRUE; -} - -bool NativeWindow::isIconic() -{ - return IsIconic(mWindow) == TRUE; -} - -bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) -{ - return IsWindow(window) == TRUE; -} - -#if defined(ANGLE_ENABLE_D3D11) -HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, - DXGI_FORMAT format, unsigned int width, unsigned int height, - DXGISwapChain** swapChain) -{ - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) - { - return E_INVALIDARG; - } - -#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; - swapChainDesc.BufferDesc.Height = height; - swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - 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_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER; - swapChainDesc.Flags = 0; - swapChainDesc.OutputWindow = mWindow; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Windowed = TRUE; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - - const HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, swapChain); - if (SUCCEEDED(result)) - { - const HRESULT makeWindowAssociationResult = factory->MakeWindowAssociation(mWindow, DXGI_MWA_NO_ALT_ENTER); - 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/win32/NativeWindow11Win32.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp new file mode 100644 index 0000000000..5394e3d3e7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11Win32.cpp: Implementation of NativeWindow11 using win32 window APIs. + +#include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +#include "common/debug.h" + +#include +#include + +namespace rx +{ + +NativeWindow11Win32::NativeWindow11Win32(EGLNativeWindowType window, + bool hasAlpha, + bool directComposition) + : NativeWindow11(window), + mDirectComposition(directComposition), + mHasAlpha(hasAlpha), + mDevice(nullptr), + mCompositionTarget(nullptr), + mVisual(nullptr) +{ +} + +NativeWindow11Win32::~NativeWindow11Win32() +{ + SafeRelease(mCompositionTarget); + SafeRelease(mDevice); + SafeRelease(mVisual); +} + +bool NativeWindow11Win32::initialize() +{ + return true; +} + +bool NativeWindow11Win32::getClientRect(LPRECT rect) const +{ + return GetClientRect(getNativeWindow(), rect) == TRUE; +} + +bool NativeWindow11Win32::isIconic() const +{ + return IsIconic(getNativeWindow()) == TRUE; +} + +HRESULT NativeWindow11Win32::createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) +{ + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) + { + return E_INVALIDARG; + } + + 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(getNativeWindow(), 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 = + mHasAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; + 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 = samples; + 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, getNativeWindow(), &swapChainDesc, + nullptr, nullptr, &swapChain1); + if (SUCCEEDED(result)) + { + factory2->MakeWindowAssociation(getNativeWindow(), DXGI_MWA_NO_ALT_ENTER); + *swapChain = static_cast(swapChain1); + } + SafeRelease(factory2); + return result; + } + + DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; + swapChainDesc.BufferCount = 1; + swapChainDesc.BufferDesc.Format = format; + swapChainDesc.BufferDesc.Width = width; + swapChainDesc.BufferDesc.Height = height; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + 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_SHADER_INPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.Flags = 0; + swapChainDesc.OutputWindow = getNativeWindow(); + swapChainDesc.SampleDesc.Count = samples; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, swapChain); + if (SUCCEEDED(result)) + { + factory->MakeWindowAssociation(getNativeWindow(), DXGI_MWA_NO_ALT_ENTER); + } + return result; +} + +void NativeWindow11Win32::commitChange() +{ + if (mDevice) + { + mDevice->Commit(); + } +} + +// static +bool NativeWindow11Win32::IsValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h new file mode 100644 index 0000000000..baeba6a347 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11Win32.h: Implementation of NativeWindow11 using win32 window APIs. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" + +typedef interface IDCompositionDevice IDCompositionDevice; +typedef interface IDCompositionTarget IDCompositionTarget; +typedef interface IDCompositionVisual IDCompositionVisual; + +namespace rx +{ + +class NativeWindow11Win32 : public NativeWindow11 +{ + public: + NativeWindow11Win32(EGLNativeWindowType window, bool hasAlpha, bool directComposition); + ~NativeWindow11Win32() override; + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) override; + + void commitChange() override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); + + private: + bool mDirectComposition; + bool mHasAlpha; + IDCompositionDevice *mDevice; + IDCompositionTarget *mCompositionTarget; + IDCompositionVisual *mVisual; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WIN32_NATIVEWINDOW11WIN32_H_ 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 f401db614b..1ef90e7b09 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 @@ -8,6 +8,8 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include + using namespace ABI::Windows::Foundation::Collections; namespace rx @@ -19,7 +21,6 @@ CoreWindowNativeWindow::~CoreWindowNativeWindow() bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) { - mOrientationChangedEventToken.value = 0; ComPtr props = propertySet; ComPtr win = window; SIZE swapChainSize = {}; @@ -63,7 +64,8 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet // 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."); + ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a " + "EGLRenderResolutionScaleProperty."; return false; } } @@ -87,26 +89,16 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet } else { - SIZE coreWindowSize; + Size coreWindowSize; result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize); if (SUCCEEDED(result)) { - mClientRect = { 0, 0, static_cast(coreWindowSize.cx * mSwapChainScale), static_cast(coreWindowSize.cy * mSwapChainScale) }; + mClientRect = clientRect(coreWindowSize); } } } - if (SUCCEEDED(result)) - { - ComPtr displayInformation; - result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), &displayInformation); - if (SUCCEEDED(result)) - { - result = displayInformation->GetForCurrentView(&mDisplayInformation); - } - } - if (SUCCEEDED(result)) { mNewClientRect = mClientRect; @@ -126,16 +118,6 @@ bool CoreWindowNativeWindow::registerForSizeChangeEvents() result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); } -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - ComPtr orientationChangedHandler; - result = sizeChangedHandler.As(&orientationChangedHandler); - if (SUCCEEDED(result)) - { - result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); - orientationChangedHandler->Invoke(mDisplayInformation.Get(), nullptr); - } -#endif - if (SUCCEEDED(result)) { return true; @@ -150,34 +132,26 @@ 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, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) + IDXGISwapChain1 **swapChain) { - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) { return E_INVALIDARG; } DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; - swapChainDesc.Width = mRotationFlags ? height : width; - swapChainDesc.Height = mRotationFlags ? width : height; + swapChainDesc.Width = width; + swapChainDesc.Height = height; swapChainDesc.Format = format; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; @@ -195,17 +169,6 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); if (SUCCEEDED(result)) { - -#if 0 //(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // Qt: allow Windows Phone to resize, but don't modify the backing texture in the swap chain. - // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On - // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed - // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. - if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED) - { - mSupportsSwapChainResize = false; - } -#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - result = newSwapChain.CopyTo(swapChain); } @@ -222,14 +185,16 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, return result; } -inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect) +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) +HRESULT GetCoreWindowSizeInPixels(const ComPtr &coreWindow, + Size *windowSize) { ABI::Windows::Foundation::Rect bounds; HRESULT result = coreWindow->get_Bounds(&bounds); 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 fc1cd124a1..21855c2c3b 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 @@ -12,10 +12,10 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" #include -#include + +#include typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; -typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CDisplay__CDisplayInformation_IInspectable_t IDisplayOrientationEventHandler; namespace rx { @@ -26,12 +26,12 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) override; + IDXGISwapChain1 **swapChain) override; protected: HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; @@ -42,13 +42,11 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl private: ComPtr mCoreWindow; ComPtr> mPropertyMap; - ComPtr mDisplayInformation; - EventRegistrationToken mOrientationChangedEventToken; }; [uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] class CoreWindowSizeChangedHandler : - public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler, IDisplayOrientationEventHandler> + public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler> { public: CoreWindowSizeChangedHandler() { } @@ -72,47 +70,21 @@ class CoreWindowSizeChangedHandler : ABI::Windows::Foundation::Size windowSize; if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) { - host->setNewClientSize(windowSize); + Size windowSizeInPixels = {ConvertDipsToPixels(windowSize.Width), + ConvertDipsToPixels(windowSize.Height)}; + host->setNewClientSize(windowSizeInPixels); } } 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))) - { - 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; - } - - private: std::weak_ptr mHost; }; -HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, SIZE *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 aacfadd2f0..1bd796e58f 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,108 +11,6 @@ namespace rx { -NativeWindow::NativeWindow(EGLNativeWindowType window, - const egl::Config *config, - bool directComposition) -{ - mWindow = window; - mConfig = config; -} - -NativeWindow::~NativeWindow() -{ -} - -void NativeWindow::commitChange() -{ -} - -bool NativeWindow::initialize() -{ - // If the native window type is a IPropertySet, extract the - // EGLNativeWindowType (IInspectable) and initialize the - // proper host with this IPropertySet. - ComPtr propertySet; - ComPtr eglNativeWindow; - if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow)) - { - // A property set was found and the EGLNativeWindowType was - // retrieved. The mWindow member of the host to must be updated - // to use the EGLNativeWindowType specified in the property set. - // mWindow is treated as a raw pointer not an AddRef'd interface, so - // the old mWindow does not need a Release() before this assignment. - mWindow = eglNativeWindow.Get(); - } - - ComPtr coreWindow; - ComPtr swapChainPanel; - if (IsCoreWindow(mWindow, &coreWindow)) - { - mImpl = std::make_shared(); - if (mImpl) - { - return mImpl->initialize(mWindow, propertySet.Get()); - } - } - else if (IsSwapChainPanel(mWindow, &swapChainPanel)) - { - mImpl = std::make_shared(); - if (mImpl) - { - return mImpl->initialize(mWindow, propertySet.Get()); - } - } - else - { - ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet"); - } - - return false; -} - -bool NativeWindow::getClientRect(RECT *rect) -{ - if (mImpl) - { - return mImpl->getClientRect(rect); - } - - return false; -} - -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) -NativeWindow::RotationFlags NativeWindow::rotationFlags() const -{ - if (mImpl) - { - return mImpl->rotationFlags(); - } - - return NativeWindow::RotateNone; -} -#endif - -bool NativeWindow::isIconic() -{ - return false; -} - -bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) -{ - return IsValidEGLNativeWindowType(window); -} - -HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) -{ - if (mImpl) - { - bool containsAlpha = (mConfig->alphaSize > 0); - return mImpl->createSwapChain(device, factory, format, width, height, containsAlpha, - swapChain); - } - - return E_UNEXPECTED; -} bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) { @@ -127,7 +25,7 @@ bool IsCoreWindow(EGLNativeWindowType window, ComPtr> &propertyMap, const wchar_t *propertyName, @@ -381,7 +268,13 @@ HRESULT GetOptionalSinglePropertyValue(const ComPtr(ConvertDipsToPixels(size.Width)), + static_cast(ConvertDipsToPixels(size.Height))}; +} + +float GetLogicalDpi() { ComPtr displayProperties; float dpi = 96.0f; @@ -396,7 +289,7 @@ static float GetLogicalDpi() return dpi; } -long ConvertDipsToPixels(float dips) +float ConvertDipsToPixels(float dips) { static const float dipsPerInch = 96.0f; return lround((dips * GetLogicalDpi() / dipsPerInch)); 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 2d58f1c00a..d81c3e5fb9 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 @@ -10,14 +10,18 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ #define LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ -#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" - +#include "common/debug.h" #include "common/platform.h" #include "angle_windowsstore.h" +#include + +#include #include #include +#include +#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -26,7 +30,8 @@ using namespace ABI::Windows::Foundation::Collections; namespace rx { -long ConvertDipsToPixels(float dips); +float ConvertDipsToPixels(float dips); +float GetLogicalDpi(); class InspectableNativeWindow { @@ -35,24 +40,25 @@ class InspectableNativeWindow mSupportsSwapChainResize(true), mSwapChainSizeSpecified(false), mSwapChainScaleSpecified(false), - mSwapChainScale(1.0f), mClientRectChanged(false), mClientRect({0,0,0,0}), - mNewClientRect({0,0,0,0}), - mRotationFlags(NativeWindow::RotateNone) + mNewClientRect({0,0,0,0}) { mSizeChangedEventToken.value = 0; + mSwapChainScale = 96.0f / GetLogicalDpi(); + if (mSwapChainScale != 1.0f) + mSwapChainScaleSpecified = true; } virtual ~InspectableNativeWindow(){} virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; virtual HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) = 0; + IDXGISwapChain1 **swapChain) = 0; bool getClientRect(RECT *rect) { @@ -77,8 +83,7 @@ class InspectableNativeWindow // 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) }; + mNewClientRect = clientRect(newWindowSize); 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 @@ -97,18 +102,9 @@ class InspectableNativeWindow } } - NativeWindow::RotationFlags rotationFlags() const - { - return mRotationFlags; - } - - void setRotationFlags(NativeWindow::RotationFlags flags) - { - mRotationFlags = flags; - } - protected: virtual HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) = 0; + RECT clientRect(const Size &size); bool mSupportsSwapChainResize; // Support for IDXGISwapChain::ResizeBuffers method bool mSwapChainSizeSpecified; // If an EGLRenderSurfaceSizeProperty was specified @@ -117,12 +113,10 @@ class InspectableNativeWindow RECT mClientRect; RECT mNewClientRect; bool mClientRectChanged; - NativeWindow::RotationFlags mRotationFlags; EventRegistrationToken mSizeChangedEventToken; }; -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); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp new file mode 100644 index 0000000000..655b23be83 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.cpp @@ -0,0 +1,126 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11WinRT.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" + +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +namespace rx +{ +NativeWindow11WinRT::NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha) + : NativeWindow11(window), mHasAlpha(hasAlpha) +{ +} + +bool NativeWindow11WinRT::initialize() +{ + EGLNativeWindowType window = getNativeWindow(); + + // If the native window type is a IPropertySet, extract the + // EGLNativeWindowType (IInspectable) and initialize the + // proper host with this IPropertySet. + ComPtr propertySet; + ComPtr eglNativeWindow; + if (IsEGLConfiguredPropertySet(window, &propertySet, &eglNativeWindow)) + { + // A property set was found and the EGLNativeWindowType was + // retrieved. The mWindow member of the host to must be updated + // to use the EGLNativeWindowType specified in the property set. + // mWindow is treated as a raw pointer not an AddRef'd interface, so + // the old mWindow does not need a Release() before this assignment. + window = eglNativeWindow.Get(); + } + + ComPtr coreWindow; + ComPtr swapChainPanel; + if (IsCoreWindow(window, &coreWindow)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else if (IsSwapChainPanel(window, &swapChainPanel)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(window, propertySet.Get()); + } + } + else + { + ERR() << "Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include " + "ICoreWindow, ISwapChainPanel and IPropertySet"; + } + + return false; +} + +bool NativeWindow11WinRT::getClientRect(LPRECT rect) const +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +bool NativeWindow11WinRT::isIconic() const +{ + return false; +} + +HRESULT NativeWindow11WinRT::createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) +{ + if (mImpl) + { + IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject(factory); + IDXGISwapChain1 *swapChain1 = nullptr; + HRESULT result = + mImpl->createSwapChain(device, factory2, format, width, height, mHasAlpha, &swapChain1); + SafeRelease(factory2); + *swapChain = static_cast(swapChain1); + return result; + } + + return E_UNEXPECTED; +} + +void NativeWindow11WinRT::commitChange() +{ +} + +// static +bool NativeWindow11WinRT::IsValidNativeWindow(EGLNativeWindowType window) +{ + // A Valid EGLNativeWindowType IInspectable can only be: + // + // ICoreWindow + // ISwapChainPanel + // IPropertySet + // + // Anything else will be rejected as an invalid IInspectable. + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h new file mode 100644 index 0000000000..c4ac997a55 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow11WinRT.h: NativeWindow base class for managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h" + +#include +#include +#include +#include + +namespace rx +{ +class InspectableNativeWindow; + +class NativeWindow11WinRT : public NativeWindow11 +{ + public: + NativeWindow11WinRT(EGLNativeWindowType window, bool hasAlpha); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + HRESULT createSwapChain(ID3D11Device *device, + IDXGIFactory *factory, + DXGI_FORMAT format, + UINT width, + UINT height, + UINT samples, + IDXGISwapChain **swapChain) override; + + void commitChange() override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); + + private: + bool mHasAlpha; + std::shared_ptr mImpl; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_NATIVEWINDOW11WINRT_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 548b4602fd..3425fad95d 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 @@ -49,7 +49,8 @@ HRESULT RunOnUIThread(CODE &&code, const ComPtr &dispatcher) } else { - Event waitEvent(CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); + Event waitEvent( + CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); if (!waitEvent.IsValid()) { return E_FAIL; @@ -78,7 +79,8 @@ HRESULT RunOnUIThread(CODE &&code, const ComPtr &dispatcher) // 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."); + ERR() + << "Timeout waiting for async action on UI thread. The UI thread might be blocked."; std::terminate(); return E_FAIL; } @@ -132,7 +134,8 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert // 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."); + ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a " + "EGLRenderResolutionScaleProperty."; return false; } } @@ -169,17 +172,14 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert } else { - SIZE swapChainPanelSize; + Size swapChainPanelSize; result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, - &swapChainPanelSize, &mSwapChainScale); - if (mSwapChainScale != 1.0f) - mSwapChainScaleSpecified = true; + &swapChainPanelSize); 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)) }; + mClientRect = clientRect(swapChainPanelSize); } } } @@ -241,14 +241,15 @@ void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() } HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) + IDXGISwapChain1 **swapChain) { - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || + height == 0) { return E_INVALIDARG; } @@ -272,6 +273,7 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, ComPtr newSwapChain; ComPtr swapChainPanelNative; + Size currentPanelSize = {}; HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); @@ -306,14 +308,14 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, { if (mSwapChainSizeSpecified || mSwapChainScaleSpecified) { - ComPtr uiElement; - result = mSwapChainPanel.As(&uiElement); - ASSERT(SUCCEEDED(result)); - - Size currentSize; - result = uiElement->get_RenderSize(¤tSize); - ASSERT(SUCCEEDED(result)); - result = scaleSwapChain(currentSize, mClientRect); + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + ¤tPanelSize); + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result)) + { + result = scaleSwapChain(currentPanelSize, mClientRect); + } } } @@ -342,31 +344,14 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const HRESULT GetSwapChainPanelSize( const ComPtr &swapChainPanel, const ComPtr &dispatcher, - SIZE *windowSize, float *scaleFactor) + Size *windowSize) { ComPtr uiElement; - Size renderSize = {0, 0}; HRESULT result = swapChainPanel.As(&uiElement); if (SUCCEEDED(result)) { result = RunOnUIThread( - [uiElement, &renderSize] - { - return uiElement->get_RenderSize(&renderSize); - }, - dispatcher); - } - - if (SUCCEEDED(result)) - { - long width = ConvertDipsToPixels(renderSize.Width); - long height = ConvertDipsToPixels(renderSize.Height); - *windowSize = { width, height }; - - if (scaleFactor) - { - *scaleFactor = renderSize.Width / width; - } + [uiElement, windowSize] { return uiElement->get_RenderSize(windowSize); }, dispatcher); } return result; 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 09d87ad523..f9a2fc0e4b 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 @@ -11,6 +11,8 @@ #include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" +#include + namespace rx { class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this @@ -20,12 +22,12 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) override; HRESULT createSwapChain(ID3D11Device *device, - DXGIFactory *factory, + IDXGIFactory2 *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, bool containsAlpha, - DXGISwapChain **swapChain) override; + IDXGISwapChain1 **swapChain) override; protected: HRESULT scaleSwapChain(const Size &windowSize, const RECT &clientRect) override; @@ -37,7 +39,7 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e ComPtr mSwapChainPanel; ComPtr mSwapChainPanelDispatcher; ComPtr> mPropertyMap; - ComPtr mSwapChain; + ComPtr mSwapChain; }; [uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] @@ -86,6 +88,6 @@ class SwapChainPanelSizeChangedHandler : HRESULT GetSwapChainPanelSize( const ComPtr &swapChainPanel, const ComPtr &dispatcher, - SIZE *windowSize, float *scaleFactor); + Size *windowSize); } #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 2ac8ee3a29..36f2bd0db8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp @@ -7,6 +7,8 @@ // Blit9.cpp: Surface copy utility class. #include "libANGLE/renderer/d3d/d3d9/Blit9.h" + +#include "libANGLE/renderer/d3d/TextureD3D.h" #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" @@ -20,27 +22,34 @@ namespace { // Precompiled shaders #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h" -#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminancepremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceunmultps.h" #include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskpremultps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/componentmaskunmultps.h" -const BYTE* const g_shaderCode[] = -{ +const BYTE *const g_shaderCode[] = { g_vs20_standardvs, - g_vs20_flipyvs, g_ps20_passthroughps, g_ps20_luminanceps, - g_ps20_componentmaskps + g_ps20_luminancepremultps, + g_ps20_luminanceunmultps, + g_ps20_componentmaskps, + g_ps20_componentmaskpremultps, + g_ps20_componentmaskunmultps, }; -const size_t g_shaderSize[] = -{ +const size_t g_shaderSize[] = { sizeof(g_vs20_standardvs), - sizeof(g_vs20_flipyvs), sizeof(g_ps20_passthroughps), sizeof(g_ps20_luminanceps), - sizeof(g_ps20_componentmaskps) + sizeof(g_ps20_luminancepremultps), + sizeof(g_ps20_luminanceunmultps), + sizeof(g_ps20_componentmaskps), + sizeof(g_ps20_componentmaskpremultps), + sizeof(g_ps20_componentmaskunmultps), }; } @@ -50,11 +59,11 @@ namespace rx Blit9::Blit9(Renderer9 *renderer) : mRenderer(renderer), mGeometryLoaded(false), - mQuadVertexBuffer(NULL), - mQuadVertexDeclaration(NULL), - mSavedStateBlock(NULL), - mSavedRenderTarget(NULL), - mSavedDepthStencil(NULL) + mQuadVertexBuffer(nullptr), + mQuadVertexDeclaration(nullptr), + mSavedStateBlock(nullptr), + mSavedRenderTarget(nullptr), + mSavedDepthStencil(nullptr) { memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); } @@ -75,7 +84,7 @@ gl::Error Blit9::initialize() { if (mGeometryLoaded) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } static const float quad[] = @@ -88,22 +97,25 @@ gl::Error Blit9::initialize() IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, + D3DPOOL_DEFAULT, &mQuadVertexBuffer, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create internal blit vertex shader, " + << gl::FmtHR(result); } - void *lockPtr = NULL; + void *lockPtr = nullptr; result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); - if (FAILED(result) || lockPtr == NULL) + if (FAILED(result) || lockPtr == nullptr) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(mQuadVertexBuffer); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock internal blit vertex shader, " + << gl::FmtHR(result); } memcpy(lockPtr, quad, sizeof(quad)); @@ -121,11 +133,12 @@ gl::Error Blit9::initialize() { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(mQuadVertexBuffer); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock internal blit vertex declaration, " + << gl::FmtHR(result); } mGeometryLoaded = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template @@ -137,7 +150,7 @@ gl::Error Blit9::setShader(ShaderId source, const char *profile, D3DShaderType *shader = nullptr; - if (mCompiledShaders[source] != NULL) + if (mCompiledShaders[source] != nullptr) { shader = static_cast(mCompiledShaders[source]); } @@ -145,23 +158,17 @@ gl::Error Blit9::setShader(ShaderId source, const char *profile, { const BYTE* shaderCode = g_shaderCode[source]; size_t shaderSize = g_shaderSize[source]; - - gl::Error error = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader); - if (error.isError()) - { - return error; - } - + ANGLE_TRY((mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader)); mCompiledShaders[source] = shader; } HRESULT hr = (device->*setShader)(shader); if (FAILED(hr)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr); + return gl::OutOfMemory() << "Failed to set shader for blit operation, " << gl::FmtHR(hr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Blit9::setVertexShader(ShaderId shader) @@ -188,20 +195,20 @@ RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const return rect; } +gl::Extents Blit9::getSurfaceSize(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + return gl::Extents(desc.Width, desc.Height, 1); +} + gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initialize()); - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); - if (error.isError()) - { - return error; - } + IDirect3DBaseTexture9 *texture = nullptr; + ANGLE_TRY(copySurfaceToTexture(source, getSurfaceRect(source), &texture)); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -210,14 +217,15 @@ gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) device->SetTexture(0, texture); device->SetRenderTarget(0, dest); - setVertexShader(SHADER_VS_STANDARD); - setPixelShader(SHADER_PS_PASSTHROUGH); + ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD)); + ANGLE_TRY(setPixelShader(SHADER_PS_PASSTHROUGH)); setCommonBlitState(); device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - setViewport(getSurfaceRect(dest), gl::Offset(0, 0, 0)); + setViewportAndShaderConstants(getSurfaceRect(source), getSurfaceSize(source), + getSurfaceRect(dest), false); render(); @@ -225,34 +233,32 @@ gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) restoreState(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Blit9::copy2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initialize()); const gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); ASSERT(colorbuffer); RenderTarget9 *renderTarget9 = nullptr; - error = colorbuffer->getRenderTarget(&renderTarget9); - if (error.isError()) - { - return error; - } + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget9)); ASSERT(renderTarget9); IDirect3DSurface9 *source = renderTarget9->getSurface(); ASSERT(source); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, true, &destSurface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_2D, level, true, &destSurface); if (error.isError()) { SafeRelease(source); @@ -260,7 +266,8 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe } ASSERT(destSurface); - gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + gl::Error result = + copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false); SafeRelease(destSurface); SafeRelease(source); @@ -268,7 +275,14 @@ gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRe return result; } -gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +gl::Error Blit9::copyCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) { gl::Error error = initialize(); if (error.isError()) @@ -280,7 +294,7 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source ASSERT(colorbuffer); RenderTarget9 *renderTarget9 = nullptr; - error = colorbuffer->getRenderTarget(&renderTarget9); + error = colorbuffer->getRenderTarget(context, &renderTarget9); if (error.isError()) { return error; @@ -290,9 +304,9 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source IDirect3DSurface9 *source = renderTarget9->getSurface(); ASSERT(source); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - error = storage9->getSurfaceLevel(target, level, true, &destSurface); + error = storage9->getSurfaceLevel(context, target, level, true, &destSurface); if (error.isError()) { SafeRelease(source); @@ -300,7 +314,8 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source } ASSERT(destSurface); - gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + gl::Error result = + copy(source, nullptr, sourceRect, destFormat, destOffset, destSurface, false, false, false); SafeRelease(destSurface); SafeRelease(source); @@ -308,9 +323,69 @@ gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &source return result; } -gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +gl::Error Blit9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(initialize()); + + const TextureD3D *sourceD3D = GetImplAs(source); + + TextureStorage *sourceStorage = nullptr; + ANGLE_TRY(const_cast(sourceD3D)->getNativeTexture(context, &sourceStorage)); + + TextureStorage9_2D *sourceStorage9 = GetAs(sourceStorage); + ASSERT(sourceStorage9); + + TextureStorage9 *destStorage9 = GetAs(storage); + ASSERT(destStorage9); + + ASSERT(sourceLevel == 0); + IDirect3DBaseTexture9 *sourceTexture = nullptr; + ANGLE_TRY(sourceStorage9->getBaseTexture(context, &sourceTexture)); + + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY( + sourceStorage9->getSurfaceLevel(context, GL_TEXTURE_2D, sourceLevel, true, &sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + gl::Error error = + destStorage9->getSurfaceLevel(context, destTarget, destLevel, true, &destSurface); + if (error.isError()) + { + SafeRelease(sourceSurface); + return error; + } + + error = copy(sourceSurface, sourceTexture, sourceRect, destFormat, destOffset, destSurface, + flipY, premultiplyAlpha, unmultiplyAlpha); + + SafeRelease(sourceSurface); + SafeRelease(destSurface); + + return error; +} + +gl::Error Blit9::copy(IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) { - ASSERT(source != NULL && dest != NULL); + ASSERT(source != nullptr && dest != nullptr); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -319,8 +394,10 @@ gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum source->GetDesc(&sourceDesc); dest->GetDesc(&destDesc); - if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && - d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect + // Check if it's possible to use StetchRect + if (sourceDesc.Format == destDesc.Format && (destDesc.Usage & D3DUSAGE_RENDERTARGET) && + d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat) && !flipY && + premultiplyAlpha == unmultiplyAlpha) { RECT destRect = { destOffset.x, destOffset.y, destOffset.x + (sourceRect.right - sourceRect.left), destOffset.y + (sourceRect.bottom - sourceRect.top)}; HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); @@ -328,85 +405,135 @@ gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to blit between textures, StretchRect " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } else { - return formatConvert(source, sourceRect, destFormat, destOffset, dest); - } -} + IDirect3DBaseTexture9 *texture = sourceTexture; + RECT adjustedSourceRect = sourceRect; + gl::Extents sourceSize(sourceDesc.Width, sourceDesc.Height, 1); -gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) -{ - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } + if (texture == nullptr) + { + ANGLE_TRY(copySurfaceToTexture(source, sourceRect, &texture)); + + // copySurfaceToTexture only copies in the sourceRect area of the source surface. + // Adjust sourceRect so that it is now covering the entire source texture + adjustedSourceRect.left = 0; + adjustedSourceRect.right = sourceRect.right - sourceRect.left; + adjustedSourceRect.top = 0; + adjustedSourceRect.bottom = sourceRect.bottom - sourceRect.top; + + sourceSize.width = sourceRect.right - sourceRect.left; + sourceSize.height = sourceRect.bottom - sourceRect.top; + } + else + { + texture->AddRef(); + } + + gl::Error error = formatConvert(texture, adjustedSourceRect, sourceSize, destFormat, + destOffset, dest, flipY, premultiplyAlpha, unmultiplyAlpha); + + SafeRelease(texture); - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, sourceRect, &texture); - if (error.isError()) - { return error; } +} + +gl::Error Blit9::formatConvert(IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) +{ + ANGLE_TRY(initialize()); IDirect3DDevice9 *device = mRenderer->getDevice(); saveState(); - device->SetTexture(0, texture); + device->SetTexture(0, source); device->SetRenderTarget(0, dest); - setViewport(sourceRect, destOffset); + RECT destRect; + destRect.left = destOffset.x; + destRect.right = destOffset.x + (sourceRect.right - sourceRect.left); + destRect.top = destOffset.y; + destRect.bottom = destOffset.y + (sourceRect.bottom - sourceRect.top); + + setViewportAndShaderConstants(sourceRect, sourceSize, destRect, flipY); setCommonBlitState(); - error = setFormatConvertShaders(destFormat); + gl::Error error = setFormatConvertShaders(destFormat, flipY, premultiplyAlpha, unmultiplyAlpha); if (!error.isError()) { render(); } - SafeRelease(texture); - restoreState(); return error; } -gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) +gl::Error Blit9::setFormatConvertShaders(GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha) { - gl::Error error = setVertexShader(SHADER_VS_STANDARD); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setVertexShader(SHADER_VS_STANDARD)); switch (destFormat) { - default: UNREACHABLE(); case GL_RGBA: case GL_BGRA_EXT: case GL_RGB: case GL_RG_EXT: case GL_RED_EXT: case GL_ALPHA: - error = setPixelShader(SHADER_PS_COMPONENTMASK); - break; + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA)); + } + break; case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: - error = setPixelShader(SHADER_PS_LUMINANCE); - break; - } - - if (error.isError()) - { - return error; + if (premultiplyAlpha == unmultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE)); + } + else if (premultiplyAlpha) + { + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA)); + } + else + { + ASSERT(unmultiplyAlpha); + ANGLE_TRY(setPixelShader(SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA)); + } + break; + + default: + UNREACHABLE(); } enum { X = 0, Y = 1, Z = 2, W = 3 }; @@ -502,10 +629,12 @@ gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) +gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, + const RECT &sourceRect, + IDirect3DBaseTexture9 **outTexture) { ASSERT(surface); @@ -516,12 +645,15 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so // Copy the render target into a texture IDirect3DTexture9 *texture; - HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); + HRESULT result = device->CreateTexture( + sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, + D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to allocate internal texture for blit, " + << gl::FmtHR(result); } IDirect3DSurface9 *textureSurface; @@ -531,11 +663,12 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to query surface of internal blit texture, " + << gl::FmtHR(result); } mRenderer->endScene(); - result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + result = device->StretchRect(surface, &sourceRect, textureSurface, nullptr, D3DTEXF_NONE); SafeRelease(textureSurface); @@ -543,35 +676,50 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to copy between internal blit textures, " + << gl::FmtHR(result); } *outTexture = texture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Blit9::setViewport(const RECT &sourceRect, const gl::Offset &offset) +void Blit9::setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY) { IDirect3DDevice9 *device = mRenderer->getDevice(); D3DVIEWPORT9 vp; - vp.X = offset.x; - vp.Y = offset.y; - vp.Width = sourceRect.right - sourceRect.left; - vp.Height = sourceRect.bottom - sourceRect.top; + vp.X = destRect.left; + vp.Y = destRect.top; + vp.Width = destRect.right - destRect.left; + vp.Height = destRect.bottom - destRect.top; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; device->SetViewport(&vp); - float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 }; - device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); + float vertexConstants[8] = { + // halfPixelAdjust + -1.0f / vp.Width, 1.0f / vp.Height, 0, 0, + // texcoordOffset + static_cast(sourceRect.left) / sourceSize.width, + static_cast(flipY ? sourceRect.bottom : sourceRect.top) / sourceSize.height, + static_cast(sourceRect.right - sourceRect.left) / sourceSize.width, + static_cast(flipY ? sourceRect.top - sourceRect.bottom + : sourceRect.bottom - sourceRect.top) / + sourceSize.height, + }; + + device->SetVertexShaderConstantF(0, vertexConstants, 2); } void Blit9::setCommonBlitState() { IDirect3DDevice9 *device = mRenderer->getDevice(); - device->SetDepthStencilSurface(NULL); + device->SetDepthStencilSurface(nullptr); device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); @@ -617,7 +765,7 @@ void Blit9::saveState() device->GetDepthStencilSurface(&mSavedDepthStencil); device->GetRenderTarget(0, &mSavedRenderTarget); - if (mSavedStateBlock == NULL) + if (mSavedStateBlock == nullptr) { hr = device->BeginStateBlock(); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); @@ -626,9 +774,9 @@ void Blit9::saveState() static const float dummyConst[8] = { 0 }; - device->SetVertexShader(NULL); + device->SetVertexShader(nullptr); device->SetVertexShaderConstantF(0, dummyConst, 2); - device->SetPixelShader(NULL); + device->SetPixelShader(nullptr); device->SetPixelShaderConstantF(0, dummyConst, 2); D3DVIEWPORT9 dummyVp; @@ -641,7 +789,7 @@ void Blit9::saveState() device->SetViewport(&dummyVp); - device->SetTexture(0, NULL); + device->SetTexture(0, nullptr); device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); @@ -651,9 +799,9 @@ void Blit9::saveState() ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); } - ASSERT(mSavedStateBlock != NULL); + ASSERT(mSavedStateBlock != nullptr); - if (mSavedStateBlock != NULL) + if (mSavedStateBlock != nullptr) { hr = mSavedStateBlock->Capture(); ASSERT(SUCCEEDED(hr)); @@ -670,9 +818,9 @@ void Blit9::restoreState() device->SetRenderTarget(0, mSavedRenderTarget); SafeRelease(mSavedRenderTarget); - ASSERT(mSavedStateBlock != NULL); + ASSERT(mSavedStateBlock != nullptr); - if (mSavedStateBlock != NULL) + if (mSavedStateBlock != nullptr) { mSavedStateBlock->Apply(); } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h index 586abd2580..026874f8ae 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h @@ -16,7 +16,10 @@ namespace gl { +class Context; class Framebuffer; +class Texture; +struct Extents; struct Offset; } @@ -35,13 +38,33 @@ class Blit9 : angle::NonCopyable // Copy from source surface to dest surface. // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) - gl::Error copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level); - gl::Error copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); - - // Copy from source surface to dest surface. - // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) - // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. - gl::Error formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); + gl::Error copy2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level); + gl::Error copyCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level); + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); // 2x2 box filter sample from source to dest. // Requires that source is RGB(A) and dest has the same format as source. @@ -54,23 +77,56 @@ class Blit9 : angle::NonCopyable IDirect3DVertexBuffer9 *mQuadVertexBuffer; IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; - gl::Error setFormatConvertShaders(GLenum destFormat); - - gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); - gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture); - void setViewport(const RECT &sourceRect, const gl::Offset &offset); + // Copy from source texture to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + // source is interpreted as RGBA and destFormat specifies the desired result format. For + // example, if destFormat = GL_RGB, the alpha channel will be forced to 0. + gl::Error formatConvert(IDirect3DBaseTexture9 *source, + const RECT &sourceRect, + const gl::Extents &sourceSize, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + gl::Error setFormatConvertShaders(GLenum destFormat, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + + gl::Error copy(IDirect3DSurface9 *source, + IDirect3DBaseTexture9 *sourceTexture, + const RECT &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + IDirect3DSurface9 *dest, + bool flipY, + bool premultiplyAlpha, + bool unmultiplyAlpha); + gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, + const RECT &sourceRect, + IDirect3DBaseTexture9 **outTexture); + void setViewportAndShaderConstants(const RECT &sourceRect, + const gl::Extents &sourceSize, + const RECT &destRect, + bool flipY); void setCommonBlitState(); RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + gl::Extents getSurfaceSize(IDirect3DSurface9 *surface) const; // This enum is used to index mCompiledShaders and mShaderSource. enum ShaderId { SHADER_VS_STANDARD, - SHADER_VS_FLIPY, SHADER_PS_PASSTHROUGH, SHADER_PS_LUMINANCE, + SHADER_PS_LUMINANCE_PREMULTIPLY_ALPHA, + SHADER_PS_LUMINANCE_UNMULTIPLY_ALPHA, SHADER_PS_COMPONENTMASK, - SHADER_COUNT + SHADER_PS_COMPONENTMASK_PREMULTIPLY_ALPHA, + SHADER_PS_COMPONENTMASK_UNMULTIPLY_ALPHA, + SHADER_COUNT, }; // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. 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 804b6971ce..dc308e7752 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -12,23 +12,37 @@ namespace rx { -Buffer9::Buffer9(Renderer9 *renderer) - : BufferD3D(renderer), - mSize(0) -{} +Buffer9::Buffer9(const gl::BufferState &state, Renderer9 *renderer) + : BufferD3D(state, renderer), mSize(0) +{ +} Buffer9::~Buffer9() { mSize = 0; } -gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) +size_t Buffer9::getSize() const +{ + return mSize; +} + +bool Buffer9::supportsDirectBinding() const +{ + return false; +} + +gl::Error Buffer9::setData(const gl::Context *context, + gl::BufferBinding /*target*/, + const void *data, + size_t size, + gl::BufferUsage usage) { if (size > mMemory.size()) { if (!mMemory.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + return gl::OutOfMemory() << "Failed to resize internal buffer."; } } @@ -38,25 +52,30 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) memcpy(mMemory.data(), data, size); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + updateD3DBufferUsage(context, usage); - updateD3DBufferUsage(usage); - return gl::Error(GL_NO_ERROR); + invalidateStaticData(context); + + return gl::NoError(); } -gl::Error Buffer9::getData(const uint8_t **outData) +gl::Error Buffer9::getData(const gl::Context *context, const uint8_t **outData) { *outData = mMemory.data(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) +gl::Error Buffer9::setSubData(const gl::Context *context, + gl::BufferBinding /*target*/, + const void *data, + size_t size, + size_t offset) { if (offset + size > mMemory.size()) { if (!mMemory.resize(offset + size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + return gl::OutOfMemory() << "Failed to resize internal buffer."; } } @@ -66,46 +85,55 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) memcpy(mMemory.data() + offset, data, size); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +gl::Error Buffer9::copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) { // Note: this method is currently unreachable - Buffer9* sourceBuffer = GetAs(source); + Buffer9 *sourceBuffer = GetAs(source); ASSERT(sourceBuffer); memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // We do not support buffer mapping in D3D9 -gl::Error Buffer9::map(GLenum access, GLvoid **mapPtr) +gl::Error Buffer9::map(const gl::Context *context, GLenum access, void **mapPtr) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Buffer9::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +gl::Error Buffer9::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Buffer9::unmap(GLboolean *result) +gl::Error Buffer9::unmap(const gl::Context *context, GLboolean *result) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -void Buffer9::markTransformFeedbackUsage() +gl::Error Buffer9::markTransformFeedbackUsage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } -} +} // namespace rx 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 44a524ba28..960b2a2474 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h @@ -20,28 +20,44 @@ class Renderer9; class Buffer9 : public BufferD3D { public: - Buffer9(Renderer9 *renderer); - virtual ~Buffer9(); + Buffer9(const gl::BufferState &state, Renderer9 *renderer); + ~Buffer9() override; // BufferD3D implementation - virtual size_t getSize() const { return mSize; } - virtual bool supportsDirectBinding() const { return false; } - gl::Error getData(const uint8_t **outData) override; + size_t getSize() const override; + bool supportsDirectBinding() const override; + gl::Error getData(const gl::Context *context, const uint8_t **outData) override; // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - 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(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(); + gl::Error setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) override; + gl::Error setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) override; + gl::Error copySubData(const gl::Context *context, + BufferImpl *source, + GLintptr sourceOffset, + GLintptr destOffset, + GLsizeiptr size) override; + gl::Error map(const gl::Context *context, GLenum access, void **mapPtr) override; + gl::Error mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) override; + gl::Error unmap(const gl::Context *context, GLboolean *result) override; + gl::Error markTransformFeedbackUsage(const gl::Context *context) override; private: - MemoryBuffer mMemory; + angle::MemoryBuffer mMemory; size_t mSize; }; -} +} // namespace rx -#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ +#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp new file mode 100644 index 0000000000..1b9874cc20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -0,0 +1,303 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#include "libANGLE/renderer/d3d/d3d9/Context9.h" + +#include "common/string_utils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/SamplerD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/StateManager9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" + +namespace rx +{ + +Context9::Context9(const gl::ContextState &state, Renderer9 *renderer) + : ContextImpl(state), mRenderer(renderer) +{ +} + +Context9::~Context9() +{ +} + +gl::Error Context9::initialize() +{ + return gl::NoError(); +} + +CompilerImpl *Context9::createCompiler() +{ + return new CompilerD3D(SH_HLSL_3_0_OUTPUT); +} + +ShaderImpl *Context9::createShader(const gl::ShaderState &data) +{ + return new ShaderD3D(data, mRenderer->getWorkarounds(), mRenderer->getNativeExtensions()); +} + +ProgramImpl *Context9::createProgram(const gl::ProgramState &data) +{ + return new ProgramD3D(data, mRenderer); +} + +FramebufferImpl *Context9::createFramebuffer(const gl::FramebufferState &data) +{ + return new Framebuffer9(data, mRenderer); +} + +TextureImpl *Context9::createTexture(const gl::TextureState &state) +{ + switch (state.getTarget()) + { + case GL_TEXTURE_2D: + return new TextureD3D_2D(state, mRenderer); + case GL_TEXTURE_CUBE_MAP: + return new TextureD3D_Cube(state, mRenderer); + case GL_TEXTURE_EXTERNAL_OES: + return new TextureD3D_External(state, mRenderer); + default: + UNREACHABLE(); + } + return nullptr; +} + +RenderbufferImpl *Context9::createRenderbuffer() +{ + return new RenderbufferD3D(mRenderer); +} + +BufferImpl *Context9::createBuffer(const gl::BufferState &state) +{ + return new Buffer9(state, mRenderer); +} + +VertexArrayImpl *Context9::createVertexArray(const gl::VertexArrayState &data) +{ + return new VertexArray9(data); +} + +QueryImpl *Context9::createQuery(GLenum type) +{ + return new Query9(mRenderer, type); +} + +FenceNVImpl *Context9::createFenceNV() +{ + return new FenceNV9(mRenderer); +} + +SyncImpl *Context9::createSync() +{ + // D3D9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return nullptr; +} + +TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state) +{ + UNREACHABLE(); + return nullptr; +} + +SamplerImpl *Context9::createSampler(const gl::SamplerState &state) +{ + return new SamplerD3D(state); +} + +ProgramPipelineImpl *Context9::createProgramPipeline(const gl::ProgramPipelineState &data) +{ + UNREACHABLE(); + return nullptr; +} + +std::vector Context9::createPaths(GLsizei) +{ + return std::vector(); +} + +gl::Error Context9::flush(const gl::Context *context) +{ + return mRenderer->flush(); +} + +gl::Error Context9::finish(const gl::Context *context) +{ + return mRenderer->finish(); +} + +gl::Error Context9::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, 0); +} + +gl::Error Context9::drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) +{ + return mRenderer->genericDrawArrays(context, mode, first, count, instanceCount); +} + +gl::Error Context9::drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context9::drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, instances); +} + +gl::Error Context9::drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + return mRenderer->genericDrawElements(context, mode, count, type, indices, 0); +} + +gl::Error Context9::drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DrawArraysIndirect API"; +} + +gl::Error Context9::drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DrawElementsIndirect API"; +} + +GLenum Context9::getResetStatus() +{ + return mRenderer->getResetStatus(); +} + +std::string Context9::getVendorString() const +{ + return mRenderer->getVendorString(); +} + +std::string Context9::getRendererDescription() const +{ + return mRenderer->getRendererDescription(); +} + +void Context9::insertEventMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->setMarker(optionalString.value().data()); + } +} + +void Context9::pushGroupMarker(GLsizei length, const char *marker) +{ + auto optionalString = angle::WidenString(static_cast(length), marker); + if (optionalString.valid()) + { + mRenderer->getAnnotator()->beginEvent(optionalString.value().data()); + } +} + +void Context9::popGroupMarker() +{ + mRenderer->getAnnotator()->endEvent(); +} + +void Context9::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +{ + // Fall through to the EXT_debug_marker functions + pushGroupMarker(length, message); +} + +void Context9::popDebugGroup() +{ + // Fall through to the EXT_debug_marker functions + popGroupMarker(); +} + +void Context9::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) +{ + mRenderer->getStateManager()->syncState(mState.getState(), dirtyBits); +} + +GLint Context9::getGPUDisjoint() +{ + return mRenderer->getGPUDisjoint(); +} + +GLint64 Context9::getTimestamp() +{ + return mRenderer->getTimestamp(); +} + +void Context9::onMakeCurrent(const gl::Context *context) +{ +} + +const gl::Caps &Context9::getNativeCaps() const +{ + return mRenderer->getNativeCaps(); +} + +const gl::TextureCapsMap &Context9::getNativeTextureCaps() const +{ + return mRenderer->getNativeTextureCaps(); +} + +const gl::Extensions &Context9::getNativeExtensions() const +{ + return mRenderer->getNativeExtensions(); +} + +const gl::Limitations &Context9::getNativeLimitations() const +{ + return mRenderer->getNativeLimitations(); +} + +gl::Error Context9::dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + UNREACHABLE(); + return gl::InternalError() << "D3D9 doesn't support ES 3.1 DispatchCompute API"; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h new file mode 100644 index 0000000000..d681bfde89 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h @@ -0,0 +1,151 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Context9: +// D3D9-specific functionality associated with a GL Context. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ + +#include "libANGLE/renderer/ContextImpl.h" + +namespace rx +{ +class Renderer9; + +class Context9 : public ContextImpl +{ + public: + Context9(const gl::ContextState &state, Renderer9 *renderer); + ~Context9() override; + + gl::Error initialize() override; + + // Shader creation + CompilerImpl *createCompiler() override; + ShaderImpl *createShader(const gl::ShaderState &data) override; + ProgramImpl *createProgram(const gl::ProgramState &data) override; + + // Framebuffer creation + FramebufferImpl *createFramebuffer(const gl::FramebufferState &data) override; + + // Texture creation + TextureImpl *createTexture(const gl::TextureState &state) override; + + // Renderbuffer creation + RenderbufferImpl *createRenderbuffer() override; + + // Buffer creation + BufferImpl *createBuffer(const gl::BufferState &state) override; + + // Vertex Array creation + VertexArrayImpl *createVertexArray(const gl::VertexArrayState &data) override; + + // Query and Fence creation + QueryImpl *createQuery(GLenum type) override; + FenceNVImpl *createFenceNV() override; + SyncImpl *createSync() override; + + // Transform Feedback creation + TransformFeedbackImpl *createTransformFeedback( + const gl::TransformFeedbackState &state) override; + + // Sampler object creation + SamplerImpl *createSampler(const gl::SamplerState &state) override; + + // Program Pipeline object creation + ProgramPipelineImpl *createProgramPipeline(const gl::ProgramPipelineState &data) override; + + // Path object creation + std::vector createPaths(GLsizei) override; + + // Flush and finish. + gl::Error flush(const gl::Context *context) override; + gl::Error finish(const gl::Context *context) override; + + // Drawing methods. + gl::Error drawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count) override; + gl::Error drawArraysInstanced(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) override; + + gl::Error drawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawElementsInstanced(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) override; + gl::Error drawRangeElements(const gl::Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) override; + gl::Error drawArraysIndirect(const gl::Context *context, + GLenum mode, + const void *indirect) override; + gl::Error drawElementsIndirect(const gl::Context *context, + GLenum mode, + GLenum type, + const void *indirect) override; + + // Device loss + GLenum getResetStatus() override; + + // Vendor and description strings. + std::string getVendorString() const override; + std::string getRendererDescription() const override; + + // EXT_debug_marker + void insertEventMarker(GLsizei length, const char *marker) override; + void pushGroupMarker(GLsizei length, const char *marker) override; + void popGroupMarker() override; + + // KHR_debug + void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void popDebugGroup() override; + + // State sync with dirty bits. + void syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits) override; + + // Disjoint timer queries + GLint getGPUDisjoint() override; + GLint64 getTimestamp() override; + + // Context switching + void onMakeCurrent(const gl::Context *context) override; + + // Caps queries + const gl::Caps &getNativeCaps() const override; + const gl::TextureCapsMap &getNativeTextureCaps() const override; + const gl::Extensions &getNativeExtensions() const override; + const gl::Limitations &getNativeLimitations() const override; + + gl::Error dispatchCompute(const gl::Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) override; + + Renderer9 *getRenderer() const { return mRenderer; } + + private: + Renderer9 *mRenderer; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_CONTEXT9_H_ 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 54e3bb9490..b28008335f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h @@ -9,12 +9,12 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ #define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ -#include "common/debug.h" +#include "libANGLE/LoggingAnnotator.h" namespace rx { -class DebugAnnotator9 : public gl::DebugAnnotator +class DebugAnnotator9 : public angle::LoggingAnnotator { public: DebugAnnotator9() {} 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 3300681277..bff3881655 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp @@ -13,10 +13,7 @@ namespace rx { -FenceNV9::FenceNV9(Renderer9 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) +FenceNV9::FenceNV9(Renderer9 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) { } @@ -41,10 +38,10 @@ gl::Error FenceNV9::set(GLenum condition) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(mQuery); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to end event query, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error FenceNV9::test(GLboolean *outFinished) @@ -66,7 +63,7 @@ gl::Error FenceNV9::finish() Sleep(0); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished) @@ -74,21 +71,21 @@ gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished) ASSERT(mQuery); DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); - HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); + HRESULT result = mQuery->GetData(nullptr, 0, getDataFlags); if (d3d9::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + return gl::OutOfMemory() << "Device was lost while querying result of an event query."; } else if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get query data, " << gl::FmtHR(result); } ASSERT(result == S_OK || result == S_FALSE); *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } 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 200ac68d27..de0ff20774 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ #include "libANGLE/renderer/FenceNVImpl.h" -#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/SyncImpl.h" namespace rx { 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 9c269a8565..dff12e03f8 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp @@ -7,21 +7,25 @@ // Framebuffer9.cpp: Implements the Framebuffer9 class. #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" -#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" -#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" -#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" -#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" -#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" -#include "libANGLE/renderer/d3d/TextureD3D.h" -#include "libANGLE/formatutils.h" + +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/renderer_utils.h" namespace rx { -Framebuffer9::Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer) +Framebuffer9::Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer) : FramebufferD3D(data, renderer), mRenderer(renderer) { ASSERT(mRenderer != nullptr); @@ -31,66 +35,61 @@ Framebuffer9::~Framebuffer9() { } -gl::Error Framebuffer9::discard(size_t, const GLenum *) +gl::Error Framebuffer9::discard(const gl::Context *context, size_t, const GLenum *) { // Extension not implemented in D3D9 renderer UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::invalidate(size_t, const GLenum *) +gl::Error Framebuffer9::invalidate(const gl::Context *context, size_t, const GLenum *) { // Shouldn't ever reach here in D3D9 UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +gl::Error Framebuffer9::invalidateSub(const gl::Context *context, + size_t, + const GLenum *, + const gl::Rectangle &) { // Shouldn't ever reach here in D3D9 UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::clear(const gl::Data &data, const ClearParameters &clearParams) +gl::Error Framebuffer9::clearImpl(const gl::Context *context, const ClearParameters &clearParams) { - const gl::FramebufferAttachment *colorAttachment = mData.getColorAttachment(0); - const gl::FramebufferAttachment *depthStencilAttachment = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *colorAttachment = mState.getColorAttachment(0); + const gl::FramebufferAttachment *depthStencilAttachment = mState.getDepthOrStencilAttachment(); - gl::Error error = mRenderer->applyRenderTarget(colorAttachment, depthStencilAttachment); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->applyRenderTarget(context, colorAttachment, depthStencilAttachment)); - 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); + const gl::State &glState = context->getGLState(); + float nearZ = glState.getNearPlane(); + float farZ = glState.getFarPlane(); + mRenderer->setViewport(glState.getViewport(), nearZ, farZ, GL_TRIANGLES, + glState.getRasterizerState().frontFace, true); - mRenderer->setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + mRenderer->setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); - return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment); + return mRenderer->clear(context, clearParams, colorAttachment, depthStencilAttachment); } -gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, +gl::Error Framebuffer9::readPixelsImpl(const gl::Context *context, + const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, - uint8_t *pixels) const + uint8_t *pixels) { - ASSERT(pack.pixelBuffer.get() == nullptr); - - const gl::FramebufferAttachment *colorbuffer = mData.getColorAttachment(0); + const gl::FramebufferAttachment *colorbuffer = mState.getColorAttachment(0); ASSERT(colorbuffer); RenderTarget9 *renderTarget = nullptr; - gl::Error error = colorbuffer->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(colorbuffer->getRenderTarget(context, &renderTarget)); ASSERT(renderTarget); IDirect3DSurface9 *surface = renderTarget->getSurface(); @@ -103,7 +102,8 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, { UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments."); + return gl::OutOfMemory() + << "ReadPixels is unimplemented for multisampled framebuffer attachments."; } IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -135,7 +135,7 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels."); + return gl::OutOfMemory() << "Failed to allocate internal texture for ReadPixels."; } } @@ -157,13 +157,13 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, UNREACHABLE(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); + return gl::OutOfMemory() << "Failed to read internal render target data."; } if (directToPixels) { SafeRelease(systemSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } RECT rect; @@ -180,85 +180,42 @@ gl::Error Framebuffer9::readPixelsImpl(const gl::Rectangle &area, UNREACHABLE(); SafeRelease(systemSurface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); + return gl::OutOfMemory() << "Failed to lock internal render target."; } - uint8_t *source; - int inputPitch; - if (pack.reverseRowOrder) - { - source = reinterpret_cast(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); - inputPitch = -lock.Pitch; - } - else - { - source = reinterpret_cast(lock.pBits); - inputPitch = lock.Pitch; - } + uint8_t *source = reinterpret_cast(lock.pBits); + int inputPitch = lock.Pitch; const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat); - if (sourceFormatInfo.format == format && sourceFormatInfo.type == type) - { - // Direct copy possible - for (int y = 0; y < rect.bottom - rect.top; y++) - { - memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes); - } - } - else - { - const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type); - - GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(format, type); - const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); - - if (fastCopyFunc) - { - // Fast copy is possible through some special function - for (int y = 0; y < rect.bottom - rect.top; y++) - { - for (int x = 0; x < rect.right - rect.left; x++) - { - uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + gl::FormatType formatType(format, type); - fastCopyFunc(src, dest); - } - } - } - else - { - ColorReadFunction colorReadFunction = sourceD3DFormatInfo.colorReadFunction; - ColorWriteFunction colorWriteFunction = GetColorWriteFunction(format, type); + PackPixelsParams packParams; + packParams.area.x = rect.left; + packParams.area.y = rect.top; + packParams.area.width = rect.right - rect.left; + packParams.area.height = rect.bottom - rect.top; + packParams.format = format; + packParams.type = type; + packParams.outputPitch = static_cast(outputPitch); + packParams.pack = pack; - uint8_t temp[sizeof(gl::ColorF)]; - for (int y = 0; y < rect.bottom - rect.top; y++) - { - for (int x = 0; x < rect.right - rect.left; x++) - { - uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - // readFunc and writeFunc will be using the same type of color, CopyTexImage - // will not allow the copy otherwise. - colorReadFunction(src, temp); - colorWriteFunction(temp, dest); - } - } - } - } + PackPixels(packParams, d3dFormatInfo.info(), inputPitch, source, pixels); systemSurface->UnlockRect(); SafeRelease(systemSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Framebuffer9::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) +gl::Error Framebuffer9::blitImpl(const gl::Context *context, + const gl::Rectangle &sourceArea, + const gl::Rectangle &destArea, + const gl::Rectangle *scissor, + bool blitRenderTarget, + bool blitDepth, + bool blitStencil, + GLenum filter, + const gl::Framebuffer *sourceFramebuffer) { ASSERT(filter == GL_NEAREST); @@ -273,18 +230,18 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl ASSERT(readBuffer); RenderTarget9 *readRenderTarget = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readRenderTarget); + gl::Error error = readBuffer->getRenderTarget(context, &readRenderTarget); if (error.isError()) { return error; } ASSERT(readRenderTarget); - const gl::FramebufferAttachment *drawBuffer = mData.getColorAttachment(0); + const gl::FramebufferAttachment *drawBuffer = mState.getColorAttachment(0); ASSERT(drawBuffer); RenderTarget9 *drawRenderTarget = nullptr; - error = drawBuffer->getRenderTarget(&drawRenderTarget); + error = drawBuffer->getRenderTarget(context, &drawRenderTarget); if (error.isError()) { return error; @@ -389,7 +346,7 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result); } } @@ -399,18 +356,18 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl ASSERT(readBuffer); RenderTarget9 *readDepthStencil = nullptr; - gl::Error error = readBuffer->getRenderTarget(&readDepthStencil); + gl::Error error = readBuffer->getRenderTarget(context, &readDepthStencil); if (error.isError()) { return error; } ASSERT(readDepthStencil); - const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment(); ASSERT(drawBuffer); RenderTarget9 *drawDepthStencil = nullptr; - error = drawBuffer->getRenderTarget(&drawDepthStencil); + error = drawBuffer->getRenderTarget(context, &drawDepthStencil); if (error.isError()) { return error; @@ -431,18 +388,24 @@ gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangl if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + return gl::OutOfMemory() << "Internal blit failed, StretchRect " << gl::FmtHR(result); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const { RenderTarget9 *renderTarget9 = GetAs(renderTarget); const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat()); - return d3dFormatInfo.internalFormat; + return d3dFormatInfo.info().glInternalFormat; } +gl::Error Framebuffer9::getSamplePosition(size_t index, GLfloat *xy) const +{ + UNREACHABLE(); + return gl::InternalError() << "getSamplePosition is unsupported to d3d9."; } + +} // namespace rx 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 fe12079ae0..d2b46435ee 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h @@ -18,26 +18,40 @@ class Renderer9; class Framebuffer9 : public FramebufferD3D { public: - Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer); - virtual ~Framebuffer9(); + Framebuffer9(const gl::FramebufferState &data, Renderer9 *renderer); + ~Framebuffer9() 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 discard(const gl::Context *context, size_t count, const GLenum *attachments) override; + gl::Error invalidate(const gl::Context *context, + size_t count, + const GLenum *attachments) override; + gl::Error invalidateSub(const gl::Context *context, + size_t count, + const GLenum *attachments, + const gl::Rectangle &area) override; + + gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; private: - gl::Error clear(const gl::Data &data, const ClearParameters &clearParams) override; + gl::Error clearImpl(const gl::Context *context, const ClearParameters &clearParams) override; - gl::Error readPixelsImpl(const gl::Rectangle &area, + gl::Error readPixelsImpl(const gl::Context *context, + 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; + uint8_t *pixels) override; + + gl::Error blitImpl(const gl::Context *context, + 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; GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; 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 fec7e3e19d..179629b362 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp @@ -24,8 +24,8 @@ namespace rx Image9::Image9(Renderer9 *renderer) { - mSurface = NULL; - mRenderer = NULL; + mSurface = nullptr; + mRenderer = nullptr; mD3DPool = D3DPOOL_SYSTEMMEM; mD3DFormat = D3DFMT_UNKNOWN; @@ -45,7 +45,9 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to query the source surface description for mipmap generation, " + << gl::FmtHR(result); } D3DSURFACE_DESC sourceDesc; @@ -53,7 +55,9 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to query the destination surface description for mipmap generation, " + << gl::FmtHR(result); } ASSERT(sourceDesc.Format == destDesc.Format); @@ -61,23 +65,25 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); - ASSERT(d3dFormatInfo.mipGenerationFunction != NULL); + ASSERT(d3dFormatInfo.info().mipGenerationFunction != nullptr); D3DLOCKED_RECT sourceLocked = {0}; - result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock the source surface for mipmap generation, " + << gl::FmtHR(result); } D3DLOCKED_RECT destLocked = {0}; - result = destSurface->LockRect(&destLocked, NULL, 0); + result = destSurface->LockRect(&destLocked, nullptr, 0); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { sourceSurface->UnlockRect(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock the destination surface for mipmap generation, " + << gl::FmtHR(result); } const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); @@ -85,40 +91,29 @@ gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 ASSERT(sourceData && destData); - d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, - destData, destLocked.Pitch, 0); + d3dFormatInfo.info().mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, + sourceLocked.Pitch, 0, destData, destLocked.Pitch, + 0); destSurface->UnlockRect(); sourceSurface->UnlockRect(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) { - IDirect3DSurface9 *sourceSurface = NULL; - gl::Error error = source->getSurface(&sourceSurface); - if (error.isError()) - { - return error; - } + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(&sourceSurface)); - IDirect3DSurface9 *destSurface = NULL; - error = dest->getSurface(&destSurface); - if (error.isError()) - { - return error; - } + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(&destSurface)); - error = generateMip(destSurface, sourceSurface); - if (error.isError()) - { - return error; - } + ANGLE_TRY(generateMip(destSurface, sourceSurface)); dest->markDirty(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) @@ -128,17 +123,17 @@ gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface HRESULT result; - result = source->LockRect(&sourceLock, NULL, 0); + result = source->LockRect(&sourceLock, nullptr, 0); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock source surface for copy, " << gl::FmtHR(result); } - result = dest->LockRect(&destLock, NULL, 0); + result = dest->LockRect(&destLock, nullptr, 0); if (FAILED(result)) { source->UnlockRect(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock source surface for copy, " << gl::FmtHR(result); } ASSERT(sourceLock.pBits && destLock.pBits); @@ -161,7 +156,85 @@ gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface source->UnlockRect(); dest->UnlockRect(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +// static +gl::Error Image9::CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + IDirect3DSurface9 *sourceSurface = nullptr; + ANGLE_TRY(source->getSurface(&sourceSurface)); + + IDirect3DSurface9 *destSurface = nullptr; + ANGLE_TRY(dest->getSurface(&destSurface)); + + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to query the source surface description for mipmap generation, " + << gl::FmtHR(result); + } + const d3d9::D3DFormat &destD3DFormatInfo = d3d9::GetD3DFormatInfo(destDesc.Format); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() + << "Failed to query the destination surface description for mipmap generation, " + << gl::FmtHR(result); + } + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, nullptr, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() << "Failed to lock the source surface for CopyImage, " + << gl::FmtHR(result); + } + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, nullptr, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + return gl::OutOfMemory() << "Failed to lock the destination surface for CopyImage, " + << gl::FmtHR(result); + } + + const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits) + + sourceRect.x * sourceD3DFormatInfo.pixelBytes + + sourceRect.y * sourceLocked.Pitch; + uint8_t *destData = reinterpret_cast(destLocked.pBits) + + destOffset.x * destD3DFormatInfo.pixelBytes + + destOffset.y * destLocked.Pitch; + ASSERT(sourceData && destData); + + CopyImageCHROMIUM(sourceData, sourceLocked.Pitch, sourceD3DFormatInfo.pixelBytes, + sourceD3DFormatInfo.info().colorReadFunction, destData, destLocked.Pitch, + destD3DFormatInfo.pixelBytes, destD3DFormatInfo.info().colorWriteFunction, + gl::GetUnsizedFormat(dest->getInternalFormat()), + destD3DFormatInfo.info().componentType, sourceRect.width, sourceRect.height, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return gl::NoError(); } bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) @@ -189,7 +262,7 @@ bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &s mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); SafeRelease(mSurface); - mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); + mDirty = (d3d9FormatInfo.dataInitializerFunction != nullptr); return true; } @@ -201,11 +274,11 @@ gl::Error Image9::createSurface() { if (mSurface) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; + IDirect3DTexture9 *newTexture = nullptr; + IDirect3DSurface9 *newSurface = nullptr; const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; const D3DFORMAT d3dFormat = getD3DFormat(); @@ -218,20 +291,20 @@ gl::Error Image9::createSurface() IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, - poolToUse, &newTexture, NULL); + HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, + d3dFormat, poolToUse, &newTexture, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create image surface, " << gl::FmtHR(result); } newTexture->GetSurfaceLevel(levelToFetch, &newSurface); SafeRelease(newTexture); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - if (d3dFormatInfo.dataInitializerFunction != NULL) + if (d3dFormatInfo.dataInitializerFunction != nullptr) { RECT entireRect; entireRect.left = 0; @@ -244,7 +317,7 @@ gl::Error Image9::createSurface() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock image surface, " << gl::FmtHR(result); } d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), @@ -254,7 +327,7 @@ gl::Error Image9::createSurface() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to unlock image surface, " << gl::FmtHR(result); } } } @@ -263,7 +336,7 @@ gl::Error Image9::createSurface() mDirty = false; mD3DPool = poolToUse; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) @@ -280,13 +353,13 @@ gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to lock image surface, " << gl::FmtHR(result); } mDirty = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Image9::unlock() @@ -294,7 +367,6 @@ void Image9::unlock() if (mSurface) { HRESULT result = mSurface->UnlockRect(); - UNUSED_ASSERTION_VARIABLE(result); ASSERT(SUCCEEDED(result)); } } @@ -312,7 +384,9 @@ bool Image9::isDirty() const { // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet // if initialization is required before use. - return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; + return (mSurface || + d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != nullptr) && + mDirty; } gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) @@ -324,14 +398,16 @@ gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) } *outSurface = mSurface; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) +gl::Error Image9::setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) { - IDirect3DSurface9 *surface = NULL; + IDirect3DSurface9 *surface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - gl::Error error = storage9->getSurfaceLevel(GL_TEXTURE_2D, level, false, &surface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_2D, level, false, &surface); if (error.isError()) { return error; @@ -339,12 +415,15 @@ gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) return setManagedSurface(surface); } -gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +gl::Error Image9::setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) { - IDirect3DSurface9 *surface = NULL; + IDirect3DSurface9 *surface = nullptr; TextureStorage9 *storage9 = GetAs(storage); - gl::Error error = - storage9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); + gl::Error error = storage9->getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + level, false, &surface); if (error.isError()) { return error; @@ -374,10 +453,13 @@ gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface) mD3DPool = desc.Pool; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error Image9::copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) { gl::Error error = createSurface(); if (error.isError()) @@ -387,11 +469,12 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i TextureStorage9 *storage9 = GetAs(storage); - IDirect3DSurface9 *destSurface = NULL; + IDirect3DSurface9 *destSurface = nullptr; if (index.type == GL_TEXTURE_2D) { - error = storage9->getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, true, &destSurface); + error = + storage9->getSurfaceLevel(context, GL_TEXTURE_2D, index.mipIndex, true, &destSurface); if (error.isError()) { return error; @@ -400,7 +483,7 @@ gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &i else { ASSERT(gl::IsCubeMapTextureTarget(index.type)); - error = storage9->getSurfaceLevel(index.type, index.mipIndex, true, &destSurface); + error = storage9->getSurfaceLevel(context, index.type, index.mipIndex, true, &destSurface); if (error.isError()) { return error; @@ -417,7 +500,7 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a ASSERT(area.width > 0 && area.height > 0 && area.depth == 1); ASSERT(destSurface); - IDirect3DSurface9 *sourceSurface = NULL; + IDirect3DSurface9 *sourceSurface = nullptr; gl::Error error = getSurface(&sourceSurface); if (error.isError()) { @@ -442,19 +525,22 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a sourceSurface->GetDesc(&desc); IDirect3DSurface9 *surf = 0; - HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &surf, nullptr); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() + << "Internal CreateOffscreenPlainSurface call failed, " << gl::FmtHR(result); } - copyLockableSurfaces(surf, sourceSurface); + auto err = copyLockableSurfaces(surf, sourceSurface); result = device->UpdateSurface(surf, &rect, destSurface, &point); SafeRelease(surf); + ANGLE_TRY(err); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal UpdateSurface call failed, " << gl::FmtHR(result); } } else @@ -464,27 +550,36 @@ gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &a ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal UpdateSurface call failed, " << gl::FmtHR(result); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle. -gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +gl::Error Image9::loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) { // 3D textures are not supported by the D3D9 backend. ASSERT(area.z == 0 && area.depth == 1); - 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 gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLuint inputRowPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), + inputRowPitch); + ASSERT(!applySkipImages); + ASSERT(unpack.skipPixels == 0); + ASSERT(unpack.skipRows == 0); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - ASSERT(d3dFormatInfo.loadFunction != NULL); + ASSERT(d3dFormatInfo.loadFunction != nullptr); RECT lockRect = { @@ -500,31 +595,34 @@ gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpa } d3dFormatInfo.loadFunction(area.width, area.height, area.depth, - reinterpret_cast(input) + inputSkipBytes, - inputRowPitch, 0, reinterpret_cast(locked.pBits), - locked.Pitch, 0); + reinterpret_cast(input), inputRowPitch, 0, + reinterpret_cast(locked.pBits), locked.Pitch, 0); unlock(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) +gl::Error Image9::loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) { // 3D textures are not supported by the D3D9 backend. ASSERT(area.z == 0 && area.depth == 1); - 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, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0), inputRowPitch); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, 0, inputDepthPitch), + inputDepthPitch); const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); - ASSERT(d3d9FormatInfo.loadFunction != NULL); + ASSERT(d3d9FormatInfo.loadFunction != nullptr); RECT lockRect = { @@ -545,7 +643,7 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) unlock(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures @@ -565,16 +663,19 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, IDirect3DDevice9 *device = mRenderer->getDevice(); - IDirect3DSurface9 *renderTargetData = NULL; + IDirect3DSurface9 *renderTargetData = nullptr; D3DSURFACE_DESC description; surface->GetDesc(&description); - HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, + description.Format, D3DPOOL_SYSTEMMEM, + &renderTargetData, nullptr); if (FAILED(result)) { SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); + return gl::OutOfMemory() << "Could not create matching destination surface, " + << gl::FmtHR(result); } result = device->GetRenderTargetData(surface, renderTargetData); @@ -583,7 +684,8 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, { SafeRelease(renderTargetData); SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); + return gl::OutOfMemory() << "GetRenderTargetData unexpectedly failed, " + << gl::FmtHR(result); } int width = sourceArea.width; @@ -599,7 +701,9 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, { SafeRelease(renderTargetData); SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to lock the source surface (rectangle might be invalid), " + << gl::FmtHR(result); } D3DLOCKED_RECT destLock = {0}; @@ -776,13 +880,15 @@ gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset, SafeRelease(surface); mDirty = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) +gl::Error Image9::copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) { RenderTargetD3D *renderTarget = nullptr; - gl::Error error = source->getRenderTarget(imageIndex, &renderTarget); + gl::Error error = source->getRenderTarget(context, imageIndex, &renderTarget); if (error.isError()) { return error; @@ -792,15 +898,16 @@ gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureSt return copyFromRTInternal(gl::Offset(), sourceArea, renderTarget); } -gl::Error Image9::copyFromFramebuffer(const gl::Offset &destOffset, +gl::Error Image9::copyFromFramebuffer(const gl::Context *context, + 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); + RenderTargetD3D *renderTarget = nullptr; + gl::Error error = srcAttachment->getRenderTarget(context, &renderTarget); if (error.isError()) { return error; 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 91448cc849..01c60dc4fb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h @@ -26,27 +26,53 @@ class Image9 : public ImageD3D { public: Image9(Renderer9 *renderer); - ~Image9(); + ~Image9() override; static gl::Error generateMipmap(Image9 *dest, Image9 *source); static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + static gl::Error CopyImage(const gl::Context *context, + Image9 *dest, + Image9 *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; D3DFORMAT getD3DFormat() const; - virtual bool isDirty() const; - - virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level); - virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level); - virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); - - 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); - - gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override; - gl::Error copyFromFramebuffer(const gl::Offset &destOffset, + bool isDirty() const override; + + gl::Error setManagedSurface2D(const gl::Context *context, + TextureStorage *storage, + int level) override; + gl::Error setManagedSurfaceCube(const gl::Context *context, + TextureStorage *storage, + int face, + int level) override; + gl::Error copyToStorage(const gl::Context *context, + TextureStorage *storage, + const gl::ImageIndex &index, + const gl::Box ®ion) override; + + gl::Error loadData(const gl::Context *context, + const gl::Box &area, + const gl::PixelUnpackState &unpack, + GLenum type, + const void *input, + bool applySkipImages) override; + gl::Error loadCompressedData(const gl::Context *context, + const gl::Box &area, + const void *input) override; + + gl::Error copyFromTexStorage(const gl::Context *context, + const gl::ImageIndex &imageIndex, + TextureStorage *source) override; + gl::Error copyFromFramebuffer(const gl::Context *context, + const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) override; 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 97c7f72136..df86331766 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -14,7 +14,7 @@ namespace rx IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) { - mIndexBuffer = NULL; + mIndexBuffer = nullptr; mBufferSize = 0; mIndexType = 0; mDynamic = false; @@ -40,7 +40,7 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo } else if (indexType == GL_UNSIGNED_INT) { - ASSERT(mRenderer->getRendererExtensions().elementIndexUint); + ASSERT(mRenderer->getNativeExtensions().elementIndexUint); format = D3DFMT_INDEX32; } else UNREACHABLE(); @@ -54,7 +54,8 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + return gl::OutOfMemory() + << "Failed to allocate internal index buffer of size " << bufferSize; } } @@ -62,43 +63,43 @@ gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bo mIndexType = indexType; mDynamic = dynamic; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) { if (!mIndexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; - void *mapPtr = NULL; + void *mapPtr = nullptr; HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to lock internal index buffer, " << gl::FmtHR(result); } *outMappedMemory = mapPtr; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error IndexBuffer9::unmapBuffer() { if (!mIndexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } HRESULT result = mIndexBuffer->Unlock(); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to unlock internal index buffer, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLenum IndexBuffer9::getIndexType() const @@ -119,7 +120,7 @@ gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -127,7 +128,7 @@ gl::Error IndexBuffer9::discard() { if (!mIndexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + return gl::OutOfMemory() << "Internal index buffer is not initialized."; } void *dummy; @@ -136,16 +137,16 @@ gl::Error IndexBuffer9::discard() result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to lock internal index buffer, " << gl::FmtHR(result); } result = mIndexBuffer->Unlock(); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to unlock internal index buffer, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } D3DFORMAT IndexBuffer9::getIndexFormat() const 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 ba03ba703f..5921d2a859 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h @@ -19,18 +19,18 @@ class IndexBuffer9 : public IndexBuffer { public: explicit IndexBuffer9(Renderer9 *const renderer); - virtual ~IndexBuffer9(); + ~IndexBuffer9() override; - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) override; - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); + gl::Error mapBuffer(unsigned int offset, unsigned int size, void **outMappedMemory) override; + gl::Error unmapBuffer() override; - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + GLenum getIndexType() const override; + unsigned int getBufferSize() const override; + gl::Error setSize(unsigned int bufferSize, GLenum indexType) override; - virtual gl::Error discard(); + gl::Error discard() override; D3DFORMAT getIndexFormat() const; IDirect3DIndexBuffer9 *getBuffer() const; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp new file mode 100644 index 0000000000..388b8aa168 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow9.cpp: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" + +namespace rx +{ +NativeWindow9::NativeWindow9(EGLNativeWindowType window) : NativeWindowD3D(window) +{ +} + +bool NativeWindow9::initialize() +{ + return true; +} + +bool NativeWindow9::getClientRect(LPRECT rect) const +{ + return GetClientRect(getNativeWindow(), rect) == TRUE; +} + +bool NativeWindow9::isIconic() const +{ + return IsIconic(getNativeWindow()) == TRUE; +} + +// static +bool NativeWindow9::IsValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h new file mode 100644 index 0000000000..a56b08dc81 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/NativeWindow9.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow9.h: Defines NativeWindow9, a class for managing and +// performing operations on an EGLNativeWindowType for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include "libANGLE/renderer/d3d/NativeWindowD3D.h" + +namespace rx +{ + +class NativeWindow9 : public NativeWindowD3D +{ + public: + explicit NativeWindow9(EGLNativeWindowType window); + + bool initialize() override; + bool getClientRect(LPRECT rect) const override; + bool isIconic() const override; + + static bool IsValidNativeWindow(EGLNativeWindowType window); +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_NATIVEWINDOW9_H_ 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 c826abf81c..4ba053e6bd 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp @@ -19,7 +19,7 @@ Query9::Query9(Renderer9 *renderer, GLenum type) mResult(GL_FALSE), mQueryFinished(false), mRenderer(renderer), - mQuery(NULL) + mQuery(nullptr) { } @@ -30,23 +30,27 @@ Query9::~Query9() gl::Error Query9::begin() { - if (mQuery == NULL) + D3DQUERYTYPE d3dQueryType = gl_d3d9::ConvertQueryType(getType()); + if (mQuery == nullptr) { - HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); + HRESULT result = mRenderer->getDevice()->CreateQuery(d3dQueryType, &mQuery); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + return gl::OutOfMemory() << "Internal query creation failed, " << gl::FmtHR(result); } } - HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) + if (d3dQueryType != D3DQUERYTYPE_EVENT) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::OutOfMemory() << "Failed to begin internal query, " << gl::FmtHR(result); + } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::end() @@ -57,19 +61,19 @@ gl::Error Query9::end() ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to end internal query, " << gl::FmtHR(result); } mQueryFinished = false; mResult = GL_FALSE; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::queryCounter() { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Unimplemented"); + return gl::InternalError() << "Unimplemented"; } template @@ -91,7 +95,7 @@ gl::Error Query9::getResultBase(T *params) ASSERT(mQueryFinished); *params = static_cast(mResult); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::getResult(GLint *params) @@ -124,7 +128,7 @@ gl::Error Query9::isResultAvailable(bool *available) *available = mQueryFinished; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Query9::testQuery() @@ -133,38 +137,52 @@ gl::Error Query9::testQuery() { ASSERT(mQuery); - DWORD numPixels = 0; - - HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); - if (hres == S_OK) + HRESULT result = S_OK; + switch (getType()) { - mQueryFinished = true; + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + DWORD numPixels = 0; + result = mQuery->GetData(&numPixels, sizeof(numPixels), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + break; + } - switch (getType()) + case GL_COMMANDS_COMPLETED_CHROMIUM: { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + BOOL completed = FALSE; + result = mQuery->GetData(&completed, sizeof(completed), D3DGETDATA_FLUSH); + if (result == S_OK) + { + mQueryFinished = true; + mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; + } break; + } - default: + default: UNREACHABLE(); break; - } } - else if (d3d9::isDeviceLostError(hres)) + + if (d3d9::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + return gl::OutOfMemory() << "Failed to test get query result, device is lost."; } else if (mRenderer->testDeviceLost()) { mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + return gl::OutOfMemory() << "Failed to test get query result, device is lost."; } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } 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 9d17711a00..6c7c22f096 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h @@ -19,16 +19,16 @@ class Query9 : public QueryImpl { public: Query9(Renderer9 *renderer, GLenum type); - virtual ~Query9(); - - 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 getResult(GLint64 *params); - virtual gl::Error getResult(GLuint64 *params); - virtual gl::Error isResultAvailable(bool *available); + ~Query9() override; + + gl::Error begin() override; + gl::Error end() override; + gl::Error queryCounter() override; + gl::Error getResult(GLint *params) override; + gl::Error getResult(GLuint *params) override; + gl::Error getResult(GLint64 *params) override; + gl::Error getResult(GLuint64 *params) override; + gl::Error isResultAvailable(bool *available) override; private: gl::Error testQuery(); 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 419bff1f63..3e54c27f43 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp @@ -130,7 +130,8 @@ GLsizei SurfaceRenderTarget9::getDepth() const GLenum SurfaceRenderTarget9::getInternalFormat() const { - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetRenderTargetInternalFormat()); + return (mDepth ? mSwapChain->getDepthBufferInternalFormat() + : mSwapChain->getRenderTargetInternalFormat()); } GLsizei SurfaceRenderTarget9::getSamples() const 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 f19c54de7b..bb3b5a4ee4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h @@ -21,7 +21,7 @@ class RenderTarget9 : public RenderTargetD3D { public: RenderTarget9() { } - virtual ~RenderTarget9() { } + ~RenderTarget9() override {} // Retrieve the texture that backs this render target, may be null for swap chain render // targets. virtual IDirect3DBaseTexture9 *getTexture() const = 0; @@ -43,7 +43,7 @@ class TextureRenderTarget9 : public RenderTarget9 GLsizei height, GLsizei depth, GLsizei samples); - virtual ~TextureRenderTarget9(); + ~TextureRenderTarget9() override; GLsizei getWidth() const override; GLsizei getHeight() const override; @@ -74,7 +74,7 @@ class SurfaceRenderTarget9 : public RenderTarget9 { public: SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); - virtual ~SurfaceRenderTarget9(); + ~SurfaceRenderTarget9() override; GLsizei getWidth() const override; GLsizei getHeight() 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 6bb975b0e4..75c6298868 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -8,51 +8,51 @@ #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" -#include #include +#include #include "common/utilities.h" -#include "libANGLE/angletypes.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.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/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/d3d9/Blit9.h" #include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.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/NativeWindow9.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/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 "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" #include "third_party/trace_event/trace_event.h" - - #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) #define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif @@ -69,69 +69,69 @@ namespace rx enum { MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256, - MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, - MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, - MAX_VARYING_VECTORS_SM2 = 8, - MAX_VARYING_VECTORS_SM3 = 10, + MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, + MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, + MAX_VARYING_VECTORS_SM2 = 8, + MAX_VARYING_VECTORS_SM3 = 10, MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 }; Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this) { - mD3d9Module = NULL; + mD3d9Module = nullptr; - mD3d9 = NULL; - mD3d9Ex = NULL; - mDevice = NULL; - mDeviceEx = NULL; - mDeviceWindow = NULL; - mBlit = NULL; + mD3d9 = nullptr; + mD3d9Ex = nullptr; + mDevice = nullptr; + mDeviceEx = nullptr; + mDeviceWindow = nullptr; + mBlit = nullptr; mAdapter = D3DADAPTER_DEFAULT; const egl::AttributeMap &attributes = display->getAttributeMap(); - EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + EGLint requestedDeviceType = static_cast(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: - mDeviceType = D3DDEVTYPE_HAL; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + mDeviceType = D3DDEVTYPE_HAL; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: - mDeviceType = D3DDEVTYPE_REF; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mDeviceType = D3DDEVTYPE_REF; + break; - case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: - mDeviceType = D3DDEVTYPE_NULLREF; - break; + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDeviceType = D3DDEVTYPE_NULLREF; + break; - default: - UNREACHABLE(); + default: + UNREACHABLE(); } - mMaskedClearSavedState = NULL; + mMaskedClearSavedState = nullptr; - mVertexDataManager = NULL; - mIndexDataManager = NULL; - mLineLoopIB = NULL; - mCountingIB = NULL; + mVertexDataManager = nullptr; + mIndexDataManager = nullptr; + mLineLoopIB = nullptr; + mCountingIB = nullptr; mMaxNullColorbufferLRU = 0; for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) { mNullColorbufferCache[i].lruCount = 0; - mNullColorbufferCache[i].width = 0; - mNullColorbufferCache[i].height = 0; - mNullColorbufferCache[i].buffer = NULL; + mNullColorbufferCache[i].width = 0; + mNullColorbufferCache[i].height = 0; + mNullColorbufferCache[i].buffer = nullptr; } - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; mAppliedProgramSerial = 0; - initializeDebugAnnotator(); + gl::InitializeDebugAnnotations(&mAnnotator); mEGLDevice = nullptr; } @@ -154,6 +154,10 @@ void Renderer9::release() { RendererD3D::cleanup(); + gl::UninitializeDebugAnnotations(); + + mTranslatedAttribCache.clear(); + releaseDeviceResources(); SafeDelete(mEGLDevice); @@ -167,10 +171,10 @@ void Renderer9::release() if (mDeviceWindow) { DestroyWindow(mDeviceWindow); - mDeviceWindow = NULL; + mDeviceWindow = nullptr; } - mD3d9Module = NULL; + mD3d9Module = nullptr; } egl::Error Renderer9::initialize() @@ -178,22 +182,25 @@ egl::Error Renderer9::initialize() TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9"); mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); - if (mD3d9Module == NULL) + if (mD3d9Module == nullptr) { - return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "No D3D9 module found."); + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "No D3D9 module found."; } - typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); - Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + typedef HRESULT(WINAPI * Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex **); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = + reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); // Use Direct3D9Ex if available. Among other things, this version is less // inclined to report a lost context, for example when the user switches - // 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))) + // 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.angle", "D3d9Ex_QueryInterface"); ASSERT(mD3d9Ex); - mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); ASSERT(mD3d9); } else @@ -204,12 +211,13 @@ egl::Error Renderer9::initialize() if (!mD3d9) { - return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "Could not create D3D9 device."); + return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "Could not create D3D9 device."; } if (mDisplay->getNativeDisplayId() != nullptr) { - // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context + // corresponds to } HRESULT result; @@ -226,13 +234,14 @@ egl::Error Renderer9::initialize() } else if (result == D3DERR_NOTAVAILABLE) { - Sleep(100); // Give the driver some time to initialize/recover + Sleep(100); // Give the driver some time to initialize/recover } - else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from + else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, + // D3DERR_INVALIDDEVICE, or another error we can't recover + // from { - return egl::Error(EGL_NOT_INITIALIZED, - D3D9_INIT_OTHER_ERROR, - "Failed to get device caps: Error code 0x%x\n", result); + return egl::EglNotInitialized(D3D9_INIT_OTHER_ERROR) + << "Failed to get device caps, " << gl::FmtHR(result); } } } @@ -245,18 +254,17 @@ egl::Error Renderer9::initialize() if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0)) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D9_INIT_UNSUPPORTED_VERSION, - "Renderer does not support PS %u.%u.aborting!", minShaderModel, 0); + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_VERSION) + << "Renderer does not support PS " << minShaderModel << ".0, aborting!"; } - // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. - // This is required by Texture2D::ensureRenderTarget. + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture + // to a render target texture is not supported. This is required by + // Texture2D::ensureRenderTarget. if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) { - return egl::Error(EGL_NOT_INITIALIZED, - D3D9_INIT_UNSUPPORTED_STRETCHRECT, - "Renderer does not support StretctRect from textures."); + return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_STRETCHRECT) + << "Renderer does not support StretctRect from textures."; } { @@ -265,43 +273,52 @@ egl::Error Renderer9::initialize() } static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); - static const TCHAR className[] = TEXT("STATIC"); + static const TCHAR className[] = TEXT("STATIC"); { 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); + mDeviceWindow = + CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, + 1, HWND_MESSAGE, nullptr, GetModuleHandle(nullptr), nullptr); } D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; + DWORD behaviorFlags = + D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; { TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); + result = mD3d9->CreateDevice( + mAdapter, mDeviceType, mDeviceWindow, + behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, + &presentParameters, &mDevice); } if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) { - return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, - "CreateDevice failed: device lost of out of memory"); + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice failed: device lost of out of memory"; } if (FAILED(result)) { TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, + behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &presentParameters, &mDevice); if (FAILED(result)) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); - return egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, - "CreateDevice2 failed: device lost, not available, or of out of memory"); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || + result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY) + << "CreateDevice2 failed: device lost, not available, or of out of memory"; } } if (mD3d9Ex) { TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface"); - result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void **)&mDeviceEx); ASSERT(SUCCEEDED(result)); } @@ -318,18 +335,19 @@ egl::Error Renderer9::initialize() // Only Direct3D 10 ready devices support all the necessary vertex texture formats. // We test this using D3D9 by checking support for the R16F format. mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, - D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); + SUCCEEDED(mD3d9->CheckDeviceFormat( + mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); - initializeDevice(); + ANGLE_TRY(initializeDevice()); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } // do any one-time device initialization // NOTE: this is also needed after a device lost/reset // to reset the scene status and ensure the default states are reset. -void Renderer9::initializeDevice() +egl::Error Renderer9::initializeDevice() { // Permanent non-default states mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); @@ -337,14 +355,14 @@ void Renderer9::initializeDevice() if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) { - mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD &)mDeviceCaps.MaxPointSize); } else { - mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f } - const gl::Caps &rendererCaps = getRendererCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); @@ -358,50 +376,55 @@ void Renderer9::initializeDevice() ASSERT(!mBlit); mBlit = new Blit9(this); - mBlit->initialize(); + ANGLE_TRY(mBlit->initialize()); ASSERT(!mVertexDataManager && !mIndexDataManager); mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this, getRendererClass()); + mIndexDataManager = new IndexDataManager(this); + + if (mVertexDataManager->initialize().isError()) + { + return egl::EglBadAlloc() << "Error initializing VertexDataManager"; + } + + mTranslatedAttribCache.resize(getNativeCaps().maxVertexAttributes); + + mStateManager.initialize(); - // TODO(jmadill): use context caps, and place in common D3D location - mTranslatedAttribCache.resize(getRendererCaps().maxVertexAttributes); + return egl::NoError(); } D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters() { D3DPRESENT_PARAMETERS presentParameters = {0}; - // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters. + // The default swap chain is never actually used. Surface will create a new swap chain with the + // proper parameters. presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; - presentParameters.BackBufferCount = 1; - presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; - presentParameters.BackBufferWidth = 1; - presentParameters.BackBufferHeight = 1; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferWidth = 1; + presentParameters.BackBufferHeight = 1; presentParameters.EnableAutoDepthStencil = FALSE; - presentParameters.Flags = 0; - presentParameters.hDeviceWindow = mDeviceWindow; - presentParameters.MultiSampleQuality = 0; - presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; - presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; - presentParameters.Windowed = TRUE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mDeviceWindow; + presentParameters.MultiSampleQuality = 0; + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; return presentParameters; } -egl::ConfigSet Renderer9::generateConfigs() const +egl::ConfigSet Renderer9::generateConfigs() { - static const GLenum colorBufferFormats[] = - { - GL_BGR5_A1_ANGLEX, - GL_BGRA8_EXT, - GL_RGB565, + static const GLenum colorBufferFormats[] = { + GL_BGR5_A1_ANGLEX, GL_BGRA8_EXT, GL_RGB565, }; - static const GLenum depthStencilBufferFormats[] = - { + static const GLenum depthStencilBufferFormats[] = { GL_NONE, GL_DEPTH_COMPONENT32_OES, GL_DEPTH24_STENCIL8_OES, @@ -409,8 +432,8 @@ egl::ConfigSet Renderer9::generateConfigs() const GL_DEPTH_COMPONENT16, }; - const gl::Caps &rendererCaps = getRendererCaps(); - const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + const gl::Caps &rendererCaps = getNativeCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps(); D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); @@ -449,56 +472,72 @@ egl::ConfigSet Renderer9::generateConfigs() const for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) { GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; - const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + const gl::TextureCaps &colorBufferFormatCaps = + rendererTextureCaps.get(colorBufferInternalFormat); if (colorBufferFormatCaps.renderable) { - for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + for (size_t depthStencilIndex = 0; + depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) { - GLenum depthStencilBufferInternalFormat = 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); - const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = d3d9::GetTextureFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &colorBufferFormatInfo = + gl::GetSizedInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = + gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat); + const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = + d3d9::GetTextureFormatInfo(colorBufferInternalFormat); 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.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; // Mark as slow if blits to the back-buffer won't be straight forward - config.configCaveat = (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) ? EGL_NONE : EGL_SLOW_CONFIG; - config.configID = static_cast(configs.size() + 1); - config.conformant = EGL_OPENGL_ES2_BIT; - config.depthSize = depthStencilBufferFormatInfo.depthBits; - config.level = 0; + config.configCaveat = + (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) + ? EGL_NONE + : EGL_SLOW_CONFIG; + config.configID = static_cast(configs.size() + 1); + config.conformant = EGL_OPENGL_ES2_BIT; + 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 = maxSwapInterval; - config.minSwapInterval = minSwapInterval; + config.maxPBufferWidth = rendererCaps.max2DTextureSize; + config.maxPBufferHeight = rendererCaps.max2DTextureSize; + config.maxPBufferPixels = + rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; + config.maxSwapInterval = maxSwapInterval; + config.minSwapInterval = minSwapInterval; config.nativeRenderable = EGL_FALSE; - config.nativeVisualID = 0; + config.nativeVisualID = 0; config.nativeVisualType = EGL_NONE; - config.renderableType = EGL_OPENGL_ES2_BIT; - 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.renderableType = EGL_OPENGL_ES2_BIT; + 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.transparentBlueValue = 0; + config.colorComponentType = gl_egl::GLComponentTypeToEGLColorComponentType( + colorBufferFormatInfo.componentType); configs.add(config); } @@ -519,13 +558,12 @@ void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) outExtensions->d3dShareHandleClientBuffer = true; outExtensions->surfaceD3DTexture2DShareHandle = true; } + outExtensions->d3dTextureClientBuffer = 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; @@ -533,6 +571,14 @@ void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) outExtensions->glRenderbufferImage = true; outExtensions->flexibleSurfaceCompatibility = true; + + // Contexts are virtualized so textures can be shared globally + outExtensions->displayTextureShareGroup = true; + + // D3D9 can be used without an output surface + outExtensions->surfacelessContext = true; + + outExtensions->robustResourceInitialization = true; } void Renderer9::startScene() @@ -540,7 +586,8 @@ void Renderer9::startScene() if (!mSceneStarted) { long result = mDevice->BeginScene(); - if (SUCCEEDED(result)) { + if (SUCCEEDED(result)) + { // This is defensive checking against the device being // lost at unexpected times. mSceneStarted = true; @@ -561,8 +608,8 @@ void Renderer9::endScene() gl::Error Renderer9::flush() { - IDirect3DQuery9* query = NULL; - gl::Error error = allocateEventQuery(&query); + IDirect3DQuery9 *query = nullptr; + gl::Error error = allocateEventQuery(&query); if (error.isError()) { return error; @@ -572,11 +619,11 @@ gl::Error Renderer9::flush() if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to issue event query, " << gl::FmtHR(result); } // Grab the query data once - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); freeEventQuery(query); if (FAILED(result)) { @@ -585,16 +632,16 @@ gl::Error Renderer9::flush() notifyDeviceLost(); } - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::finish() { - IDirect3DQuery9* query = NULL; - gl::Error error = allocateEventQuery(&query); + IDirect3DQuery9 *query = nullptr; + gl::Error error = allocateEventQuery(&query); if (error.isError()) { return error; @@ -604,11 +651,11 @@ gl::Error Renderer9::finish() if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to issue event query, " << gl::FmtHR(result); } // Grab the query data once - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); if (FAILED(result)) { if (d3d9::isDeviceLostError(result)) @@ -617,7 +664,7 @@ gl::Error Renderer9::finish() } freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } // Loop until the query completes @@ -626,7 +673,7 @@ gl::Error Renderer9::finish() // Keep polling, but allow other threads to do something useful first ScheduleYield(); - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH); // explicitly check for device loss // some drivers seem to return S_FALSE even if the device is lost @@ -644,34 +691,146 @@ gl::Error Renderer9::finish() } freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get event query data, " << gl::FmtHR(result); } - } freeEventQuery(query); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +bool Renderer9::isValidNativeWindow(EGLNativeWindowType window) const +{ + return NativeWindow9::IsValidNativeWindow(window); +} + +NativeWindowD3D *Renderer9::createNativeWindow(EGLNativeWindowType window, + const egl::Config *, + const egl::AttributeMap &) const +{ + return new NativeWindow9(window); } -SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, +SwapChainD3D *Renderer9::createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) + EGLint orientation, + EGLint samples) { - return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat, - orientation); + return new SwapChain9(this, GetAs(nativeWindow), shareHandle, d3dTexture, + backBufferFormat, depthBufferFormat, orientation); } -CompilerImpl *Renderer9::createCompiler() +egl::Error Renderer9::getD3DTextureInfo(const egl::Config *config, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const { - return new CompilerD3D(SH_HLSL_3_0_OUTPUT); + IDirect3DTexture9 *texture = nullptr; + if (FAILED(d3dTexture->QueryInterface(&texture))) + { + return egl::EglBadParameter() << "Client buffer is not a IDirect3DTexture9"; + } + + IDirect3DDevice9 *textureDevice = nullptr; + texture->GetDevice(&textureDevice); + if (textureDevice != mDevice) + { + SafeRelease(texture); + return egl::EglBadParameter() << "Texture's device does not match."; + } + SafeRelease(textureDevice); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (width) + { + *width = static_cast(desc.Width); + } + if (height) + { + *height = static_cast(desc.Height); + } + + // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. + switch (desc.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + break; + + default: + return egl::EglBadParameter() + << "Unknown client buffer texture format: " << desc.Format; + } + + if (fboFormat) + { + const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ASSERT(d3dFormatInfo.info().id != angle::Format::ID::NONE); + *fboFormat = d3dFormatInfo.info().fboImplementationInternalFormat; + } + + return egl::NoError(); +} + +egl::Error Renderer9::validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const +{ + if (shareHandle == nullptr) + { + return egl::EglBadParameter() << "NULL share handle."; + } + + EGLint width = attribs.getAsInt(EGL_WIDTH, 0); + EGLint height = attribs.getAsInt(EGL_HEIGHT, 0); + ASSERT(width != 0 && height != 0); + + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(config->renderTargetFormat); + + IDirect3DTexture9 *texture = nullptr; + HRESULT result = mDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &texture, &shareHandle); + if (FAILED(result)) + { + return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result); + } + + DWORD levelCount = texture->GetLevelCount(); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + SafeRelease(texture); + + if (levelCount != 1 || desc.Width != static_cast(width) || + desc.Height != static_cast(height) || + desc.Format != backBufferd3dFormatInfo.texFormat) + { + return egl::EglBadParameter() << "Invalid texture parameters in share handle texture."; + } + + return egl::NoError(); +} + +ContextImpl *Renderer9::createContext(const gl::ContextState &state) +{ + return new Context9(state, this); } void *Renderer9::getD3DDevice() { - return reinterpret_cast(mDevice); + return reinterpret_cast(mDevice); } gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) @@ -682,7 +841,7 @@ gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to allocate event query, " << gl::FmtHR(result); } } else @@ -691,10 +850,10 @@ gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) mEventQueryPool.pop_back(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Renderer9::freeEventQuery(IDirect3DQuery9* query) +void Renderer9::freeEventQuery(IDirect3DQuery9 *query) { if (mEventQueryPool.size() > 1000) { @@ -706,20 +865,26 @@ void Renderer9::freeEventQuery(IDirect3DQuery9* query) } } -gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) +gl::Error Renderer9::createVertexShader(const DWORD *function, + size_t length, + IDirect3DVertexShader9 **outShader) { return mVertexShaderCache.create(function, length, outShader); } -gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) +gl::Error Renderer9::createPixelShader(const DWORD *function, + size_t length, + IDirect3DPixelShader9 **outShader) { return mPixelShaderCache.create(function, length, outShader); } -HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) +HRESULT Renderer9::createVertexBuffer(UINT Length, + DWORD Usage, + IDirect3DVertexBuffer9 **ppVertexBuffer) { D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); + return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, nullptr); } VertexBuffer *Renderer9::createVertexBuffer() @@ -727,10 +892,13 @@ VertexBuffer *Renderer9::createVertexBuffer() return new VertexBuffer9(this); } -HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) +HRESULT Renderer9::createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer) { D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); + return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, nullptr); } IndexBuffer *Renderer9::createIndexBuffer() @@ -738,36 +906,13 @@ IndexBuffer *Renderer9::createIndexBuffer() return new IndexBuffer9(this); } -BufferImpl *Renderer9::createBuffer() -{ - return new Buffer9(this); -} - -VertexArrayImpl *Renderer9::createVertexArray(const gl::VertexArray::Data &data) -{ - return new VertexArray9(data); -} - -QueryImpl *Renderer9::createQuery(GLenum type) -{ - return new Query9(this, type); -} - -FenceNVImpl *Renderer9::createFenceNV() -{ - return new FenceNV9(this); -} - -FenceSyncImpl *Renderer9::createFenceSync() +StreamProducerImpl *Renderer9::createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) { - // Renderer9 doesn't support ES 3.0 and its sync objects. + // Streams are not supported under D3D9 UNREACHABLE(); - return NULL; -} - -TransformFeedbackImpl* Renderer9::createTransformFeedback() -{ - return new TransformFeedbackD3D(); + return nullptr; } bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const @@ -776,22 +921,24 @@ bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const return false; } -gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer9::fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) { // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Renderer9::generateSwizzle(gl::Texture *texture) -{ - // Swizzled textures are not available in ES2 or D3D9 - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) +gl::Error Renderer9::setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &samplerState) { CurSamplerState &appliedSampler = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates[index] : mCurVertexSamplerStates[index]; @@ -800,11 +947,7 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur TextureD3D *textureD3D = GetImplAs(texture); TextureStorage *storage = nullptr; - gl::Error error = textureD3D->getNativeTexture(&storage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureD3D->getNativeTexture(context, &storage)); // Storage should exist, texture should be complete ASSERT(storage); @@ -815,12 +958,16 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0) { int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; + 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_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)); + mDevice->SetSamplerState( + d3dSampler, D3DSAMP_MAGFILTER, + gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; float lodBias; @@ -830,52 +977,50 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Textur mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast(lodBias)); - if (getRendererExtensions().textureFilterAnisotropic) + if (getNativeExtensions().textureFilterAnisotropic) { - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); + DWORD maxAnisotropy = + std::min(mDeviceCaps.MaxAnisotropy, static_cast(samplerState.maxAnisotropy)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy); } } - appliedSampler.forceSet = false; + appliedSampler.forceSet = false; appliedSampler.samplerState = samplerState; - appliedSampler.baseLevel = baseLevel; + appliedSampler.baseLevel = baseLevel; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +gl::Error Renderer9::setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture) { - int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; - IDirect3DBaseTexture9 *d3dTexture = NULL; - bool forceSetTexture = false; + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = nullptr; + bool forceSetTexture = false; - std::vector &appliedTextures = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures; + std::vector &appliedTextures = + (type == gl::SAMPLER_PIXEL) ? mCurPixelTextures : mCurVertexTextures; if (texture) { TextureD3D *textureImpl = GetImplAs(texture); TextureStorage *texStorage = nullptr; - gl::Error error = textureImpl->getNativeTexture(&texStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage)); // Texture should be complete and have a storage ASSERT(texStorage); TextureStorage9 *storage9 = GetAs(texStorage); - error = storage9->getBaseTexture(&d3dTexture); - if (error.isError()) - { - return error; - } + ANGLE_TRY(storage9->getBaseTexture(context, &d3dTexture)); // If we get NULL back from getBaseTexture here, something went wrong // in the texture class and we're unexpectedly missing the d3d texture - ASSERT(d3dTexture != NULL); + ASSERT(d3dTexture != nullptr); forceSetTexture = textureImpl->hasDirtyImages(); textureImpl->resetDirty(); @@ -888,60 +1033,50 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te appliedTextures[index] = reinterpret_cast(d3dTexture); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/, - const std::vector &/*vertexUniformBuffers*/, - const std::vector &/*fragmentUniformBuffers*/) +gl::Error Renderer9::updateState(const gl::Context *context, GLenum drawMode) { - // No effect in ES2/D3D9 - return gl::Error(GL_NO_ERROR); -} + const auto &glState = context->getGLState(); -void Renderer9::syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) -{ - mStateManager.syncState(state, bitmask); -} - -gl::Error Renderer9::updateState(const gl::Data &data, GLenum drawMode) -{ // 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::Framebuffer *framebuffer = glState.getDrawFramebuffer(); + ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit() && framebuffer->cachedComplete()); - gl::Error error = applyRenderTarget(framebufferObject); - if (error.isError()) - { - return error; - } + ANGLE_TRY(applyRenderTarget(context, framebuffer)); // Setting viewport state - setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(), - data.state->getFarPlane(), drawMode, data.state->getRasterizerState().frontFace, - false); + setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode, + glState.getRasterizerState().frontFace, false); // Setting scissors state - setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled()); // Setting blend, depth stencil, and rasterizer states - int samples = framebufferObject->getSamples(data); - gl::RasterizerState rasterizer = data.state->getRasterizerState(); + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = framebuffer->getFirstColorbuffer(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.multiSample = (samples != 0); - unsigned int mask = GetBlendSampleMask(data, samples); - error = setBlendDepthRasterStates(data, mask); - - if (error.isError()) - { - return error; - } + unsigned int mask = GetBlendSampleMask(glState, samples); + ANGLE_TRY(setBlendDepthRasterStates(context, mask)); mStateManager.resetDirtyBits(); - return error; + return gl::NoError(); } void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) @@ -949,71 +1084,85 @@ void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) mStateManager.setScissorState(scissor, enabled); } -gl::Error Renderer9::setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode) +gl::Error Renderer9::setBlendDepthRasterStates(const gl::Context *context, GLenum drawMode) { - int samples = glData.state->getDrawFramebuffer()->getSamples(glData); - gl::RasterizerState rasterizer = glData.state->getRasterizerState(); + const auto &glState = context->getGLState(); + gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + ASSERT(!drawFramebuffer->hasAnyDirtyBit()); + // Since framebuffer->getSamples will return the original samples which may be different with + // the sample counts that we set in render target view, here we use renderTarget->getSamples to + // get the actual samples. + GLsizei samples = 0; + const gl::FramebufferAttachment *firstColorAttachment = drawFramebuffer->getFirstColorbuffer(); + if (firstColorAttachment) + { + ASSERT(firstColorAttachment->isAttached()); + RenderTarget9 *renderTarget = nullptr; + ANGLE_TRY(firstColorAttachment->getRenderTarget(context, &renderTarget)); + samples = renderTarget->getSamples(); + } + gl::RasterizerState rasterizer = glState.getRasterizerState(); rasterizer.pointDrawMode = (drawMode == GL_POINTS); rasterizer.multiSample = (samples != 0); - unsigned int mask = GetBlendSampleMask(glData, samples); - return mStateManager.setBlendDepthRasterStates(*glData.state, mask); + unsigned int mask = GetBlendSampleMask(glState, samples); + return mStateManager.setBlendDepthRasterStates(glState, mask); } -void Renderer9::setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, +void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport) { - mStateManager.setViewportState(caps, viewport, zNear, zFar, drawMode, frontFace, - ignoreViewport); + mStateManager.setViewportState(viewport, zNear, zFar, drawMode, frontFace, ignoreViewport); } bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) { switch (mode) { - case GL_POINTS: - mPrimitiveType = D3DPT_POINTLIST; - mPrimitiveCount = count; - break; - case GL_LINES: - mPrimitiveType = D3DPT_LINELIST; - mPrimitiveCount = count / 2; - break; - case GL_LINE_LOOP: - mPrimitiveType = D3DPT_LINESTRIP; - mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately - break; - case GL_LINE_STRIP: - mPrimitiveType = D3DPT_LINESTRIP; - mPrimitiveCount = count - 1; - break; - case GL_TRIANGLES: - mPrimitiveType = D3DPT_TRIANGLELIST; - mPrimitiveCount = count / 3; - break; - case GL_TRIANGLE_STRIP: - mPrimitiveType = D3DPT_TRIANGLESTRIP; - mPrimitiveCount = count - 2; - break; - case GL_TRIANGLE_FAN: - mPrimitiveType = D3DPT_TRIANGLEFAN; - mPrimitiveCount = count - 2; - break; - default: - UNREACHABLE(); - return false; + case GL_POINTS: + mPrimitiveType = D3DPT_POINTLIST; + mPrimitiveCount = count; + break; + case GL_LINES: + mPrimitiveType = D3DPT_LINELIST; + mPrimitiveCount = count / 2; + break; + case GL_LINE_LOOP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = + count - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case GL_LINE_STRIP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; + break; + case GL_TRIANGLES: + mPrimitiveType = D3DPT_TRIANGLELIST; + mPrimitiveCount = count / 3; + break; + case GL_TRIANGLE_STRIP: + mPrimitiveType = D3DPT_TRIANGLESTRIP; + mPrimitiveCount = count - 2; + break; + case GL_TRIANGLE_FAN: + mPrimitiveType = D3DPT_TRIANGLEFAN; + mPrimitiveCount = count - 2; + break; + default: + UNREACHABLE(); + return false; } return mPrimitiveCount > 0; } - -gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer) +gl::Error Renderer9::getNullColorbuffer(const gl::Context *context, + const gl::FramebufferAttachment *depthbuffer, + const gl::FramebufferAttachment **outColorBuffer) { ASSERT(depthbuffer); @@ -1022,25 +1171,28 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu // search cached nullcolorbuffers for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) { - if (mNullColorbufferCache[i].buffer != NULL && + if (mNullColorbufferCache[i].buffer != nullptr && mNullColorbufferCache[i].width == size.width && mNullColorbufferCache[i].height == size.height) { mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; - *outColorBuffer = mNullColorbufferCache[i].buffer; - return gl::Error(GL_NO_ERROR); + *outColorBuffer = mNullColorbufferCache[i].buffer; + return gl::NoError(); } } - gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); - gl::Error error = nullRenderbuffer->setStorage(GL_NONE, size.width, size.height); + auto *implFactory = context->getImplementation(); + + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(implFactory->createRenderbuffer(), 0); + gl::Error error = nullRenderbuffer->setStorage(context, GL_NONE, size.width, size.height); if (error.isError()) { SafeDelete(nullRenderbuffer); return error; } - gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment(GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer); + gl::FramebufferAttachment *nullbuffer = new gl::FramebufferAttachment( + context, GL_RENDERBUFFER, GL_NONE, gl::ImageIndex::MakeInvalid(), nullRenderbuffer); // add nullbuffer to the cache NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; @@ -1053,46 +1205,38 @@ gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbu } delete oldest->buffer; - oldest->buffer = nullbuffer; + oldest->buffer = nullbuffer; oldest->lruCount = ++mMaxNullColorbufferLRU; oldest->width = size.width; oldest->height = size.height; *outColorBuffer = nullbuffer; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAttachment, +gl::Error Renderer9::applyRenderTarget(const gl::Context *context, + 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 (renderAttachment == nullptr) { - error = getNullColorbuffer(depthStencilAttachment, &renderAttachment); - if (error.isError()) - { - return error; - } + ANGLE_TRY(getNullColorbuffer(context, depthStencilAttachment, &renderAttachment)); } ASSERT(renderAttachment != nullptr); - size_t renderTargetWidth = 0; - size_t renderTargetHeight = 0; + size_t renderTargetWidth = 0; + size_t renderTargetHeight = 0; D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN; RenderTarget9 *renderTarget = nullptr; - error = renderAttachment->getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(renderAttachment->getRenderTarget(context, &renderTarget)); ASSERT(renderTarget); - bool renderTargetChanged = false; + bool renderTargetChanged = false; unsigned int renderTargetSerial = renderTarget->getSerial(); if (renderTargetSerial != mAppliedRenderTargetSerial) { @@ -1103,24 +1247,20 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mDevice->SetRenderTarget(0, renderTargetSurface); SafeRelease(renderTargetSurface); - renderTargetWidth = renderTarget->getWidth(); + renderTargetWidth = renderTarget->getWidth(); renderTargetHeight = renderTarget->getHeight(); renderTargetFormat = renderTarget->getD3DFormat(); mAppliedRenderTargetSerial = renderTargetSerial; - renderTargetChanged = true; + renderTargetChanged = true; } RenderTarget9 *depthStencilRenderTarget = nullptr; - unsigned int depthStencilSerial = 0; + unsigned int depthStencilSerial = 0; if (depthStencilAttachment != nullptr) { - error = depthStencilAttachment->getRenderTarget(&depthStencilRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(depthStencilAttachment->getRenderTarget(context, &depthStencilRenderTarget)); ASSERT(depthStencilRenderTarget); depthStencilSerial = depthStencilRenderTarget->getSerial(); @@ -1128,7 +1268,7 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized) { - unsigned int depthSize = 0; + unsigned int depthSize = 0; unsigned int stencilSize = 0; // Apply the depth stencil on the device @@ -1140,19 +1280,19 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mDevice->SetDepthStencilSurface(depthStencilSurface); SafeRelease(depthStencilSurface); - depthSize = depthStencilAttachment->getDepthSize(); + depthSize = depthStencilAttachment->getDepthSize(); stencilSize = depthStencilAttachment->getStencilSize(); } else { - mDevice->SetDepthStencilSurface(NULL); + mDevice->SetDepthStencilSurface(nullptr); } mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize); mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize); mAppliedDepthStencilSerial = depthStencilSerial; - mDepthStencilInitialized = true; + mDepthStencilInitialized = true; } if (renderTargetChanged || !mRenderTargetDescInitialized) @@ -1163,83 +1303,84 @@ gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorAtt mRenderTargetDescInitialized = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) +gl::Error Renderer9::applyRenderTarget(const gl::Context *context, + const gl::Framebuffer *framebuffer) { - return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer()); + return applyRenderTarget(context, framebuffer->getColorbuffer(0), + framebuffer->getDepthOrStencilbuffer()); } -gl::Error Renderer9::applyVertexBuffer(const gl::State &state, +gl::Error Renderer9::applyVertexBuffer(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei instances, TranslatedIndexData * /*indexInfo*/) { - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, &mTranslatedAttribCache, instances); + const gl::State &state = context->getGLState(); + gl::Error error = mVertexDataManager->prepareVertexData(context, first, count, + &mTranslatedAttribCache, instances); if (error.isError()) { return error; } - return mVertexDeclarationCache.applyDeclaration(mDevice, mTranslatedAttribCache, state.getProgram(), instances, &mRepeatDraw); + return mVertexDeclarationCache.applyDeclaration( + mDevice, mTranslatedAttribCache, state.getProgram(), first, instances, &mRepeatDraw); } // Applies the indices and element array bindings to the Direct3D 9 device -gl::Error Renderer9::applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, +gl::Error Renderer9::applyIndexBuffer(const gl::Context *context, + const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) { - gl::VertexArray *vao = data.state->getVertexArray(); + gl::VertexArray *vao = context->getGLState().getVertexArray(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, - indexInfo, false); - if (error.isError()) - { - return error; - } + const auto &lazyIndexRange = context->getParams(); + + GLenum dstType = GetIndexTranslationDestType(type, lazyIndexRange, false); + + ANGLE_TRY(mIndexDataManager->prepareIndexData(context, type, dstType, count, elementArrayBuffer, + indices, indexInfo)); // Directly binding the storage buffer is not supported for d3d9 - ASSERT(indexInfo->storage == NULL); + ASSERT(indexInfo->storage == nullptr); if (indexInfo->serial != mAppliedIBSerial) { - IndexBuffer9* indexBuffer = GetAs(indexInfo->indexBuffer); + IndexBuffer9 *indexBuffer = GetAs(indexInfo->indexBuffer); mDevice->SetIndices(indexBuffer->getBuffer()); mAppliedIBSerial = indexInfo->serial; } - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) -{ - ASSERT(!state.isTransformFeedbackActiveUnpaused()); + return gl::NoError(); } -gl::Error Renderer9::drawArraysImpl(const gl::Data &data, +gl::Error Renderer9::drawArraysImpl(const gl::Context *context, GLenum mode, + GLint startVertex, GLsizei count, GLsizei instances) { - ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + ASSERT(!context->getGLState().isTransformFeedbackActiveUnpaused()); startScene(); if (mode == GL_LINE_LOOP) { - return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + return drawLineLoop(context, count, GL_NONE, nullptr, 0, nullptr); } else if (instances > 0) { - StaticIndexBufferInterface *countingIB = NULL; - gl::Error error = getCountingIB(count, &countingIB); + StaticIndexBufferInterface *countingIB = nullptr; + gl::Error error = getCountingIB(count, &countingIB); if (error.isError()) { return error; @@ -1258,60 +1399,73 @@ gl::Error Renderer9::drawArraysImpl(const gl::Data &data, mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - else // Regular case + else // Regular case { mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error Renderer9::drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, +gl::Error Renderer9::drawElementsImpl(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, - GLsizei /*instances*/) + const void *indices, + GLsizei instances) { + TranslatedIndexData indexInfo; + + ANGLE_TRY(applyIndexBuffer(context, indices, count, mode, type, &indexInfo)); + + const auto &lazyIndexRange = context->getParams(); + const gl::IndexRange &indexRange = lazyIndexRange.getIndexRange().value(); + size_t vertexCount = indexRange.vertexCount(); + ANGLE_TRY(applyVertexBuffer(context, mode, static_cast(indexRange.start), + static_cast(vertexCount), instances, &indexInfo)); + startScene(); - int minIndex = static_cast(indexInfo.indexRange.start); + int minIndex = static_cast(indexRange.start); - gl::VertexArray *vao = data.state->getVertexArray(); + gl::VertexArray *vao = context->getGLState().getVertexArray(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); if (mode == GL_POINTS) { - return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); + return drawIndexedPoints(context, count, type, indices, minIndex, elementArrayBuffer); } else if (mode == GL_LINE_LOOP) { - return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + return drawLineLoop(context, count, type, indices, minIndex, elementArrayBuffer); } else { - size_t vertexCount = indexInfo.indexRange.vertexCount(); for (int i = 0; i < mRepeatDraw; i++) { mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, static_cast(vertexCount), indexInfo.startIndex, mPrimitiveCount); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } -gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +gl::Error Renderer9::drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer) { // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { - BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + const uint8_t *bufferData = nullptr; + gl::Error error = storage->getData(context, &bufferData); if (error.isError()) { return error; @@ -1321,12 +1475,13 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi unsigned int startIndex = 0; - if (getRendererExtensions().elementIndexUint) + if (getNativeExtensions().elementIndexUint) { if (!mLineLoopIB) { mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); if (error.isError()) { SafeDelete(mLineLoopIB); @@ -1337,60 +1492,64 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi // Checked by Renderer9::applyPrimitiveType ASSERT(count >= 0); - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + if (static_cast(count) + 1 > + (std::numeric_limits::max() / sizeof(unsigned int))) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + return gl::OutOfMemory() << "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); + const unsigned int spaceNeeded = + (static_cast(count) + 1) * sizeof(unsigned int); gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); if (error.isError()) { return error; } - void* mappedMemory = NULL; + void *mappedMemory = nullptr; unsigned int offset = 0; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); if (error.isError()) { return error; } - startIndex = static_cast(offset) / 4; - unsigned int *data = reinterpret_cast(mappedMemory); + startIndex = static_cast(offset) / 4; + unsigned int *data = reinterpret_cast(mappedMemory); 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(); + 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->unmapBuffer(); @@ -1404,7 +1563,8 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi if (!mLineLoopIB) { mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + gl::Error error = + mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); if (error.isError()) { SafeDelete(mLineLoopIB); @@ -1415,19 +1575,22 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi // Checked by Renderer9::applyPrimitiveType ASSERT(count >= 0); - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned short))) + if (static_cast(count) + 1 > + (std::numeric_limits::max() / sizeof(unsigned short))) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + return gl::OutOfMemory() << "Failed to create a 16-bit looping index buffer for " + "GL_LINE_LOOP, too many indices required."; } - const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned short); + const unsigned int spaceNeeded = + (static_cast(count) + 1) * sizeof(unsigned short); gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); if (error.isError()) { return error; } - void* mappedMemory = NULL; + void *mappedMemory = nullptr; unsigned int offset; error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); if (error.isError()) @@ -1435,40 +1598,41 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi return error; } - startIndex = static_cast(offset) / 2; - unsigned short *data = reinterpret_cast(mappedMemory); + startIndex = static_cast(offset) / 2; + unsigned short *data = reinterpret_cast(mappedMemory); switch (type) { - case GL_NONE: // Non-indexed draw - for (int i = 0; i < count; i++) - { - data[i] = static_cast(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(static_cast(indices)[i]); - } - data[count] = static_cast(static_cast(indices)[0]); - break; - default: UNREACHABLE(); + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = static_cast(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(static_cast(indices)[i]); + } + data[count] = static_cast(static_cast(indices)[0]); + break; + default: + UNREACHABLE(); } error = mLineLoopIB->unmapBuffer(); @@ -1488,22 +1652,31 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } template -static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) +static gl::Error drawPoints(IDirect3DDevice9 *device, + GLsizei count, + const void *indices, + int minIndex) { for (int i = 0; i < count; i++) { - unsigned int indexValue = static_cast(static_cast(indices)[i]) - minIndex; + unsigned int indexValue = + static_cast(static_cast(indices)[i]) - minIndex; device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +gl::Error Renderer9::drawIndexedPoints(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer) { // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call // for each individual point. This call is not expected to happen often. @@ -1511,10 +1684,10 @@ gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid if (elementArrayBuffer) { BufferD3D *storage = GetImplAs(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); + intptr_t offset = reinterpret_cast(indices); - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); + const uint8_t *bufferData = nullptr; + gl::Error error = storage->getData(context, &bufferData); if (error.isError()) { return error; @@ -1525,17 +1698,22 @@ gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid switch (type) { - case GL_UNSIGNED_BYTE: return drawPoints(mDevice, count, indices, minIndex); - case GL_UNSIGNED_SHORT: return drawPoints(mDevice, count, indices, minIndex); - case GL_UNSIGNED_INT: return drawPoints(mDevice, count, indices, minIndex); - default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); + case GL_UNSIGNED_BYTE: + return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_SHORT: + return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_INT: + return drawPoints(mDevice, count, indices, minIndex); + default: + UNREACHABLE(); + return gl::InternalError(); } } gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB) { // Update the counting index buffer if it is not large enough or has not been created yet. - if (count <= 65536) // 16-bit indices + if (count <= 65536) // 16-bit indices { const unsigned int spaceNeeded = static_cast(count) * sizeof(unsigned short); @@ -1543,29 +1721,21 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou { SafeDelete(mCountingIB); mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + ANGLE_TRY(mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT)); - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, nullptr)); - unsigned short *data = reinterpret_cast(mappedMemory); + unsigned short *data = reinterpret_cast(mappedMemory); for (size_t i = 0; i < count; i++) { data[i] = static_cast(i); } - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCountingIB->unmapBuffer()); } } - else if (getRendererExtensions().elementIndexUint) + else if (getNativeExtensions().elementIndexUint) { const unsigned int spaceNeeded = static_cast(count) * sizeof(unsigned int); @@ -1573,59 +1743,53 @@ gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **ou { SafeDelete(mCountingIB); mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + ANGLE_TRY(mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)); - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } + void *mappedMemory = nullptr; + ANGLE_TRY(mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, nullptr)); - unsigned int *data = reinterpret_cast(mappedMemory); + unsigned int *data = reinterpret_cast(mappedMemory); for (unsigned int i = 0; i < count; i++) { data[i] = i; } - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mCountingIB->unmapBuffer()); } } else { - return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); + return gl::OutOfMemory() + << "Could not create a counting index buffer for glDrawArraysInstanced."; } *outIB = mCountingIB; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Renderer9::applyShadersImpl(const gl::Data &data, GLenum /*drawMode*/) +gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode) { - ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); - const auto &inputLayout = programD3D->getCachedInputLayout(); + const gl::State &state = context->getContextState().getState(); + // This method is called single-threaded. + ANGLE_TRY(ensureHLSLCompilerInitialized()); - ShaderExecutableD3D *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); - if (error.isError()) - { - return error; - } + ProgramD3D *programD3D = GetImplAs(state.getProgram()); + VertexArray9 *vao = GetImplAs(state.getVertexArray()); + programD3D->updateCachedInputLayout(vao->getCurrentStateSerial(), state); - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - ShaderExecutableD3D *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(drawFramebuffer, &pixelExe); - if (error.isError()) - { - return error; - } + ShaderExecutableD3D *vertexExe = nullptr; + ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr)); + + const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer(); + programD3D->updateCachedOutputLayout(context, drawFramebuffer); + + ShaderExecutableD3D *pixelExe = nullptr; + ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr)); - IDirect3DVertexShader9 *vertexShader = (vertexExe ? GetAs(vertexExe)->getVertexShader() : nullptr); - IDirect3DPixelShader9 *pixelShader = (pixelExe ? GetAs(pixelExe)->getPixelShader() : nullptr); + IDirect3DVertexShader9 *vertexShader = + (vertexExe ? GetAs(vertexExe)->getVertexShader() : nullptr); + IDirect3DPixelShader9 *pixelShader = + (pixelExe ? GetAs(pixelExe)->getPixelShader() : nullptr); if (vertexShader != mAppliedVertexShader) { @@ -1652,25 +1816,39 @@ gl::Error Renderer9::applyShadersImpl(const gl::Data &data, GLenum /*drawMode*/) mAppliedProgramSerial = programSerial; } - return gl::Error(GL_NO_ERROR); + ANGLE_TRY(applyUniforms(programD3D)); + + // Driver uniforms + mStateManager.setShaderConstants(); + + return gl::NoError(); } -gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, - GLenum /*drawMode*/, - const std::vector &uniformArray) +gl::Error Renderer9::applyUniforms(ProgramD3D *programD3D) { + // Skip updates if we're not dirty. Note that D3D9 cannot have compute. + if (!programD3D->areVertexUniformsDirty() && !programD3D->areFragmentUniformsDirty()) + { + return gl::NoError(); + } + + const auto &uniformArray = programD3D->getD3DUniforms(); + for (const D3DUniform *targetUniform : uniformArray) { - if (!targetUniform->dirty) + // Built-in uniforms must be skipped. + if (!targetUniform->isReferencedByFragmentShader() && + !targetUniform->isReferencedByVertexShader()) continue; - GLfloat *f = (GLfloat *)targetUniform->data; - GLint *i = (GLint *)targetUniform->data; + const GLfloat *f = reinterpret_cast(targetUniform->firstNonNullData()); + const GLint *i = reinterpret_cast(targetUniform->firstNonNullData()); - switch (targetUniform->type) + switch (targetUniform->typeInfo.type) { case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: + case GL_SAMPLER_EXTERNAL_OES: break; case GL_BOOL: case GL_BOOL_VEC2: @@ -1698,22 +1876,22 @@ gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, } } - // Driver uniforms - mStateManager.setShaderConstants(); - - return gl::Error(GL_NO_ERROR); + programD3D->markUniformsClean(); + return gl::NoError(); } void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v) { if (targetUniform->isReferencedByFragmentShader()) { - mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); + mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, + targetUniform->registerCount); } if (targetUniform->isReferencedByVertexShader()) { - mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); + mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, + targetUniform->registerCount); } } @@ -1730,7 +1908,7 @@ void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v) vector[i][3] = (GLfloat)v[4 * i + 3]; } - applyUniformnfv(targetUniform, (GLfloat*)vector); + applyUniformnfv(targetUniform, (GLfloat *)vector); } void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v) @@ -1746,18 +1924,19 @@ void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v) vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; } - applyUniformnfv(targetUniform, (GLfloat*)vector); + applyUniformnfv(targetUniform, (GLfloat *)vector); } -gl::Error Renderer9::clear(const ClearParameters &clearParams, +gl::Error Renderer9::clear(const gl::Context *context, + const ClearParameters &clearParams, const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer) { - if (clearParams.colorClearType != GL_FLOAT) + if (clearParams.colorType != GL_FLOAT) { // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } bool clearColor = clearParams.clearColor[0]; @@ -1765,14 +1944,15 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, { if (clearParams.clearColor[i] != clearColor) { - // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and + // ES 2.0 UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } } - float depth = gl::clamp01(clearParams.depthClearValue); - DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + float depth = gl::clamp01(clearParams.depthValue); + DWORD stencil = clearParams.stencilValue & 0x000000FF; unsigned int stencilUnmasked = 0x0; if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0) @@ -1780,7 +1960,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, ASSERT(depthStencilBuffer != nullptr); RenderTargetD3D *stencilRenderTarget = nullptr; - gl::Error error = depthStencilBuffer->getRenderTarget(&stencilRenderTarget); + gl::Error error = depthStencilBuffer->getRenderTarget(context, &stencilRenderTarget); if (error.isError()) { return error; @@ -1789,21 +1969,23 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, RenderTarget9 *stencilRenderTarget9 = GetAs(stencilRenderTarget); ASSERT(stencilRenderTarget9); - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1; } - const bool needMaskedStencilClear = clearParams.clearStencil && - (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + const bool needMaskedStencilClear = + clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; bool needMaskedColorClear = false; - D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); if (clearColor) { ASSERT(colorBuffer != nullptr); - RenderTargetD3D *colorRenderTarget = NULL; - gl::Error error = colorBuffer->getRenderTarget(&colorRenderTarget); + RenderTargetD3D *colorRenderTarget = nullptr; + gl::Error error = colorBuffer->getRenderTarget(context, &colorRenderTarget); if (error.isError()) { return error; @@ -1812,17 +1994,27 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, RenderTarget9 *colorRenderTarget9 = GetAs(colorRenderTarget); ASSERT(colorRenderTarget9); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(colorBuffer->getInternalFormat()); - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat()); - - color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), - gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), - gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), - gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); - - if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + const gl::InternalFormat &formatInfo = *colorBuffer->getFormat().info; + const d3d9::D3DFormat &d3dFormatInfo = + d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat()); + + color = + D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) + ? 1.0f + : clearParams.colorF.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) + ? 0.0f + : clearParams.colorF.red), + gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) + ? 0.0f + : clearParams.colorF.green), + gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) + ? 0.0f + : clearParams.colorF.blue)); + + if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || - (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) { needMaskedColorClear = true; @@ -1835,7 +2027,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, // State which is altered in only some paths will be flagged dirty in the case that // that path is taken. HRESULT hr; - if (mMaskedClearSavedState == NULL) + if (mMaskedClearSavedState == nullptr) { hr = mDevice->BeginStateBlock(); ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); @@ -1850,10 +2042,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - mDevice->SetPixelShader(NULL); - mDevice->SetVertexShader(NULL); + mDevice->SetPixelShader(nullptr); + mDevice->SetVertexShader(nullptr); mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); - mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetStreamSource(0, nullptr, 0, 0); mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); @@ -1862,7 +2054,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); - for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { mDevice->SetStreamSourceFreq(i, 1); } @@ -1871,9 +2063,9 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); } - ASSERT(mMaskedClearSavedState != NULL); + ASSERT(mMaskedClearSavedState != nullptr); - if (mMaskedClearSavedState != NULL) + if (mMaskedClearSavedState != nullptr) { hr = mMaskedClearSavedState->Capture(); ASSERT(SUCCEEDED(hr)); @@ -1890,11 +2082,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, if (clearColor) { - mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, - gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, - clearParams.colorMaskGreen, - clearParams.colorMaskBlue, - clearParams.colorMaskAlpha)); + mDevice->SetRenderState( + D3DRS_COLORWRITEENABLE, + gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, clearParams.colorMaskGreen, + clearParams.colorMaskBlue, clearParams.colorMaskAlpha)); } else { @@ -1917,8 +2108,8 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); } - mDevice->SetPixelShader(NULL); - mDevice->SetVertexShader(NULL); + mDevice->SetPixelShader(nullptr); + mDevice->SetVertexShader(nullptr); mDevice->SetFVF(D3DFVF_XYZRHW); mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); @@ -1928,7 +2119,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); - for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { mDevice->SetStreamSourceFreq(i, 1); } @@ -1936,7 +2127,7 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, int renderTargetWidth = mStateManager.getRenderTargetWidth(); int renderTargetHeight = mStateManager.getRenderTargetHeight(); - float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges quad[0][0] = -0.5f; quad[0][1] = renderTargetHeight - 0.5f; quad[0][2] = 0.0f; @@ -1964,10 +2155,10 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, { mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + mDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, color, depth, stencil); } - if (mMaskedClearSavedState != NULL) + if (mMaskedClearSavedState != nullptr) { mMaskedClearSavedState->Apply(); } @@ -1988,17 +2179,17 @@ gl::Error Renderer9::clear(const ClearParameters &clearParams, dxClearFlags |= D3DCLEAR_STENCIL; } - mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); + mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void Renderer9::markAllStateDirty() { - mAppliedRenderTargetSerial = 0; - mAppliedDepthStencilSerial = 0; - mDepthStencilInitialized = false; + mAppliedRenderTargetSerial = 0; + mAppliedDepthStencilSerial = 0; + mDepthStencilInitialized = false; mRenderTargetDescInitialized = false; mStateManager.forceSetRasterState(); @@ -2021,9 +2212,9 @@ void Renderer9::markAllStateDirty() mCurPixelTextures[i] = angle::DirtyPointer; } - mAppliedIBSerial = 0; - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; + mAppliedIBSerial = 0; + mAppliedVertexShader = nullptr; + mAppliedPixelShader = nullptr; mAppliedProgramSerial = 0; mStateManager.forceSetDXUniformsState(); @@ -2051,6 +2242,10 @@ void Renderer9::releaseDeviceResources() for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) { + if (mNullColorbufferCache[i].buffer) + { + mNullColorbufferCache[i].buffer->detach(mDisplay->getProxyContext()); + } SafeDelete(mNullColorbufferCache[i].buffer); } } @@ -2059,19 +2254,7 @@ void Renderer9::releaseDeviceResources() bool Renderer9::testDeviceLost() { HRESULT status = getDeviceStatusCode(); - bool isLost = FAILED(status); - - if (isLost) - { - // ensure we note the device loss -- - // we'll probably get this done again by notifyDeviceLost - // but best to remember it! - // Note that we don't want to clear the device loss status here - // -- this needs to be done by resetDevice - mDeviceLost = true; - } - - return isLost; + return FAILED(status); } HRESULT Renderer9::getDeviceStatusCode() @@ -2080,7 +2263,7 @@ HRESULT Renderer9::getDeviceStatusCode() if (mDeviceEx) { - status = mDeviceEx->CheckDeviceState(NULL); + status = mDeviceEx->CheckDeviceState(nullptr); } else if (mDevice) { @@ -2096,16 +2279,16 @@ bool Renderer9::testDeviceResettable() // DEVICEREMOVED indicates the device has been stopped and must be recreated switch (getDeviceStatusCode()) { - case D3DERR_DEVICENOTRESET: - case D3DERR_DEVICEHUNG: - return true; - case D3DERR_DEVICELOST: - return (mDeviceEx != NULL); - case D3DERR_DEVICEREMOVED: - ASSERT(mDeviceEx != NULL); - return isRemovedDeviceResettable(); - default: - return false; + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + case D3DERR_DEVICELOST: + return (mDeviceEx != nullptr); + case D3DERR_DEVICEREMOVED: + ASSERT(mDeviceEx != nullptr); + return isRemovedDeviceResettable(); + default: + return false; } } @@ -2115,12 +2298,12 @@ bool Renderer9::resetDevice() D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - HRESULT result = D3D_OK; - bool lost = testDeviceLost(); + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED); // Device Removed is a feature which is only present with D3D9Ex - ASSERT(mDeviceEx != NULL || !removedDevice); + ASSERT(mDeviceEx != nullptr || !removedDevice); for (int attempts = 3; lost && attempts > 0; attempts--) { @@ -2134,16 +2317,16 @@ bool Renderer9::resetDevice() } else if (mDeviceEx) { - Sleep(500); // Give the graphics driver some CPU time - result = mDeviceEx->ResetEx(&presentParameters, NULL); - lost = testDeviceLost(); + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, nullptr); + lost = testDeviceLost(); } else { result = mDevice->TestCooperativeLevel(); while (result == D3DERR_DEVICELOST) { - Sleep(100); // Give the graphics driver some CPU time + Sleep(100); // Give the graphics driver some CPU time result = mDevice->TestCooperativeLevel(); } @@ -2157,13 +2340,13 @@ bool Renderer9::resetDevice() if (FAILED(result)) { - ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + ERR() << "Reset/ResetEx failed multiple times, " << gl::FmtHR(result); return false; } if (removedDevice && lost) { - ERR("Device lost reset failed multiple times"); + ERR() << "Device lost reset failed multiple times"; return false; } @@ -2171,11 +2354,12 @@ bool Renderer9::resetDevice() if (!removedDevice) { // reset device defaults - initializeDevice(); + if (initializeDevice().isError()) + { + return false; + } } - mDeviceLost = false; - return true; } @@ -2184,15 +2368,16 @@ bool Renderer9::isRemovedDeviceResettable() const bool success = false; #if ANGLE_D3D9EX == ANGLE_ENABLED - IDirect3D9Ex *d3d9Ex = NULL; - typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); - Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + IDirect3D9Ex *d3d9Ex = nullptr; + typedef HRESULT(WINAPI * Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex **); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = + reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex))) { D3DCAPS9 deviceCaps; HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps); - success = SUCCEEDED(result); + success = SUCCEEDED(result); } SafeRelease(d3d9Ex); @@ -2232,20 +2417,22 @@ std::string Renderer9::getRendererDescription() const rendererString << " Direct3D9"; } - rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); - rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); + rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" + << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); + rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" + << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); return rendererString.str(); } DeviceIdentifier Renderer9::getAdapterIdentifier() const { - 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; + 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; } @@ -2260,20 +2447,10 @@ unsigned int Renderer9::getReservedFragmentUniformVectors() const return d3d9_gl::GetReservedFragmentUniformVectors(); } -unsigned int Renderer9::getReservedVertexUniformBuffers() const -{ - return 0; -} - -unsigned int Renderer9::getReservedFragmentUniformBuffers() const -{ - return 0; -} - bool Renderer9::getShareHandleSupport() const { // PIX doesn't seem to support using share handles, so disable them. - return (mD3d9Ex != NULL) && !gl::DebugAnnotationsActive(); + return (mD3d9Ex != nullptr) && !gl::DebugAnnotationsActive(); } int Renderer9::getMajorShaderModel() const @@ -2298,7 +2475,7 @@ DWORD Renderer9::getCapsDeclTypes() const D3DPOOL Renderer9::getBufferPool(DWORD usage) const { - if (mD3d9Ex != NULL) + if (mD3d9Ex != nullptr) { return D3DPOOL_DEFAULT; } @@ -2313,66 +2490,126 @@ D3DPOOL Renderer9::getBufferPool(DWORD usage) const return D3DPOOL_DEFAULT; } -gl::Error Renderer9::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { RECT rect; - rect.left = sourceRect.x; - rect.top = sourceRect.y; - rect.right = sourceRect.x + sourceRect.width; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; rect.bottom = sourceRect.y + sourceRect.height; - return mBlit->copy2D(framebuffer, rect, destFormat, destOffset, storage, level); + return mBlit->copy2D(context, framebuffer, rect, destFormat, destOffset, storage, level); } -gl::Error Renderer9::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +gl::Error Renderer9::copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) { RECT rect; - rect.left = sourceRect.x; - rect.top = sourceRect.y; - rect.right = sourceRect.x + sourceRect.width; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; rect.bottom = sourceRect.y + sourceRect.height; - return mBlit->copyCube(framebuffer, rect, destFormat, destOffset, storage, target, level); + return mBlit->copyCube(context, framebuffer, rect, destFormat, destOffset, storage, target, + level); } -gl::Error Renderer9::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { // 3D textures are not available in the D3D9 backend. UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error Renderer9::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) { // 2D array textures are not available in the D3D9 backend. UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); +} + +gl::Error Renderer9::copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copyTexture(context, source, sourceLevel, rect, destFormat, destOffset, storage, + destTarget, destLevel, unpackFlipY, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha); } -gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +gl::Error Renderer9::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) +{ + UNIMPLEMENTED(); + return gl::InternalError(); +} + +gl::Error Renderer9::createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) { const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); - const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); + const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); IDirect3DTexture9 *texture = nullptr; - IDirect3DSurface9 *renderTarget = NULL; + IDirect3DSurface9 *renderTarget = nullptr; if (width > 0 && height > 0) { bool requiresInitialization = false; - HRESULT result = D3DERR_INVALIDCALL; + HRESULT result = D3DERR_INVALIDCALL; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) { - result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &renderTarget, NULL); + result = mDevice->CreateDepthStencilSurface( + width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &renderTarget, nullptr); } else { @@ -2398,25 +2635,25 @@ gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GL if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create render target, " << gl::FmtHR(result); } if (requiresInitialization) { - // This format requires that the data be initialized before the render target can be used - // Unfortunately this requires a Get call on the d3d device but it is far better than having - // to mark the render target as lockable and copy data to the gpu. - IDirect3DSurface9 *prevRenderTarget = NULL; + // This format requires that the data be initialized before the render target can be + // used Unfortunately this requires a Get call on the d3d device but it is far better + // than having to mark the render target as lockable and copy data to the gpu. + IDirect3DSurface9 *prevRenderTarget = nullptr; mDevice->GetRenderTarget(0, &prevRenderTarget); mDevice->SetRenderTarget(0, renderTarget); - mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); mDevice->SetRenderTarget(0, prevRenderTarget); } } *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1, supportedSamples); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) @@ -2424,7 +2661,7 @@ gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTarge ASSERT(source != nullptr); RenderTargetD3D *newRT = nullptr; - gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), + gl::Error error = createRenderTarget(source->getWidth(), source->getHeight(), source->getInternalFormat(), source->getSamples(), &newRT); if (error.isError()) { @@ -2439,31 +2676,16 @@ gl::Error Renderer9::createRenderTargetCopy(RenderTargetD3D *source, RenderTarge 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); + return gl::OutOfMemory() << "Failed to copy render target, " << gl::FmtHR(result); } *outRT = newRT; - return gl::Error(GL_NO_ERROR); -} - -FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data) -{ - return new Framebuffer9(data, this); -} - -ShaderImpl *Renderer9::createShader(const gl::Shader::Data &data) -{ - return new ShaderD3D(data); + return gl::NoError(); } -ProgramImpl *Renderer9::createProgram(const gl::Program::Data &data) -{ - return new ProgramD3D(data, this); -} - -gl::Error Renderer9::loadExecutable(const void *function, +gl::Error Renderer9::loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) @@ -2473,10 +2695,10 @@ gl::Error Renderer9::loadExecutable(const void *function, switch (type) { - case SHADER_VERTEX: + case gl::SHADER_VERTEX: { - IDirect3DVertexShader9 *vshader = NULL; - gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + IDirect3DVertexShader9 *vshader = nullptr; + gl::Error error = createVertexShader((DWORD *)function, length, &vshader); if (error.isError()) { return error; @@ -2484,10 +2706,10 @@ gl::Error Renderer9::loadExecutable(const void *function, *outExecutable = new ShaderExecutable9(function, length, vshader); } break; - case SHADER_PIXEL: + case gl::SHADER_FRAGMENT: { - IDirect3DPixelShader9 *pshader = NULL; - gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + IDirect3DPixelShader9 *pshader = nullptr; + gl::Error error = createPixelShader((DWORD *)function, length, &pshader); if (error.isError()) { return error; @@ -2495,41 +2717,45 @@ gl::Error Renderer9::loadExecutable(const void *function, *outExecutable = new ShaderExecutable9(function, length, pshader); } break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + default: + UNREACHABLE(); + return gl::InternalError(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(streamOutVaryings.empty()); - const char *profileType = NULL; + std::stringstream profileStream; + switch (type) { - case SHADER_VERTEX: - profileType = "vs"; - break; - case SHADER_PIXEL: - profileType = "ps"; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + case gl::SHADER_VERTEX: + profileStream << "vs"; + break; + case gl::SHADER_FRAGMENT: + profileStream << "ps"; + break; + default: + UNREACHABLE(); + return gl::InternalError(); } - unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; - unsigned int profileMinorVersion = 0; - std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); + + profileStream << "_" << ((getMajorShaderModel() >= 3) ? 3 : 2); + profileStream << "_" + << "0"; + + std::string profile = profileStream.str(); UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; @@ -2551,31 +2777,35 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, flags |= D3DCOMPILE_DEBUG; } - // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. - // Try the default flags first and if compilation fails, try some alternatives. + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders + // when it would otherwise pass with alternative options. Try the default flags first and if + // compilation fails, try some alternatives. std::vector configs; - configs.push_back(CompileConfig(flags, "default" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); + configs.push_back(CompileConfig(flags, "default")); + configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control")); configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); - ID3DBlob *binary = NULL; + ID3DBlob *binary = nullptr; std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, nullptr, + &binary, &debugInfo); if (error.isError()) { return error; } - // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL - // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + // It's possible that binary is NULL if the compiler failed in all configurations. Set the + // executable to NULL and return GL_NO_ERROR to signify that there was a link error but the + // internal state is still OK. if (!binary) { - *outExectuable = NULL; - return gl::Error(GL_NO_ERROR); + *outExectuable = nullptr; + return gl::NoError(); } - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - streamOutVaryings, separatedOutputBuffers, outExectuable); + error = loadExecutable(reinterpret_cast(binary->GetBufferPointer()), + binary->GetBufferSize(), type, streamOutVaryings, separatedOutputBuffers, + outExectuable); SafeRelease(binary); if (error.isError()) @@ -2588,7 +2818,12 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, (*outExectuable)->appendDebugInfo(debugInfo); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer9::ensureHLSLCompilerInitialized() +{ + return mCompiler.ensureInitialized(); } UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize) @@ -2603,7 +2838,7 @@ gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *des D3DPOOL Renderer9::getTexturePool(DWORD usage) const { - if (mD3d9Ex != NULL) + if (mD3d9Ex != nullptr) { return D3DPOOL_DEFAULT; } @@ -2618,7 +2853,9 @@ D3DPOOL Renderer9::getTexturePool(DWORD usage) const return D3DPOOL_DEFAULT; } -gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged) { ASSERT(source && dest); @@ -2630,28 +2867,34 @@ gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurfac source->GetDesc(&desc); IDirect3DSurface9 *surf = 0; - result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &surf, nullptr); if (SUCCEEDED(result)) { - Image9::copyLockableSurfaces(surf, source); - result = mDevice->UpdateSurface(surf, NULL, dest, NULL); + ANGLE_TRY(Image9::copyLockableSurfaces(surf, source)); + result = mDevice->UpdateSurface(surf, nullptr, dest, nullptr); SafeRelease(surf); } } else { endScene(); - result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + result = mDevice->StretchRect(source, nullptr, dest, nullptr, D3DTEXF_NONE); } if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to blit internal texture, " << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +RendererClass Renderer9::getRendererClass() const +{ + return RENDERER_D3D9; } ImageD3D *Renderer9::createImage() @@ -2659,18 +2902,34 @@ ImageD3D *Renderer9::createImage() return new Image9(this); } -gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src) +gl::Error Renderer9::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src) { Image9 *src9 = GetAs(src); Image9 *dst9 = GetAs(dest); return Image9::generateMipmap(dst9, src9); } -gl::Error Renderer9::generateMipmapsUsingD3D(TextureStorage *storage, - const gl::TextureState &textureState) +gl::Error Renderer9::generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) { UNREACHABLE(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error Renderer9::copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + Image9 *dest9 = GetAs(dest); + Image9 *src9 = GetAs(source); + return Image9::CopyImage(context, dest9, src9, sourceRect, destOffset, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha); } TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) @@ -2679,59 +2938,83 @@ TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) return new TextureStorage9_2D(this, swapChain9); } -TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage) +TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) +{ + return new TextureStorage9_EGLImage(this, eglImage, GetAs(renderTargetD3D)); +} + +TextureStorage *Renderer9::createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - return new TextureStorage9_EGLImage(this, eglImage); + UNIMPLEMENTED(); + return nullptr; } -TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +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); } -TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) { - return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, + hintLevelZeroOnly); } -TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { // 3D textures are not supported by the D3D9 backend. UNREACHABLE(); - return NULL; + return nullptr; } -TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) { // 2D array textures are not supported by the D3D9 backend. UNREACHABLE(); - return NULL; + return nullptr; } -TextureImpl *Renderer9::createTexture(GLenum target) +TextureStorage *Renderer9::createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) { - switch(target) - { - case GL_TEXTURE_2D: return new TextureD3D_2D(this); - case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); - default: UNREACHABLE(); - } + // 2D multisampled textures are not supported by the D3D9 backend. + UNREACHABLE(); return NULL; } -RenderbufferImpl *Renderer9::createRenderbuffer() -{ - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - return renderbuffer; -} - bool Renderer9::getLUID(LUID *adapterLuid) const { adapterLuid->HighPart = 0; - adapterLuid->LowPart = 0; + adapterLuid->LowPart = 0; if (mD3d9Ex) { @@ -2752,6 +3035,40 @@ GLenum Renderer9::getVertexComponentType(gl::VertexFormatType vertexFormatType) return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType).componentType; } +gl::ErrorOrResult Renderer9::getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const +{ + if (!attrib.enabled) + { + return 16u; + } + + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = + d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatType); + + unsigned int elementCount = 0; + const unsigned int divisor = binding.getDivisor(); + if (instances == 0 || divisor == 0) + { + elementCount = static_cast(count); + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), divisor); + } + + if (d3d9VertexInfo.outputElementSize > std::numeric_limits::max() / elementCount) + { + return gl::OutOfMemory() << "New vertex buffer size would result in an overflow."; + } + + return static_cast(d3d9VertexInfo.outputElementSize) * elementCount; +} + void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, @@ -2761,31 +3078,11 @@ void Renderer9::generateCaps(gl::Caps *outCaps, outExtensions, outLimitations); } -WorkaroundsD3D Renderer9::generateWorkarounds() const +angle::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) @@ -2803,14 +3100,211 @@ egl::Error Renderer9::getEGLDevice(DeviceImpl **device) } *device = static_cast(mEGLDevice); - return egl::Error(EGL_SUCCESS); + return egl::NoError(); } Renderer9::CurSamplerState::CurSamplerState() - : forceSet(true), - baseLevel(std::numeric_limits::max()), - samplerState() + : forceSet(true), baseLevel(std::numeric_limits::max()), samplerState() +{ +} + +gl::Error Renderer9::genericDrawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances) +{ + const auto &data = context->getContextState(); + gl::Program *program = context->getGLState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return gl::NoError(); + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(data.getState(), mode)) + { + ANGLE_TRY(drawElementsImpl(context, mode, count, type, indices, instances)); + } + + return gl::NoError(); +} + +gl::Error Renderer9::genericDrawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances) +{ + gl::Program *program = context->getGLState().getProgram(); + ASSERT(program != nullptr); + ProgramD3D *programD3D = GetImplAs(program); + bool usesPointSize = programD3D->usesPointSize(); + + programD3D->updateSamplerMapping(); + + if (!applyPrimitiveType(mode, count, usesPointSize)) + { + return gl::NoError(); + } + + ANGLE_TRY(updateState(context, mode)); + ANGLE_TRY(applyVertexBuffer(context, mode, first, count, instances, nullptr)); + ANGLE_TRY(applyTextures(context)); + ANGLE_TRY(applyShaders(context, mode)); + + if (!skipDraw(context->getGLState(), mode)) + { + ANGLE_TRY(drawArraysImpl(context, mode, first, count, instances)); + } + + return gl::NoError(); +} + +FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::FramebufferState &state) { + return new Framebuffer9(state, this); } +gl::Version Renderer9::getMaxSupportedESVersion() const +{ + return gl::Version(2, 0); +} + +gl::Error Renderer9::clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) +{ + D3DCOLOR color = + D3DCOLOR_ARGB(gl::unorm<8>(clearColorValue.alpha), gl::unorm<8>(clearColorValue.red), + gl::unorm<8>(clearColorValue.green), gl::unorm<8>(clearColorValue.blue)); + float depth = clearDepthValue; + DWORD stencil = clearStencilValue & 0x000000FF; + + unsigned int renderTargetSerial = renderTarget->getSerial(); + RenderTarget9 *renderTarget9 = GetAs(renderTarget); + IDirect3DSurface9 *renderTargetSurface = renderTarget9->getSurface(); + ASSERT(renderTargetSurface); + + DWORD dxClearFlags = 0; + + const gl::InternalFormat &internalFormatInfo = + gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat()); + if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0) + { + dxClearFlags = D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL; + if (mAppliedDepthStencilSerial != renderTargetSerial) + { + mDevice->SetDepthStencilSurface(renderTargetSurface); + } + } + else + { + dxClearFlags = D3DCLEAR_TARGET; + if (mAppliedRenderTargetSerial != renderTargetSerial) + { + mDevice->SetRenderTarget(0, renderTargetSurface); + } + } + SafeRelease(renderTargetSurface); + + D3DVIEWPORT9 viewport; + viewport.X = 0; + viewport.Y = 0; + viewport.Width = renderTarget->getWidth(); + viewport.Height = renderTarget->getHeight(); + mDevice->SetViewport(&viewport); + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil); + + markAllStateDirty(); + + return gl::NoError(); } + +bool Renderer9::canSelectViewInVertexShader() const +{ + return false; +} + +// 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 Renderer9::applyTextures(const gl::Context *context, gl::SamplerType shaderType) +{ + const auto &glState = context->getGLState(); + const auto &caps = context->getCaps(); + ProgramD3D *programD3D = GetImplAs(glState.getProgram()); + + ASSERT(!programD3D->isSamplerMappingDirty()); + + // TODO(jmadill): Use the Program's sampler bindings. + const auto &completeTextures = glState.getCompleteTextureCache(); + + unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); + for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); + ASSERT(textureUnit != -1); + gl::Texture *texture = completeTextures[textureUnit]; + + // A nullptr texture indicates incomplete. + if (texture) + { + gl::Sampler *samplerObject = glState.getSampler(textureUnit); + + const gl::SamplerState &samplerState = + samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); + + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState)); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); + } + else + { + GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); + + // Texture is not sampler complete or it is in use by the framebuffer. Bind the + // incomplete texture. + gl::Texture *incompleteTexture = nullptr; + ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture)); + ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, + incompleteTexture->getSamplerState())); + ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits + : caps.maxVertexTextureImageUnits; + + // TODO(jmadill): faster way? + for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + ANGLE_TRY(setTexture(context, shaderType, static_cast(samplerIndex), nullptr)); + } + + return gl::NoError(); +} + +gl::Error Renderer9::applyTextures(const gl::Context *context) +{ + ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX)); + ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL)); + return gl::NoError(); +} + +} // namespace rx 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 a0dfecb02e..9ddee45f0f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h @@ -12,12 +12,13 @@ #include "common/angleutils.h" #include "common/mathutil.h" #include "libANGLE/renderer/d3d/HLSLCompiler.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #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" +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libANGLE/renderer/driver_utils.h" namespace gl { @@ -32,6 +33,7 @@ class AttributeMap; namespace rx { class Blit9; +class Context9; class IndexDataManager; class ProgramD3D; class StreamingIndexBufferInterface; @@ -65,184 +67,270 @@ class Renderer9 : public RendererD3D { public: explicit Renderer9(egl::Display *display); - virtual ~Renderer9(); + ~Renderer9() override; egl::Error initialize() override; - virtual bool resetDevice(); + bool resetDevice() override; - egl::ConfigSet generateConfigs() const override; + egl::ConfigSet generateConfigs() override; void generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const override; void startScene(); void endScene(); - gl::Error flush() override; - gl::Error finish() override; + gl::Error flush(); + gl::Error finish(); - SwapChainD3D *createSwapChain(NativeWindow nativeWindow, + bool isValidNativeWindow(EGLNativeWindowType window) const override; + NativeWindowD3D *createNativeWindow(EGLNativeWindowType window, + const egl::Config *config, + const egl::AttributeMap &attribs) const override; + + SwapChainD3D *createSwapChain(NativeWindowD3D *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, - EGLint orientation) override; - - CompilerImpl *createCompiler() override; + EGLint orientation, + EGLint samples) override; + egl::Error getD3DTextureInfo(const egl::Config *configuration, + IUnknown *d3dTexture, + EGLint *width, + EGLint *height, + GLenum *fboFormat) const override; + egl::Error validateShareHandle(const egl::Config *config, + HANDLE shareHandle, + const egl::AttributeMap &attribs) const override; + + ContextImpl *createContext(const gl::ContextState &state) override; gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); - void freeEventQuery(IDirect3DQuery9* query); + void freeEventQuery(IDirect3DQuery9 *query); // resource creation - gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); - gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); + gl::Error createVertexShader(const DWORD *function, + size_t length, + IDirect3DVertexShader9 **outShader); + gl::Error createPixelShader(const DWORD *function, + size_t length, + IDirect3DPixelShader9 **outShader); HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); - HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); - 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 std::vector &vertexUniformBuffers, - const std::vector &fragmentUniformBuffers) override; - - gl::Error updateState(const gl::Data &data, GLenum drawMode) override; + HRESULT createIndexBuffer(UINT Length, + DWORD Usage, + D3DFORMAT Format, + IDirect3DIndexBuffer9 **ppIndexBuffer); + gl::Error setSamplerState(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture, + const gl::SamplerState &sampler); + gl::Error setTexture(const gl::Context *context, + gl::SamplerType type, + int index, + gl::Texture *texture); + + gl::Error updateState(const gl::Context *context, GLenum drawMode); void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); - void setViewport(const gl::Caps *caps, - const gl::Rectangle &viewport, + void setViewport(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 *colorAttachment, + gl::Error applyRenderTarget(const gl::Context *context, const gl::Framebuffer *frameBuffer); + gl::Error applyRenderTarget(const gl::Context *context, + 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, - TranslatedIndexData *indexInfo); - gl::Error applyIndexBuffer(const gl::Data &data, - const GLvoid *indices, + gl::Error applyUniforms(ProgramD3D *programD3D); + bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize); + gl::Error applyVertexBuffer(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances, + TranslatedIndexData *indexInfo); + gl::Error applyIndexBuffer(const gl::Context *context, + const void *indices, GLsizei count, GLenum mode, GLenum type, - TranslatedIndexData *indexInfo) override; + TranslatedIndexData *indexInfo); - void applyTransformFeedbackBuffers(const gl::State &state) override; - - gl::Error clear(const ClearParameters &clearParams, + gl::Error clear(const gl::Context *context, + const ClearParameters &clearParams, const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer); - virtual void markAllStateDirty(); + void markAllStateDirty(); // lost device bool testDeviceLost() override; bool testDeviceResettable() override; VendorID getVendorId() const; - std::string getRendererDescription() const override; + std::string getRendererDescription() const; 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; + unsigned int getReservedVertexUniformVectors() const; + unsigned int getReservedFragmentUniformVectors() const; bool getShareHandleSupport() const; - virtual int getMajorShaderModel() const; + int getMajorShaderModel() const override; int getMinorShaderModel() const override; std::string getShaderModelSuffix() const override; DWORD getCapsDeclTypes() 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); - virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); - virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - const gl::Offset &destOffset, TextureStorage *storage, GLint level); + gl::Error copyImage2D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImageCube(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum target, + GLint level) override; + gl::Error copyImage3D(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + gl::Error copyImage2DArray(const gl::Context *context, + const gl::Framebuffer *framebuffer, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLint level) override; + + gl::Error copyTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + const gl::Rectangle &sourceRect, + GLenum destFormat, + const gl::Offset &destOffset, + TextureStorage *storage, + GLenum destTarget, + GLint destLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + gl::Error copyCompressedTexture(const gl::Context *context, + const gl::Texture *source, + GLint sourceLevel, + TextureStorage *storage, + GLint destLevel) override; // RenderTarget creation - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + gl::Error createRenderTarget(int width, + int height, + GLenum format, + GLsizei samples, + RenderTargetD3D **outRT) override; gl::Error createRenderTargetCopy(RenderTargetD3D *source, RenderTargetD3D **outRT) override; - // Framebuffer creation - FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; - - // Shader creation - ShaderImpl *createShader(const gl::Shader::Data &data) override; - ProgramImpl *createProgram(const gl::Program::Data &data) override; - // Shader operations - gl::Error loadExecutable(const void *function, + gl::Error loadExecutable(const uint8_t *function, size_t length, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) override; gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, - ShaderType type, + gl::ShaderType type, const std::vector &streamOutVaryings, bool separatedOutputBuffers, - const D3DCompilerWorkarounds &workarounds, + const angle::CompilerWorkaroundsD3D &workarounds, ShaderExecutableD3D **outExectuable) override; + gl::Error ensureHLSLCompilerInitialized() 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); - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - - // Texture creation - virtual TextureImpl *createTexture(GLenum target); - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer(); + ImageD3D *createImage() override; + gl::Error generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *source) override; + gl::Error generateMipmapUsingD3D(const gl::Context *context, + TextureStorage *storage, + const gl::TextureState &textureState) override; + gl::Error copyImage(const gl::Context *context, + ImageD3D *dest, + ImageD3D *source, + const gl::Rectangle &sourceRect, + const gl::Offset &destOffset, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) override; + TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; + TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, + RenderTargetD3D *renderTargetD3D) override; + TextureStorage *createTextureStorageExternal( + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) override; + TextureStorage *createTextureStorage2D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorageCube(GLenum internalformat, + bool renderTarget, + int size, + int levels, + bool hintLevelZeroOnly) override; + TextureStorage *createTextureStorage3D(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + TextureStorage *createTextureStorage2DArray(GLenum internalformat, + bool renderTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + int levels) override; + + TextureStorage *createTextureStorage2DMultisample(GLenum internalformat, + GLsizei width, + GLsizei height, + int levels, + int samples, + bool fixedSampleLocations) override; // Buffer creation - virtual BufferImpl *createBuffer(); - virtual VertexBuffer *createVertexBuffer(); - virtual IndexBuffer *createIndexBuffer(); + VertexBuffer *createVertexBuffer() override; + IndexBuffer *createIndexBuffer() override; - // Vertex Array creation - VertexArrayImpl *createVertexArray(const gl::VertexArray::Data &data) override; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); + // Stream Creation + StreamProducerImpl *createStreamProducerD3DTextureNV12( + egl::Stream::ConsumerType consumerType, + const egl::AttributeMap &attribs) override; // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - 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; + bool supportsFastCopyBufferToTexture(GLenum internalFormat) const override; + gl::Error fastCopyBufferToTexture(const gl::Context *context, + const gl::PixelUnpackState &unpack, + unsigned int offset, + RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, + GLenum sourcePixelsType, + const gl::Box &destArea) override; // D3D9-renderer specific methods gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); @@ -250,42 +338,82 @@ class Renderer9 : public RendererD3D D3DPOOL getTexturePool(DWORD usage) const; bool getLUID(LUID *adapterLuid) const override; - VertexConversionType getVertexConversionType(gl::VertexFormatType vertexFormatType) const override; + VertexConversionType getVertexConversionType( + gl::VertexFormatType vertexFormatType) const override; GLenum getVertexComponentType(gl::VertexFormatType vertexFormatType) const override; - gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. + gl::ErrorOrResult getVertexSpaceRequired(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + GLsizei count, + GLsizei instances) const override; - RendererClass getRendererClass() const override { return RENDERER_D3D9; } + gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, + IDirect3DSurface9 *source, + bool fromManaged); + + RendererClass getRendererClass() const override; 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; + StateManager9 *getStateManager() { return &mStateManager; } + + gl::Error genericDrawArrays(const gl::Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei instances); + + gl::Error genericDrawElements(const gl::Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instances); + + // Necessary hack for default framebuffers in D3D. + FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override; + + DebugAnnotator9 *getAnnotator() { return &mAnnotator; } + + gl::Version getMaxSupportedESVersion() const override; + + gl::Error clearRenderTarget(RenderTargetD3D *renderTarget, + const gl::ColorF &clearColorValue, + const float clearDepthValue, + const unsigned int clearStencilValue) override; + + bool canSelectViewInVertexShader() const override; private: - gl::Error drawArraysImpl(const gl::Data &data, + gl::Error drawArraysImpl(const gl::Context *context, GLenum mode, + GLint startVertex, GLsizei count, - GLsizei instances) override; - gl::Error drawElementsImpl(const gl::Data &data, - const TranslatedIndexData &indexInfo, + GLsizei instances); + gl::Error drawElementsImpl(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, - GLsizei instances) override; + const void *indices, + GLsizei instances); - void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, + gl::Error applyShaders(const gl::Context *context, GLenum drawMode); + + gl::Error applyTextures(const gl::Context *context); + gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType); + + void generateCaps(gl::Caps *outCaps, + gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions, gl::Limitations *outLimitations) const override; - WorkaroundsD3D generateWorkarounds() const override; + angle::WorkaroundsD3D generateWorkarounds() const override; - gl::Error setBlendDepthRasterStates(const gl::Data &glData, GLenum drawMode); + gl::Error setBlendDepthRasterStates(const gl::Context *context, GLenum drawMode); void release(); @@ -293,18 +421,30 @@ class Renderer9 : public RendererD3D 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); + gl::Error drawLineLoop(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer); + gl::Error drawIndexedPoints(const gl::Context *context, + GLsizei count, + GLenum type, + const void *indices, + int minIndex, + gl::Buffer *elementArrayBuffer); gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); - gl::Error getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer); + gl::Error getNullColorbuffer(const gl::Context *context, + const gl::FramebufferAttachment *depthbuffer, + const gl::FramebufferAttachment **outColorBuffer); D3DPOOL getBufferPool(DWORD usage) const; HMODULE mD3d9Module; - void initializeDevice(); + egl::Error initializeDevice(); D3DPRESENT_PARAMETERS getDefaultPresentParameters(); void releaseDeviceResources(); @@ -314,7 +454,7 @@ class Renderer9 : public RendererD3D UINT mAdapter; D3DDEVTYPE mDeviceType; - IDirect3D9 *mD3d9; // Always valid after successful initialization. + IDirect3D9 *mD3d9; // Always valid after successful initialization. IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. IDirect3DDevice9 *mDevice; IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. @@ -368,7 +508,7 @@ class Renderer9 : public RendererD3D unsigned int mAppliedProgramSerial; // A pool of event queries that are currently unused. - std::vector mEventQueryPool; + std::vector mEventQueryPool; VertexShaderCache mVertexShaderCache; PixelShaderCache mPixelShaderCache; @@ -379,7 +519,10 @@ class Renderer9 : public RendererD3D StreamingIndexBufferInterface *mLineLoopIB; StaticIndexBufferInterface *mCountingIB; - enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; + enum + { + NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 + }; struct NullColorbufferCacheEntry { UINT lruCount; @@ -390,7 +533,11 @@ class Renderer9 : public RendererD3D UINT mMaxNullColorbufferLRU; DeviceD3D *mEGLDevice; + std::vector mTranslatedAttribCache; + + DebugAnnotator9 mAnnotator; }; -} -#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ +} // namespace rx + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h index cf831c62fa..399770dd8d 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h @@ -24,9 +24,7 @@ template class ShaderCache : angle::NonCopyable { public: - ShaderCache() : mDevice(NULL) - { - } + ShaderCache() : mDevice(nullptr) {} ~ShaderCache() { @@ -47,14 +45,14 @@ class ShaderCache : angle::NonCopyable { it->second->AddRef(); *outShaderObject = it->second; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } ShaderObject *shader; HRESULT result = createShader(function, &shader); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create shader, " << gl::FmtHR(result); } // Random eviction policy. @@ -68,7 +66,7 @@ class ShaderCache : angle::NonCopyable mMap[key] = shader; *outShaderObject = shader; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void clear() 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 28a486056b..362c6c60a3 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -18,14 +18,14 @@ ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirec : ShaderExecutableD3D(function, length) { mPixelExecutable = executable; - mVertexExecutable = NULL; + mVertexExecutable = nullptr; } ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) : ShaderExecutableD3D(function, length) { mVertexExecutable = executable; - mPixelExecutable = NULL; + mPixelExecutable = nullptr; } ShaderExecutable9::~ShaderExecutable9() @@ -44,4 +44,4 @@ IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const return mPixelExecutable; } -} \ No newline at end of file +} 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 382a68c820..0b6b87947e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h @@ -20,7 +20,7 @@ class ShaderExecutable9 : public ShaderExecutableD3D public: ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); - virtual ~ShaderExecutable9(); + ~ShaderExecutable9() override; 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 index c4c600aedb..a3bdc14efb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp @@ -7,7 +7,7 @@ // StateManager9.cpp: Defines a class for caching D3D9 state #include "libANGLE/renderer/d3d/d3d9/StateManager9.h" -#include "common/BitSetIterator.h" +#include "common/bitset_utils.h" #include "common/utilities.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" @@ -18,7 +18,8 @@ namespace rx { StateManager9::StateManager9(Renderer9 *renderer9) - : mCurBlendState(), + : mUsingZeroColorMaskWorkaround(false), + mCurBlendState(), mCurBlendColor(0, 0, 0, 0), mCurSampleMask(0), mCurRasterState(), @@ -67,6 +68,11 @@ StateManager9::~StateManager9() { } +void StateManager9::initialize() +{ + mUsingZeroColorMaskWorkaround = IsAMD(mRenderer9->getVendorId()); +} + void StateManager9::forceSetBlendState() { mDirtyBits |= mBlendStateDirtyBits; @@ -114,7 +120,7 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits return; } - for (auto dirtyBit : angle::IterateBitSet(dirtyBits)) + for (auto dirtyBit : dirtyBits) { switch (dirtyBit) { @@ -125,6 +131,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits // 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); + + // The color mask may have to be updated if the blend state changes + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; case gl::State::DIRTY_BIT_BLEND_FUNCS: @@ -138,6 +150,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); // BlendColor depends on the values of blend funcs mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; } @@ -148,6 +166,12 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha) { mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + + // The color mask may have to be updated if the blend funcs change + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + } } break; } @@ -167,6 +191,14 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha) { mDirtyBits.set(DIRTY_BIT_COLOR_MASK); + + // The color mask can cause the blend state to get out of sync when using the + // zero color mask workaround + if (mUsingZeroColorMaskWorkaround) + { + mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED); + mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS); + } } break; } @@ -364,7 +396,7 @@ gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState, mCurFrontFaceCCW = frontFaceCCW; } - for (auto dirtyBit : angle::IterateBitSet(mDirtyBits)) + for (auto dirtyBit : mDirtyBits) { switch (dirtyBit) { @@ -438,11 +470,10 @@ gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState, setSampleMask(sampleMask); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void StateManager9::setViewportState(const gl::Caps *caps, - const gl::Rectangle &viewport, +void StateManager9::setViewportState(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, @@ -698,6 +729,7 @@ void StateManager9::setStencilTestEnabled(bool stencilTestEnabled) if (stencilTestEnabled && mCurStencilSize > 0) { mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mRenderer9->getDevice()->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); } else { @@ -718,7 +750,7 @@ void StateManager9::setSampleAlphaToCoverage(bool enabled) { if (enabled) { - FIXME("Sample alpha to coverage is unimplemented."); + UNREACHABLE(); } } @@ -800,42 +832,52 @@ void StateManager9::setColorMask(const gl::Framebuffer *framebuffer, 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); + const auto *attachment = framebuffer->getFirstColorbuffer(); + const auto &format = attachment ? attachment->getFormat() : gl::Format::Invalid(); 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) + format.info->redBits > 0 && red, format.info->greenBits > 0 && green, + format.info->blueBits > 0 && blue, format.info->alphaBits > 0 && alpha); + + // 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://anglebug.com/169 + if (colorMask == 0 && mUsingZeroColorMaskWorkaround) { 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); + + mCurBlendState.colorMaskRed = false; + mCurBlendState.colorMaskGreen = true; + mCurBlendState.colorMaskBlue = false; + mCurBlendState.colorMaskAlpha = false; + + mCurBlendState.blend = true; + mCurBlendState.sourceBlendRGB = GL_ZERO; + mCurBlendState.sourceBlendAlpha = GL_ZERO; + mCurBlendState.destBlendRGB = GL_ONE; + mCurBlendState.destBlendAlpha = GL_ONE; + mCurBlendState.blendEquationRGB = GL_FUNC_ADD; + mCurBlendState.blendEquationAlpha = GL_FUNC_ADD; } else { mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); - } - mCurBlendState.colorMaskRed = red; - mCurBlendState.colorMaskGreen = green; - mCurBlendState.colorMaskBlue = blue; - mCurBlendState.colorMaskAlpha = alpha; + mCurBlendState.colorMaskRed = red; + mCurBlendState.colorMaskGreen = green; + mCurBlendState.colorMaskBlue = blue; + mCurBlendState.colorMaskAlpha = alpha; + } } void StateManager9::setSampleMask(unsigned int sampleMask) @@ -848,7 +890,7 @@ void StateManager9::setSampleMask(unsigned int sampleMask) mCurSampleMask = sampleMask; } -void StateManager9::setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace) +void StateManager9::setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace) { if (cullFace) { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h index d8c1eb9812..63ce17cb1e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/StateManager9.h @@ -10,7 +10,7 @@ #define LIBANGLE_RENDERER_D3D9_STATEMANAGER9_H_ #include "libANGLE/angletypes.h" -#include "libANGLE/Data.h" +#include "libANGLE/ContextState.h" #include "libANGLE/State.h" #include "libANGLE/renderer/d3d/RendererD3D.h" @@ -39,12 +39,13 @@ class StateManager9 final : angle::NonCopyable StateManager9(Renderer9 *renderer9); ~StateManager9(); + void initialize(); + 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, + void setViewportState(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, @@ -85,7 +86,7 @@ class StateManager9 final : angle::NonCopyable void setSampleMask(unsigned int sampleMask); // Current raster state functions - void setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace); + void setCullMode(bool cullFace, gl::CullFaceMode cullMode, GLenum frontFace); void setDepthBias(bool polygonOffsetFill, GLfloat polygonOffsetFactor, GLfloat polygonOffsetUnits); @@ -154,7 +155,9 @@ class StateManager9 final : angle::NonCopyable DIRTY_BIT_MAX }; - typedef std::bitset DirtyBits; + using DirtyBits = angle::BitSet; + + bool mUsingZeroColorMaskWorkaround; // Currently applied blend state gl::BlendState mCurBlendState; 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 be6a9c424c..bc81aa18ec 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp @@ -7,25 +7,29 @@ // SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" -#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +#include "libANGLE/features.h" #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h" #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" -#include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" namespace rx { SwapChain9::SwapChain9(Renderer9 *renderer, - NativeWindow nativeWindow, + NativeWindow9 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, EGLint orientation) - : SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + : SwapChainD3D(shareHandle, d3dTexture, backBufferFormat, depthBufferFormat), mRenderer(renderer), mWidth(-1), mHeight(-1), mSwapInterval(-1), + mNativeWindow(nativeWindow), mSwapChain(nullptr), mBackBuffer(nullptr), mRenderTarget(nullptr), @@ -50,9 +54,9 @@ void SwapChain9::release() SafeRelease(mRenderTarget); SafeRelease(mOffscreenTexture); - if (mNativeWindow.getNativeWindow()) + if (mNativeWindow->getNativeWindow()) { - mShareHandle = NULL; + mShareHandle = nullptr; } } @@ -75,17 +79,20 @@ static DWORD convertInterval(EGLint interval) #endif } -EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) +EGLint SwapChain9::resize(const gl::Context *context, int backbufferWidth, int backbufferHeight) { // D3D9 does not support resizing swap chains without recreating them - return reset(backbufferWidth, backbufferHeight, mSwapInterval); + return reset(context, backbufferWidth, backbufferHeight, mSwapInterval); } -EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +EGLint SwapChain9::reset(const gl::Context *context, + int backbufferWidth, + int backbufferHeight, + EGLint swapInterval) { IDirect3DDevice9 *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return EGL_BAD_ACCESS; } @@ -103,28 +110,37 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI SafeRelease(mOffscreenTexture); SafeRelease(mDepthStencil); - HANDLE *pShareHandle = NULL; - if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) + const d3d9::TextureFormat &backBufferd3dFormatInfo = + d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat); + if (mD3DTexture != nullptr) { - pShareHandle = &mShareHandle; + result = mD3DTexture->QueryInterface(&mOffscreenTexture); + ASSERT(SUCCEEDED(result)); } - - const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mOffscreenRenderTargetFormat); - result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, - backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, - pShareHandle); - if (FAILED(result)) + else { - ERR("Could not create offscreen texture: %08lX", result); - release(); - - if (d3d9::isDeviceLostError(result)) + HANDLE *pShareHandle = nullptr; + if (!mNativeWindow->getNativeWindow() && mRenderer->getShareHandleSupport()) { - return EGL_CONTEXT_LOST; + pShareHandle = &mShareHandle; } - else + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, + &mOffscreenTexture, pShareHandle); + if (FAILED(result)) { - return EGL_BAD_ALLOC; + ERR() << "Could not create offscreen texture, " << gl::FmtHR(result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } } } @@ -163,7 +179,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI // Don't create a swapchain for NULLREF devices D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType(); - EGLNativeWindowType window = mNativeWindow.getNativeWindow(); + EGLNativeWindowType window = mNativeWindow->getNativeWindow(); if (window && deviceType != D3DDEVTYPE_NULLREF) { D3DPRESENT_PARAMETERS presentParameters = {0}; @@ -189,7 +205,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI // // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur. - if (mRenderer->getVendorId() == VENDOR_ID_INTEL) + if (IsIntel(mRenderer->getVendorId())) { presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; } @@ -200,7 +216,8 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); - ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + ERR() << "Could not create additional swap chains or offscreen surfaces, " + << gl::FmtHR(result); release(); if (d3d9::isDeviceLostError(result)) @@ -215,20 +232,21 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); ASSERT(SUCCEEDED(result)); - InvalidateRect(window, NULL, FALSE); + InvalidateRect(window, nullptr, FALSE); } if (mDepthBufferFormat != GL_NONE) { - result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, - depthBufferd3dFormatInfo.renderFormat, - D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL); + result = device->CreateDepthStencilSurface( + backbufferWidth, backbufferHeight, depthBufferd3dFormatInfo.renderFormat, + D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); - ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + ERR() << "Could not create depthstencil surface for new swap chain, " + << gl::FmtHR(result); release(); if (d3d9::isDeviceLostError(result)) @@ -250,7 +268,11 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI } // parameters should be validated/clamped by caller -EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +EGLint SwapChain9::swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) { if (!mSwapChain) { @@ -270,11 +292,11 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - device->SetPixelShader(NULL); - device->SetVertexShader(NULL); + device->SetPixelShader(nullptr); + device->SetVertexShader(nullptr); device->SetRenderTarget(0, mBackBuffer); - device->SetDepthStencilSurface(NULL); + device->SetDepthStencilSurface(nullptr); device->SetTexture(0, mOffscreenTexture); device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); @@ -313,7 +335,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); mRenderer->endScene(); - device->SetTexture(0, NULL); + device->SetTexture(0, nullptr); RECT rect = { @@ -321,7 +343,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) static_cast(x + width), static_cast(mHeight - y) }; - HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + HRESULT result = mSwapChain->Present(&rect, &rect, nullptr, nullptr, 0); mRenderer->markAllStateDirty(); @@ -333,7 +355,7 @@ EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The // device appears to be ok after emitting this error so simply return a failure to swap. - if (result == 0x88760873) + if (result == static_cast(0x88760873)) { return EGL_BAD_MATCH; } @@ -395,6 +417,12 @@ void *SwapChain9::getKeyedMutex() return nullptr; } +egl::Error SwapChain9::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) +{ + UNREACHABLE(); + return egl::EglBadSurface(); +} + void SwapChain9::recreate() { if (!mSwapChain) @@ -403,7 +431,7 @@ void SwapChain9::recreate() } IDirect3DDevice9 *device = mRenderer->getDevice(); - if (device == NULL) + if (device == nullptr) { return; } @@ -412,7 +440,7 @@ void SwapChain9::recreate() HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); ASSERT(SUCCEEDED(result)); - IDirect3DSwapChain9* newSwapChain = NULL; + IDirect3DSwapChain9 *newSwapChain = nullptr; result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); if (FAILED(result)) { @@ -427,4 +455,13 @@ void SwapChain9::recreate() ASSERT(SUCCEEDED(result)); } +RenderTargetD3D *SwapChain9::getColorRenderTarget() +{ + return &mColorRenderTarget; +} + +RenderTargetD3D *SwapChain9::getDepthStencilRenderTarget() +{ + return &mDepthStencilRenderTarget; +} } 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 55a700c2d6..5753637c47 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h @@ -15,26 +15,36 @@ namespace rx { +class NativeWindow9; class Renderer9; class SwapChain9 : public SwapChainD3D { public: SwapChain9(Renderer9 *renderer, - NativeWindow nativeWindow, + NativeWindow9 *nativeWindow, HANDLE shareHandle, + IUnknown *d3dTexture, GLenum backBufferFormat, GLenum depthBufferFormat, EGLint orientation); - virtual ~SwapChain9(); + ~SwapChain9() override; - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - virtual void recreate(); + EGLint resize(const gl::Context *context, EGLint backbufferWidth, EGLint backbufferHeight) + override; + EGLint reset(const gl::Context *context, + EGLint backbufferWidth, + EGLint backbufferHeight, + EGLint swapInterval) override; + EGLint swapRect(const gl::Context *context, + EGLint x, + EGLint y, + EGLint width, + EGLint height) override; + void recreate() override; - RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } - RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + RenderTargetD3D *getColorRenderTarget() override; + RenderTargetD3D *getDepthStencilRenderTarget() override; virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); @@ -45,6 +55,8 @@ class SwapChain9 : public SwapChainD3D void *getKeyedMutex() override; + egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override; + private: void release(); @@ -53,6 +65,8 @@ class SwapChain9 : public SwapChainD3D EGLint mHeight; EGLint mSwapInterval; + NativeWindow9 *mNativeWindow; + IDirect3DSwapChain9 *mSwapChain; IDirect3DSurface9 *mBackBuffer; IDirect3DSurface9 *mRenderTarget; 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 b28d5076b5..6404af6bba 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp @@ -43,7 +43,7 @@ DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) { DWORD d3dusage = 0; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) { @@ -93,11 +93,16 @@ int TextureStorage9::getLevelCount() const return static_cast(mMipLevels) - mTopLevel; } -gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +gl::Error TextureStorage9::setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) @@ -107,7 +112,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai mTexture = surfaceTexture; mMipLevels = surfaceTexture->GetLevelCount(); - mInternalFormat = swapchain->GetRenderTargetInternalFormat(); + mInternalFormat = swapchain->getRenderTargetInternalFormat(); D3DSURFACE_DESC surfaceDesc; surfaceTexture->GetLevelDesc(0, &surfaceDesc); @@ -121,7 +126,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchai TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { - mTexture = NULL; + mTexture = nullptr; mInternalFormat = internalformat; @@ -139,7 +144,7 @@ TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalforma TextureStorage9_2D::~TextureStorage9_2D() { SafeRelease(mTexture); - for (auto &renderTarget : mRenderTargets) + for (RenderTargetD3D *renderTarget : mRenderTargets) { SafeDelete(renderTarget); } @@ -147,16 +152,16 @@ TextureStorage9_2D::~TextureStorage9_2D() // Increments refcount on surface. // caller must Release() the returned surface -gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_2D::getSurfaceLevel(const gl::Context *context, + 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); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; @@ -169,33 +174,36 @@ gl::Error TextureStorage9_2D::getSurfaceLevel(GLenum target, ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(result); } // With managed textures the driver needs to be informed of updates to the lower mipmap levels if (level + mTopLevel != 0 && isManaged() && dirty) { - texture->AddDirtyRect(NULL); + texture->AddDirtyRect(nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage9_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(index.mipIndex < getLevelCount()); if (!mRenderTargets[index.mipIndex] && isRenderTarget()) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; } - IDirect3DSurface9 *surface = NULL; - error = getSurfaceLevel(GL_TEXTURE_2D, index.mipIndex, false, &surface); + IDirect3DSurface9 *surface = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_2D, index.mipIndex, false, &surface); if (error.isError()) { return error; @@ -213,20 +221,22 @@ gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &index, Rende ASSERT(outRT); *outRT = mRenderTargets[index.mipIndex]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage9_2D::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { - IDirect3DSurface9 *upper = NULL; - gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper); + IDirect3DSurface9 *upper = nullptr; + gl::Error error = getSurfaceLevel(context, GL_TEXTURE_2D, sourceIndex.mipIndex, false, &upper); if (error.isError()) { return error; } - IDirect3DSurface9 *lower = NULL; - error = getSurfaceLevel(GL_TEXTURE_2D, destIndex.mipIndex, true, &lower); + IDirect3DSurface9 *lower = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_2D, destIndex.mipIndex, true, &lower); if (error.isError()) { SafeRelease(upper); @@ -242,32 +252,34 @@ gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, return error; } -gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_2D::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) { // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture(static_cast(mTextureWidth), + HRESULT result = device->CreateTexture(static_cast(mTextureWidth), static_cast(mTextureHeight), static_cast(mMipLevels), getUsage(), - mTextureFormat, getPool(), &mTexture, NULL); + mTextureFormat, getPool(), &mTexture, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to create 2D storage texture, " << gl::FmtHR(result); } } *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_2D::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); @@ -276,15 +288,15 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) int levels = getLevelCount(); for (int i = 0; i < levels; ++i) { - IDirect3DSurface9 *srcSurf = NULL; - gl::Error error = getSurfaceLevel(GL_TEXTURE_2D, i, false, &srcSurf); + IDirect3DSurface9 *srcSurf = nullptr; + gl::Error error = getSurfaceLevel(context, GL_TEXTURE_2D, i, false, &srcSurf); if (error.isError()) { return error; } - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getSurfaceLevel(GL_TEXTURE_2D, i, true, &dstSurf); + IDirect3DSurface9 *dstSurf = nullptr; + error = dest9->getSurfaceLevel(context, GL_TEXTURE_2D, i, true, &dstSurf); if (error.isError()) { SafeRelease(srcSurf); @@ -302,17 +314,14 @@ gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image) +TextureStorage9_EGLImage::TextureStorage9_EGLImage(Renderer9 *renderer, + EGLImageD3D *image, + RenderTarget9 *renderTarget9) : 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(); @@ -325,18 +334,17 @@ TextureStorage9_EGLImage::~TextureStorage9_EGLImage() { } -gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *context, + 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); + gl::Error error = mImage->getRenderTarget(context, &renderTargetD3D); if (error.isError()) { return error; @@ -345,23 +353,24 @@ gl::Error TextureStorage9_EGLImage::getSurfaceLevel(GLenum target, RenderTarget9 *renderTarget9 = GetAs(renderTargetD3D); *outSurface = renderTarget9->getSurface(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::ImageIndex &index, +gl::Error TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); ASSERT(index.mipIndex == 0); - UNUSED_ASSERTION_VARIABLE(index); - return mImage->getRenderTarget(outRT); + return mImage->getRenderTarget(context, outRT); } -gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_EGLImage::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) { RenderTargetD3D *renderTargetD3D = nullptr; - gl::Error error = mImage->getRenderTarget(&renderTargetD3D); + gl::Error error = mImage->getRenderTarget(context, &renderTargetD3D); if (error.isError()) { return error; @@ -371,16 +380,19 @@ gl::Error TextureStorage9_EGLImage::getBaseTexture(IDirect3DBaseTexture9 **outTe *outTexture = renderTarget9->getTexture(); ASSERT(*outTexture != nullptr); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::ImageIndex &, const gl::ImageIndex &) +gl::Error TextureStorage9_EGLImage::generateMipmap(const gl::Context *context, + const gl::ImageIndex &, + const gl::ImageIndex &) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_EGLImage::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); ASSERT(getLevelCount() == 1); @@ -388,7 +400,7 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) TextureStorage9 *dest9 = GetAs(destStorage); IDirect3DBaseTexture9 *destBaseTexture9 = nullptr; - gl::Error error = dest9->getBaseTexture(&destBaseTexture9); + gl::Error error = dest9->getBaseTexture(context, &destBaseTexture9); if (error.isError()) { return error; @@ -400,12 +412,12 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) 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); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(result); } RenderTargetD3D *sourceRenderTarget = nullptr; - error = mImage->getRenderTarget(&sourceRenderTarget); + error = mImage->getRenderTarget(context, &sourceRenderTarget); if (error.isError()) { SafeRelease(destSurface); @@ -427,16 +439,16 @@ gl::Error TextureStorage9_EGLImage::copyToStorage(TextureStorage *destStorage) } SafeRelease(destSurface); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { - mTexture = NULL; - for (int i = 0; i < CUBE_FACE_COUNT; ++i) + mTexture = nullptr; + for (size_t i = 0; i < gl::CUBE_FACE_COUNT; ++i) { - mRenderTarget[i] = NULL; + mRenderTarget[i] = nullptr; } mInternalFormat = internalformat; @@ -455,7 +467,7 @@ TextureStorage9_Cube::~TextureStorage9_Cube() { SafeRelease(mTexture); - for (int i = 0; i < CUBE_FACE_COUNT; ++i) + for (size_t i = 0; i < gl::CUBE_FACE_COUNT; ++i) { SafeDelete(mRenderTarget[i]); } @@ -463,13 +475,14 @@ TextureStorage9_Cube::~TextureStorage9_Cube() // Increments refcount on surface. // caller must Release() the returned surface -gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target, +gl::Error TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context, + GLenum target, int level, bool dirty, IDirect3DSurface9 **outSurface) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; @@ -483,35 +496,38 @@ gl::Error TextureStorage9_Cube::getSurfaceLevel(GLenum target, ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to get the surface from a texture, " + << gl::FmtHR(result); } // With managed textures the driver needs to be informed of updates to the lower mipmap levels if (level != 0 && isManaged() && dirty) { - texture->AddDirtyRect(face, NULL); + texture->AddDirtyRect(face, nullptr); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureStorage9_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(outRT); ASSERT(index.mipIndex == 0); - ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); + ASSERT(index.layerIndex >= 0 && static_cast(index.layerIndex) < gl::CUBE_FACE_COUNT); - if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) + if (mRenderTarget[index.layerIndex] == nullptr && isRenderTarget()) { - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); + IDirect3DBaseTexture9 *baseTexture = nullptr; + gl::Error error = getBaseTexture(context, &baseTexture); if (error.isError()) { return error; } - IDirect3DSurface9 *surface = NULL; - error = getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, + IDirect3DSurface9 *surface = nullptr; + error = getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, mTopLevel + index.mipIndex, false, &surface); if (error.isError()) { @@ -525,20 +541,23 @@ gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, Ren } *outRT = mRenderTarget[index.layerIndex]; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +gl::Error TextureStorage9_Cube::generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) { - IDirect3DSurface9 *upper = NULL; - gl::Error error = getSurfaceLevel(sourceIndex.type, sourceIndex.mipIndex, false, &upper); + IDirect3DSurface9 *upper = nullptr; + gl::Error error = + getSurfaceLevel(context, sourceIndex.type, sourceIndex.mipIndex, false, &upper); if (error.isError()) { return error; } - IDirect3DSurface9 *lower = NULL; - error = getSurfaceLevel(destIndex.type, destIndex.mipIndex, true, &lower); + IDirect3DSurface9 *lower = nullptr; + error = getSurfaceLevel(context, destIndex.type, destIndex.mipIndex, true, &lower); if (error.isError()) { SafeRelease(upper); @@ -554,52 +573,56 @@ gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex return error; } -gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +gl::Error TextureStorage9_Cube::getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) { // if the size is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + if (mTexture == nullptr && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); ASSERT(mTextureWidth == mTextureHeight); IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateCubeTexture( + HRESULT result = device->CreateCubeTexture( static_cast(mTextureWidth), static_cast(mMipLevels), - getUsage(), mTextureFormat, getPool(), &mTexture, NULL); + getUsage(), mTextureFormat, getPool(), &mTexture, nullptr); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result); + return gl::OutOfMemory() + << "Failed to create cube storage texture, " << gl::FmtHR(result); } } *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) +gl::Error TextureStorage9_Cube::copyToStorage(const gl::Context *context, + TextureStorage *destStorage) { ASSERT(destStorage); TextureStorage9_Cube *dest9 = GetAs(destStorage); int levels = getLevelCount(); - for (int f = 0; f < CUBE_FACE_COUNT; f++) + for (int f = 0; f < static_cast(gl::CUBE_FACE_COUNT); f++) { for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *srcSurf = NULL; + IDirect3DSurface9 *srcSurf = nullptr; gl::Error error = - getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); + getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); if (error.isError()) { return error; } - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getSurfaceLevel(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); + IDirect3DSurface9 *dstSurf = nullptr; + error = dest9->getSurfaceLevel(context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, + &dstSurf); if (error.isError()) { SafeRelease(srcSurf); @@ -618,7 +641,7 @@ gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } 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 50e63a6f14..2f51901931 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h @@ -25,28 +25,34 @@ class RenderTarget9; class TextureStorage9 : public TextureStorage { public: - virtual ~TextureStorage9(); + ~TextureStorage9() override; static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); D3DPOOL getPool() const; DWORD getUsage() const; - virtual gl::Error getSurfaceLevel(GLenum target, + virtual gl::Error getSurfaceLevel(const gl::Context *context, + 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 gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) = 0; - virtual int getTopLevel() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; + int getTopLevel() const override; + bool isRenderTarget() const override; + bool isManaged() const override; bool supportsNativeMipmapFunction() const override; - virtual int getLevelCount() const; + int getLevelCount() const override; - 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 setData(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D *image, + const gl::Box *destBox, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixelData) override; protected: int mTopLevel; @@ -70,16 +76,22 @@ class TextureStorage9_2D : public TextureStorage9 public: TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); - virtual ~TextureStorage9_2D(); + ~TextureStorage9_2D() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + 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); - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: IDirect3DTexture9 *mTexture; @@ -89,18 +101,23 @@ class TextureStorage9_2D : public TextureStorage9 class TextureStorage9_EGLImage final : public TextureStorage9 { public: - TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image); + TextureStorage9_EGLImage(Renderer9 *renderer, EGLImageD3D *image, RenderTarget9 *renderTarget9); ~TextureStorage9_EGLImage() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + 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, + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) override; - gl::Error copyToStorage(TextureStorage *destStorage) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: EGLImageD3D *mImage; @@ -110,25 +127,28 @@ class TextureStorage9_Cube : public TextureStorage9 { public: TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); - virtual ~TextureStorage9_Cube(); + ~TextureStorage9_Cube() override; - gl::Error getSurfaceLevel(GLenum target, + gl::Error getSurfaceLevel(const gl::Context *context, + 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); - virtual gl::Error copyToStorage(TextureStorage *destStorage); + gl::Error getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) override; + gl::Error getBaseTexture(const gl::Context *context, + IDirect3DBaseTexture9 **outTexture) override; + gl::Error generateMipmap(const gl::Context *context, + const gl::ImageIndex &sourceIndex, + const gl::ImageIndex &destIndex) override; + gl::Error copyToStorage(const gl::Context *context, TextureStorage *destStorage) override; private: - static const size_t CUBE_FACE_COUNT = 6; - IDirect3DCubeTexture9 *mTexture; - RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; + RenderTarget9 *mRenderTarget[gl::CUBE_FACE_COUNT]; }; } #endif // LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ - 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 992201737f..0f4410b8de 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h @@ -9,7 +9,9 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ #define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ +#include "libANGLE/Context.h" #include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d9/Context9.h" #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" namespace rx @@ -19,14 +21,26 @@ class Renderer9; class VertexArray9 : public VertexArrayImpl { public: - VertexArray9(const gl::VertexArray::Data &data) - : VertexArrayImpl(data) - { - } + VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {} - virtual ~VertexArray9() { } + void syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) override; + + ~VertexArray9() override {} + + Serial getCurrentStateSerial() const { return mCurrentStateSerial; } + + private: + Serial mCurrentStateSerial; }; +inline void VertexArray9::syncState(const gl::Context *context, + const gl::VertexArray::DirtyBits &dirtyBits) +{ + ASSERT(dirtyBits.any()); + Renderer9 *renderer = GetImplAs(context)->getRenderer(); + mCurrentStateSerial = renderer->generateSerial(); +} } #endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ 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 bfdf137126..c0b80a847c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -19,7 +19,7 @@ namespace rx VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) { - mVertexBuffer = NULL; + mVertexBuffer = nullptr; mBufferSize = 0; mDynamicUsage = false; } @@ -47,16 +47,18 @@ gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + return gl::OutOfMemory() + << "Failed to allocate internal vertex buffer of size " << size; } } mBufferSize = size; mDynamicUsage = dynamicUsage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -66,32 +68,33 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib { if (!mVertexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } - int inputStride = static_cast(gl::ComputeVertexAttributeStride(attrib)); + int inputStride = static_cast(gl::ComputeVertexAttributeStride(attrib, binding)); int elementSize = static_cast(gl::ComputeVertexAttributeTypeSize(attrib)); DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; - uint8_t *mapPtr = NULL; + uint8_t *mapPtr = nullptr; - unsigned int mapSize; - gl::Error error = spaceRequired(attrib, count, instances, &mapSize); - if (error.isError()) + auto errorOrMapSize = mRenderer->getVertexSpaceRequired(attrib, binding, count, instances); + if (errorOrMapSize.isError()) { - return error; + return errorOrMapSize.getError(); } + unsigned int mapSize = errorOrMapSize.getResult(); + HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast(&mapPtr), lockFlags); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); + return gl::OutOfMemory() << "Failed to lock internal vertex buffer, " << gl::FmtHR(result); } const uint8_t *input = sourceData; - if (instances == 0 || attrib.divisor == 0) + if (instances == 0 || binding.getDivisor() == 0) { input += inputStride * start; } @@ -112,13 +115,7 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib mVertexBuffer->Unlock(); - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const -{ - return spaceRequired(attrib, count, instances, outSpaceRequired); + return gl::NoError(); } unsigned int VertexBuffer9::getBufferSize() const @@ -134,7 +131,7 @@ gl::Error VertexBuffer9::setBufferSize(unsigned int size) } else { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -142,7 +139,7 @@ gl::Error VertexBuffer9::discard() { if (!mVertexBuffer) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + return gl::OutOfMemory() << "Internal vertex buffer is not initialized."; } void *dummy; @@ -151,65 +148,22 @@ gl::Error VertexBuffer9::discard() result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); + return gl::OutOfMemory() << "Failed to lock internal buffer for discarding, " + << gl::FmtHR(result); } result = mVertexBuffer->Unlock(); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); + return gl::OutOfMemory() << "Failed to unlock internal buffer for discarding, " + << gl::FmtHR(result); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const { return mVertexBuffer; } - -gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, - unsigned int *outSpaceRequired) const -{ - 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 = static_cast(count); - } - else - { - // Round up to divisor, if possible - elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); - } - - if (d3d9VertexInfo.outputElementSize <= std::numeric_limits::max() / elementCount) - { - if (outSpaceRequired) - { - *outSpaceRequired = - static_cast(d3d9VertexInfo.outputElementSize) * elementCount; - } - return gl::Error(GL_NO_ERROR); - } - else - { - return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); - } - } - else - { - const unsigned int elementSize = 4; - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * 4; - } - return gl::Error(GL_NO_ERROR); - } -} - -} +} // namespace rx 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 64271cbe2a..983616f4e4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h @@ -19,11 +19,13 @@ class VertexBuffer9 : public VertexBuffer { public: explicit VertexBuffer9(Renderer9 *renderer); - virtual ~VertexBuffer9(); - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + gl::Error initialize(unsigned int size, bool dynamicUsage) override; + // Warning: you should ensure binding really matches attrib.bindingIndex before using this + // function. gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, GLenum currentValueType, GLint start, GLsizei count, @@ -31,23 +33,19 @@ class VertexBuffer9 : public VertexBuffer unsigned int offset, const uint8_t *sourceData) override; - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; - - virtual unsigned int getBufferSize() const; - virtual gl::Error setBufferSize(unsigned int size); - virtual gl::Error discard(); + unsigned int getBufferSize() const override; + gl::Error setBufferSize(unsigned int size) override; + gl::Error discard() override; IDirect3DVertexBuffer9 *getBuffer() const; private: + ~VertexBuffer9() override; Renderer9 *mRenderer; IDirect3DVertexBuffer9 *mVertexBuffer; unsigned int mBufferSize; bool mDynamicUsage; - - gl::Error spaceRequired(const gl::VertexAttribute &attrib, std::size_t 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 a23ab4a290..abadf5c0b5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -21,7 +21,7 @@ VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) { for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) { - mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].vertexDeclaration = nullptr; mVertexDeclCache[i].lruCount = 0; } @@ -30,7 +30,7 @@ VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) mAppliedVBs[i].serial = 0; } - mLastSetVDecl = NULL; + mLastSetVDecl = nullptr; mInstancingEnabled = true; } @@ -42,11 +42,13 @@ VertexDeclarationCache::~VertexDeclarationCache() } } -gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, - const std::vector &attributes, - gl::Program *program, - GLsizei instances, - GLsizei *repeatDraw) +gl::Error VertexDeclarationCache::applyDeclaration( + IDirect3DDevice9 *device, + const std::vector &attributes, + gl::Program *program, + GLint start, + GLsizei instances, + GLsizei *repeatDraw) { ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size()); @@ -102,14 +104,14 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, D3DVERTEXELEMENT9 *element = &elements[0]; ProgramD3D *programD3D = GetImplAs(program); - const auto &semanticIndexes = programD3D->getSemanticIndexes(); + const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics(); 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); + ASSERT(attributes[i].storage == nullptr); int stream = static_cast(i); @@ -147,19 +149,24 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, } } - VertexBuffer9 *vertexBuffer = GetAs(attributes[i].vertexBuffer); + VertexBuffer9 *vertexBuffer = GetAs(attributes[i].vertexBuffer.get()); + + unsigned int offset = 0; + ANGLE_TRY_RESULT(attributes[i].computeOffset(start), offset); if (mAppliedVBs[stream].serial != attributes[i].serial || mAppliedVBs[stream].stride != attributes[i].stride || - mAppliedVBs[stream].offset != attributes[i].offset) + mAppliedVBs[stream].offset != offset) { - device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); + device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset, + attributes[i].stride); mAppliedVBs[stream].serial = attributes[i].serial; mAppliedVBs[stream].stride = attributes[i].stride; - mAppliedVBs[stream].offset = attributes[i].offset; + mAppliedVBs[stream].offset = offset; } - gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); + gl::VertexFormatType vertexformatType = + gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatType); element->Stream = static_cast(stream); @@ -200,7 +207,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, mLastSetVDecl = entry->vertexDeclaration; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } } @@ -214,7 +221,7 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, } } - if (lastCache->vertexDeclaration != NULL) + if (lastCache->vertexDeclaration != nullptr) { SafeRelease(lastCache->vertexDeclaration); // mLastSetVDecl is set to the replacement, so we don't have to worry @@ -225,14 +232,15 @@ gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); if (FAILED(result)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); + return gl::OutOfMemory() << "Failed to create internal vertex declaration, " + << gl::FmtHR(result); } device->SetVertexDeclaration(lastCache->vertexDeclaration); mLastSetVDecl = lastCache->vertexDeclaration; lastCache->lruCount = ++mMaxLru; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void VertexDeclarationCache::markStateDirty() @@ -242,7 +250,7 @@ void VertexDeclarationCache::markStateDirty() mAppliedVBs[i].serial = 0; } - mLastSetVDecl = NULL; + mLastSetVDecl = nullptr; mInstancingEnabled = true; // Forces it to be disabled when not used } 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 bad4de4d6b..7bd7cabae4 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -30,6 +30,7 @@ class VertexDeclarationCache gl::Error applyDeclaration(IDirect3DDevice9 *device, const std::vector &attributes, gl::Program *program, + GLint start, GLsizei instances, GLsizei *repeatDraw); 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 b672a60e3c..d10fa1ee87 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp @@ -7,12 +7,16 @@ // formatutils9.cpp: Queries for GL image formats and their translations to D3D9 // formats. -#include "libANGLE/renderer/d3d/copyimage.h" #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + #include "libANGLE/renderer/d3d/d3d9/Renderer9.h" #include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" -#include "libANGLE/renderer/d3d/generatemip.h" -#include "libANGLE/renderer/d3d/loadimage.h" + +using namespace angle; namespace rx { @@ -20,35 +24,8 @@ namespace rx namespace d3d9 { -const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); -const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); - -struct D3D9FastCopyFormat -{ - GLenum destFormat; - GLenum destType; - ColorCopyFunction copyFunction; - - D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) - : destFormat(destFormat), destType(destType), copyFunction(copyFunction) - { } - - bool operator<(const D3D9FastCopyFormat& other) const - { - return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; - } -}; - -typedef std::multimap D3D9FastCopyMap; - -static D3D9FastCopyMap BuildFastCopyMap() -{ - D3D9FastCopyMap map; - - map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); - - return map; -} +constexpr D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +constexpr D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); // A map to determine the pixel size and mip generation function of a given D3D format typedef std::map D3D9FormatInfoMap; @@ -64,109 +41,188 @@ D3DFormat::D3DFormat() luminanceBits(0), depthBits(0), stencilBits(0), - internalFormat(GL_NONE), - mipGenerationFunction(NULL), - colorReadFunction(NULL), - fastCopyFunctions() + formatID(angle::Format::ID::NONE) { } -ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const +D3DFormat::D3DFormat(GLuint bits, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint lumBits, + GLuint depthBits, + GLuint stencilBits, + Format::ID formatID) + : pixelBytes(bits / 8), + blockWidth(blockWidth), + blockHeight(blockHeight), + redBits(redBits), + greenBits(greenBits), + blueBits(blueBits), + alphaBits(alphaBits), + luminanceBits(lumBits), + depthBits(depthBits), + stencilBits(stencilBits), + formatID(formatID) { - FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); - return (iter != fastCopyFunctions.end()) ? iter->second : NULL; } -static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth, - GLuint blockHeight, GLuint redBits, GLuint greenBits, GLuint blueBits, - GLuint alphaBits, GLuint lumBits, GLuint depthBits, GLuint stencilBits, - GLenum internalFormat, MipGenerationFunction mipFunc, - ColorReadFunction colorReadFunc) +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) { - D3DFormat info; - info.pixelBytes = bits / 8; - info.blockWidth = blockWidth; - info.blockHeight = blockHeight; - info.redBits = redBits; - info.greenBits = greenBits; - info.blueBits = blueBits; - info.alphaBits = alphaBits; - info.luminanceBits = lumBits; - info.depthBits = depthBits; - info.stencilBits = stencilBits; - info.internalFormat = internalFormat; - info.mipGenerationFunction = mipFunc; - info.colorReadFunction = colorReadFunc; - - static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); - std::pair fastCopyIter = fastCopyMap.equal_range(format); - for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + if (format == D3DFMT_NULL) { - info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE); + return info; } - map->insert(std::make_pair(format, info)); -} - -static D3D9FormatInfoMap BuildD3D9FormatInfoMap() -{ - D3D9FormatInfoMap map; - - // | D3DFORMAT | S |W |H | R | G | B | A | L | D | S | Internal format | Mip generation function | Color read function | - InsertD3DFormatInfo(&map, D3DFMT_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); - - 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_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 ); - InsertD3DFormatInfo(&map, D3DFMT_R16F, 16, 1, 1, 16, 0, 0, 0, 0, 0, 0, GL_R16F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_G16R16F, 32, 1, 1, 16, 16, 0, 0, 0, 0, 0, GL_RG16F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F, 64, 1, 1, 16, 16, 16, 16, 0, 0, 0, GL_RGBA16F_EXT, GenerateMip, ReadColor); - InsertD3DFormatInfo(&map, D3DFMT_R32F, 32, 1, 1, 32, 0, 0, 0, 0, 0, 0, GL_R32F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_G32R32F, 64, 1, 1, 32, 32, 0, 0, 0, 0, 0, GL_RG32F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, 32, 32, 32, 32, 0, 0, 0, GL_RGBA32F_EXT, GenerateMip, ReadColor); - - InsertD3DFormatInfo(&map, D3DFMT_D16, 16, 1, 1, 0, 0, 0, 0, 0, 16, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D24S8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D24X8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D32, 32, 1, 1, 0, 0, 0, 0, 0, 32, 0, GL_DEPTH_COMPONENT32_OES, NULL, NULL ); - - InsertD3DFormatInfo(&map, D3DFMT_INTZ, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); - - InsertD3DFormatInfo(&map, D3DFMT_DXT1, 64, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_DXT3, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_DXT5, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ); - - return map; -} - -const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) -{ - static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); - D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); - if (iter != infoMap.end()) + if (format == D3DFMT_INTZ) { - return iter->second; + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, Format::ID::D24_UNORM_S8_UINT); + return info; } - else + + switch (format) { - static const D3DFormat defaultInfo; - return defaultInfo; - } -} + case D3DFMT_UNKNOWN: + { + static const D3DFormat info(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Format::ID::NONE); + return info; + } + case D3DFMT_L8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 0, 8, 0, 0, Format::ID::L8_UNORM); + return info; + } + case D3DFMT_A8: + { + static const D3DFormat info(8, 1, 1, 0, 0, 0, 8, 0, 0, 0, Format::ID::A8_UNORM); + return info; + } + case D3DFMT_A8L8: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 8, 8, 0, 0, Format::ID::L8A8_UNORM); + return info; + } + case D3DFMT_A4R4G4B4: + { + static const D3DFormat info(16, 1, 1, 4, 4, 4, 4, 0, 0, 0, Format::ID::B4G4R4A4_UNORM); + return info; + } + case D3DFMT_A1R5G5B5: + { + static const D3DFormat info(16, 1, 1, 5, 5, 5, 1, 0, 0, 0, Format::ID::B5G5R5A1_UNORM); + return info; + } + case D3DFMT_R5G6B5: + { + static const D3DFormat info(16, 1, 1, 5, 6, 5, 0, 0, 0, 0, Format::ID::R5G6B5_UNORM); + return info; + } + case D3DFMT_X8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 0, 0, 0, 0, Format::ID::B8G8R8X8_UNORM); + return info; + } + case D3DFMT_A8R8G8B8: + { + static const D3DFormat info(32, 1, 1, 8, 8, 8, 8, 0, 0, 0, Format::ID::B8G8R8A8_UNORM); + return info; + } + + case D3DFMT_R16F: + { + static const D3DFormat info(16, 1, 1, 16, 0, 0, 0, 0, 0, 0, Format::ID::R16_FLOAT); + return info; + } + case D3DFMT_G16R16F: + { + static const D3DFormat info(32, 1, 1, 16, 16, 0, 0, 0, 0, 0, Format::ID::R16G16_FLOAT); + return info; + } + case D3DFMT_A16B16G16R16F: + { + static const D3DFormat info(64, 1, 1, 16, 16, 16, 16, 0, 0, 0, + Format::ID::R16G16B16A16_FLOAT); + return info; + } + case D3DFMT_R32F: + { + static const D3DFormat info(32, 1, 1, 32, 0, 0, 0, 0, 0, 0, Format::ID::R32_FLOAT); + return info; + } + case D3DFMT_G32R32F: + { + static const D3DFormat info(64, 1, 1, 32, 32, 0, 0, 0, 0, 0, Format::ID::R32G32_FLOAT); + return info; + } + case D3DFMT_A32B32G32R32F: + { + static const D3DFormat info(128, 1, 1, 32, 32, 32, 32, 0, 0, 0, + Format::ID::R32G32B32A32_FLOAT); + return info; + } + + case D3DFMT_D16: + { + static const D3DFormat info(16, 1, 1, 0, 0, 0, 0, 0, 16, 0, Format::ID::D16_UNORM); + return info; + } + case D3DFMT_D24S8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 8, + Format::ID::D24_UNORM_S8_UINT); + return info; + } + case D3DFMT_D24X8: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 24, 0, Format::ID::D16_UNORM); + return info; + } + case D3DFMT_D32: + { + static const D3DFormat info(32, 1, 1, 0, 0, 0, 0, 0, 32, 0, Format::ID::D32_UNORM); + return info; + } + + case D3DFMT_DXT1: + { + static const D3DFormat info(64, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC1_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT3: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC2_RGBA_UNORM_BLOCK); + return info; + } + case D3DFMT_DXT5: + { + static const D3DFormat info(128, 4, 4, 0, 0, 0, 0, 0, 0, 0, + Format::ID::BC3_RGBA_UNORM_BLOCK); + return info; + } + + default: + { + static const D3DFormat defaultInfo; + return defaultInfo; + } + } +} typedef std::pair InternalFormatInitialzerPair; typedef std::map InternalFormatInitialzerMap; static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() { + using namespace angle; // For image initialization functions + InternalFormatInitialzerMap map; map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData)); @@ -175,28 +231,6 @@ static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() return map; } -// Each GL internal format corresponds to one D3D format and data loading function. -// Due to not all formats being available all the time, some of the function/format types are wrapped -// in templates that perform format support queries on a Renderer9 object which is supplied -// when requesting the function or format. - -typedef bool(*FallbackPredicateFunction)(); - -template -static void FallbackLoad(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) -{ - if (pred()) - { - prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); - } - else - { - fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); - } -} - static void UnreachableLoad(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) @@ -210,7 +244,7 @@ typedef std::map D3D9FormatMap; TextureFormat::TextureFormat() : texFormat(D3DFMT_UNKNOWN), renderFormat(D3DFMT_UNKNOWN), - dataInitializerFunction(NULL), + dataInitializerFunction(nullptr), loadFunction(UnreachableLoad) { } @@ -224,7 +258,8 @@ static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalForma static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); - info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; + info.dataInitializerFunction = + (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : nullptr; info.loadFunction = loadFunction; @@ -233,8 +268,11 @@ static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalForma static D3D9FormatMap BuildD3D9FormatMap() { + using namespace angle; // For image loading functions + D3D9FormatMap map; + // clang-format off // | Internal format | Texture format | Render format | Load function | InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); @@ -268,11 +306,11 @@ static D3D9FormatMap BuildD3D9FormatMap() InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); - InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadA8ToBGRA8 ); InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); - InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 ); InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); @@ -291,6 +329,7 @@ static D3D9FormatMap BuildD3D9FormatMap() // then changing the format and loading function appropriately. InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative ); InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative ); + // clang-format on return map; } @@ -503,7 +542,7 @@ public: VertexFormat::VertexFormat() : conversionType(VERTEX_CONVERT_NONE), outputElementSize(0), - copyFunction(NULL), + copyFunction(nullptr), nativeFormat(D3DDECLTYPE_UNUSED), componentType(GL_NONE) { 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 c55010760d..1bef320b53 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h @@ -15,6 +15,8 @@ #include "common/platform.h" #include "libANGLE/angletypes.h" #include "libANGLE/formatutils.h" +#include "libANGLE/renderer/Format.h" +#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h" namespace rx @@ -25,11 +27,22 @@ class Renderer9; namespace d3d9 { -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; - struct D3DFormat { D3DFormat(); + D3DFormat(GLuint pixelBytes, + GLuint blockWidth, + GLuint blockHeight, + GLuint redBits, + GLuint greenBits, + GLuint blueBits, + GLuint alphaBits, + GLuint luminanceBits, + GLuint depthBits, + GLuint stencilBits, + angle::Format::ID formatID); + + const angle::Format &info() const { return angle::Format::Get(formatID); } GLuint pixelBytes; GLuint blockWidth; @@ -44,14 +57,9 @@ struct D3DFormat GLuint depthBits; GLuint stencilBits; - GLenum internalFormat; - - MipGenerationFunction mipGenerationFunction; - ColorReadFunction colorReadFunction; - - FastCopyFunctionMap fastCopyFunctions; - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; + angle::Format::ID formatID; }; + const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); struct VertexFormat 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 8622dc4d13..fd451a6e51 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 @@ -17,7 +17,9 @@ #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 "libANGLE/renderer/driver_utils.h" +#include "platform/Platform.h" +#include "platform/WorkaroundsD3D.h" #include "third_party/systeminfo/SystemInfo.h" @@ -133,21 +135,22 @@ D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) return d3dWrap; } -D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +D3DCULL ConvertCullMode(gl::CullFaceMode cullFace, GLenum frontFace) { D3DCULL cull = D3DCULL_CCW; switch (cullFace) { - case GL_FRONT: - cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); - break; - case GL_BACK: - cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); - break; - case GL_FRONT_AND_BACK: - cull = D3DCULL_NONE; // culling will be handled during draw - break; - default: UNREACHABLE(); + case gl::CullFaceMode::Front: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case gl::CullFaceMode::Back: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case gl::CullFaceMode::FrontAndBack: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: + UNREACHABLE(); } return cull; @@ -264,6 +267,21 @@ void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DT } } +D3DQUERYTYPE ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + return D3DQUERYTYPE_OCCLUSION; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return D3DQUERYTYPE_EVENT; + default: + UNREACHABLE(); + return static_cast(0); + } +} + D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) { return (samples > 1) ? static_cast(samples) : D3DMULTISAMPLE_NONE; @@ -291,8 +309,8 @@ GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) { - GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; - GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat; + GLenum convertedFormat = gl::GetSizedInternalFormatInfo(internalFormat).format; return convertedFormat == format; } @@ -302,7 +320,7 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3 gl::TextureCaps textureCaps; const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) { @@ -333,7 +351,8 @@ static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3 { D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); - HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); + HRESULT result = d3d9->CheckDeviceMultiSampleType( + adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr); if (SUCCEEDED(result)) { textureCaps.sampleCounts.insert(i); @@ -364,18 +383,17 @@ void GenerateCaps(IDirect3D9 *d3d9, d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); GLuint maxSamples = 0; - const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); - for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + for (GLenum internalFormat : gl::GetAllSizedInternalFormats()) { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, - currentDisplayMode.Format); - textureCapsMap->insert(*internalFormat, textureCaps); + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType, + adapter, currentDisplayMode.Format); + textureCapsMap->insert(internalFormat, textureCaps); maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); - if (gl::GetInternalFormatInfo(*internalFormat).compressed) + if (gl::GetSizedInternalFormatInfo(internalFormat).compressed) { - caps->compressedTextureFormats.push_back(*internalFormat); + caps->compressedTextureFormats.push_back(internalFormat); } } @@ -444,6 +462,8 @@ void GenerateCaps(IDirect3D9 *d3d9, // Vertex shader limits caps->maxVertexAttributes = 16; + // Vertex Attrib Binding not supported. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; caps->maxVertexUniformVectors = @@ -525,12 +545,12 @@ void GenerateCaps(IDirect3D9 *d3d9, { // ATI cards on XP have problems with non-power-of-two textures. extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && - !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && - !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && - !(!isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId)); // Disable depth texture support on AMD cards (See ANGLE issue 839) - if (adapterId.VendorId == VENDOR_ID_AMD) + if (IsAMD(adapterId.VendorId)) { extensions->depthTextures = false; } @@ -548,18 +568,21 @@ void GenerateCaps(IDirect3D9 *d3d9, extensions->maxTextureAnisotropy = static_cast(deviceCaps.MaxAnisotropy); // Check occlusion query support by trying to create one - IDirect3DQuery9 *occlusionQuery = NULL; + IDirect3DQuery9 *occlusionQuery = nullptr; extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; SafeRelease(occlusionQuery); // Check event query support by trying to create one - IDirect3DQuery9 *eventQuery = NULL; + IDirect3DQuery9 *eventQuery = nullptr; extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; SafeRelease(eventQuery); - extensions->timerQuery = false; // Unimplemented extensions->disjointTimerQuery = false; extensions->robustness = true; + // It seems that only DirectX 10 and higher enforce the well-defined behavior of always + // returning zero values when out-of-bounds reads. See + // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt + extensions->robustBufferAccessBehavior = false; extensions->blendMinMax = true; extensions->framebufferBlit = true; extensions->framebufferMultisample = true; @@ -575,10 +598,11 @@ void GenerateCaps(IDirect3D9 *d3d9, extensions->colorBufferFloat = false; extensions->debugMarker = true; extensions->eglImage = true; + extensions->eglImageExternal = true; extensions->unpackSubimage = true; extensions->packSubimage = true; - extensions->vertexArrayObject = true; - extensions->noError = true; + extensions->syncQuery = extensions->fence; + extensions->copyTexture = true; // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil // state. @@ -625,15 +649,23 @@ void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsize *levelOffset = upsampleCount; } -WorkaroundsD3D GenerateWorkarounds() +angle::WorkaroundsD3D GenerateWorkarounds() { - WorkaroundsD3D workarounds; + angle::WorkaroundsD3D workarounds; workarounds.mrtPerfWorkaround = true; workarounds.setDataFasterThanImageUpload = false; workarounds.useInstancedPointSpriteEmulation = false; + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + workarounds.expandIntegerPowExpressions = true; + + // Call platform hooks for testing overrides. + auto *platform = ANGLEPlatformCurrent(); + platform->overrideWorkaroundsD3D(platform, &workarounds); + return workarounds; } -} +} // namespace d3d9 -} +} // namespace rx 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 aa494adb62..5b65b8910a 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 @@ -10,9 +10,10 @@ #ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ #define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ -#include "libANGLE/angletypes.h" +#include "common/Color.h" #include "libANGLE/Caps.h" #include "libANGLE/Error.h" +#include "platform/WorkaroundsD3D.h" namespace gl { @@ -22,7 +23,6 @@ class FramebufferAttachment; namespace rx { class RenderTarget9; -struct WorkaroundsD3D; namespace gl_d3d9 { @@ -33,12 +33,13 @@ D3DBLEND ConvertBlendFunc(GLenum blend); D3DBLENDOP ConvertBlendOp(GLenum blendOp); D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); -D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +D3DCULL ConvertCullMode(gl::CullFaceMode 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 *d3dLodBias, float maxAnisotropy, size_t baseLevel); +D3DQUERYTYPE ConvertQueryType(GLenum queryType); D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); @@ -86,9 +87,9 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -WorkaroundsD3D GenerateWorkarounds(); +angle::WorkaroundsD3D GenerateWorkarounds(); } -} +} // namespace d3d9 #endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps index dc357d0fa6..ecc593cc78 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps @@ -24,6 +24,23 @@ float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; }; +float4 luminancepremultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 luma = tex2D(tex, texcoord.xy).xxxw; + luma.rgb *= luma.a; + return luma * mult + add; +}; + +float4 luminanceunmultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 luma = tex2D(tex, texcoord.xy).xxxw; + if (luma.a > 0.0f) + { + luma.rgb /= luma.a; + } + return luma * mult + add; +}; + // RGB/A Component Mask Pixel Shader // Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. // Returns data in the form of rgba @@ -31,3 +48,20 @@ float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR { return tex2D(tex, texcoord.xy) * mult + add; }; + +float4 componentmaskpremultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 color = tex2D(tex, texcoord.xy); + color.rgb *= color.a; + return color * mult + add; +}; + +float4 componentmaskunmultps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 color = tex2D(tex, texcoord.xy); + if (color.a > 0.0f) + { + color.rgb /= color.a; + } + return color * mult + add; +}; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs index 3a36980b93..c68395a69c 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs @@ -11,6 +11,7 @@ struct VS_OUTPUT }; uniform float4 halfPixelSize : c0; +uniform float4 texcoordOffset : c1; // Standard Vertex Shader // Input 0 is the homogenous position. @@ -22,22 +23,7 @@ VS_OUTPUT standardvs(in float4 position : POSITION) VS_OUTPUT Out; Out.position = position + halfPixelSize; - Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); - - return Out; -}; - -// Flip Y Vertex Shader -// Input 0 is the homogenous position. -// Outputs the homogenous position as-is. -// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right. -// C0.XY must be the half-pixel width and height. C0.ZW must be 0. -VS_OUTPUT flipyvs(in float4 position : POSITION) -{ - VS_OUTPUT Out; - - Out.position = position + halfPixelSize; - Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + Out.texcoord = ((position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0)) * float4(texcoordOffset.zw, 1.0, 1.0)) + float4(texcoordOffset.xy, 0, 0); return Out; }; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp deleted file mode 100644 index e1c955eb06..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// 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. -// - -// formatutils9.cpp: Queries for GL image formats and their translations to D3D -// formats. - -#include "libANGLE/renderer/d3d/formatutilsD3D.h" - -#include - -#include "common/debug.h" -#include "libANGLE/renderer/d3d/imageformats.h" -#include "libANGLE/renderer/d3d/copyimage.h" - -namespace rx -{ - -typedef std::pair FormatTypePair; -typedef std::pair FormatWriteFunctionPair; -typedef std::map FormatWriteFunctionMap; - -static inline void InsertFormatWriteFunctionMapping(FormatWriteFunctionMap *map, GLenum format, GLenum type, - ColorWriteFunction writeFunc) -{ - map->insert(FormatWriteFunctionPair(FormatTypePair(format, type), writeFunc)); -} - -static FormatWriteFunctionMap BuildFormatWriteFunctionMap() -{ - FormatWriteFunctionMap map; - - // | Format | Type | Color write function | - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_FLOAT, WriteColor); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT, WriteColor); - InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, WriteColor); - - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_INT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_INT, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RG, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT_OES, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_INT, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RED, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT_OES, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_SHORT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_INT, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT, WriteColor ); - 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_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor ); - InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor ); - - InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, NULL ); - - InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); - - InsertFormatWriteFunctionMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, NULL ); - - InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL ); - InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL ); - - return map; -} - -ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type) -{ - static const FormatWriteFunctionMap formatTypeMap = BuildFormatWriteFunctionMap(); - FormatWriteFunctionMap::const_iterator iter = formatTypeMap.find(FormatTypePair(format, type)); - ASSERT(iter != formatTypeMap.end()); - if (iter != formatTypeMap.end()) - { - return iter->second; - } - else - { - return NULL; - } -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h index 6dd59ca94b..a245a0432f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h @@ -15,24 +15,15 @@ #include #include -namespace rx -{ - -typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); +#include -typedef void (*LoadImageFunction)(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); - -typedef void (*InitializeTextureDataFunction)(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -typedef void (*ColorReadFunction)(const uint8_t *source, uint8_t *dest); -typedef void (*ColorWriteFunction)(const uint8_t *source, uint8_t *dest); -typedef void (*ColorCopyFunction)(const uint8_t *source, uint8_t *dest); +namespace gl +{ +struct FormatType; +} +namespace rx +{ typedef void (*VertexCopyFunction)(const uint8_t *input, size_t stride, size_t count, uint8_t *output); enum VertexConversionType @@ -42,9 +33,6 @@ enum VertexConversionType VERTEX_CONVERT_GPU = 2, VERTEX_CONVERT_BOTH = 3 }; - -ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type); - -} +} // namespace rx #endif // LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h deleted file mode 100644 index 398ef26b30..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// 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. -// - -// generatemip.h: Defines the GenerateMip function, templated on the format -// type of the image for which mip levels are being generated. - -#ifndef LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ -#define LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ - -#include "libANGLE/renderer/d3d/imageformats.h" -#include "libANGLE/angletypes.h" - -namespace rx -{ - -template -inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - -} - -#include "generatemip.inl" - -#endif // LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl deleted file mode 100644 index 265783641e..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl +++ /dev/null @@ -1,266 +0,0 @@ -// -// 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. -// - -// generatemip.inl: Defines the GenerateMip function, templated on the format -// type of the image for which mip levels are being generated. - -#include "common/mathutil.h" - -namespace rx -{ - -namespace priv -{ - -template -static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); -} - -template -static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); -} - -template -static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth == 1); - - for (size_t y = 0; y < destHeight; y++) - { - const T *src0 = GetPixel(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, y, 0, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth == 1); - - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, 0, 0, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - const T *src0 = GetPixel(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, 0, z, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth == 1); - - for (size_t y = 0; y < destHeight; y++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, y, 0, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t y = 0; y < destHeight; y++) - { - const T *src0 = GetPixel(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, y, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, 0, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t y = 0; y < destHeight; y++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src4 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src5 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src6 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src7 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, y, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(&tmp2, src4, src5); - T::average(&tmp3, src6, src7); - - T::average(&tmp4, &tmp0, &tmp1); - T::average(&tmp5, &tmp2, &tmp3); - - T::average(dst, &tmp4, &tmp5); - } - } - } -} - - -typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - -template -static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) -{ - uint8_t index = ((sourceWidth > 1) ? 1 : 0) | - ((sourceHeight > 1) ? 2 : 0) | - ((sourceDepth > 1) ? 4 : 0); - - switch (index) - { - case 0: return NULL; - case 1: return GenerateMip_X; // W x 1 x 1 - case 2: return GenerateMip_Y; // 1 x H x 1 - case 3: return GenerateMip_XY; // W x H x 1 - case 4: return GenerateMip_Z; // 1 x 1 x D - case 5: return GenerateMip_XZ; // W x 1 x D - case 6: return GenerateMip_YZ; // 1 x H x D - case 7: return GenerateMip_XYZ; // W x H x D - } - - UNREACHABLE(); - return NULL; -} - -} - -template -inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - size_t mipWidth = std::max(1, sourceWidth >> 1); - size_t mipHeight = std::max(1, sourceHeight >> 1); - size_t mipDepth = std::max(1, sourceDepth >> 1); - - priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction(sourceWidth, sourceHeight, sourceDepth); - ASSERT(generationFunction != NULL); - - generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, - mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h deleted file mode 100644 index 76f1830e64..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h +++ /dev/null @@ -1,1999 +0,0 @@ -// -// 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. -// - -// imageformats.h: Defines image format types with functions for mip generation -// and copying. - -#ifndef LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ -#define LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ - -#include "libANGLE/angletypes.h" - -#include "common/mathutil.h" - -namespace rx -{ - -// Several structures share functionality for reading, writing or mipmapping but the layout -// must match the texture format which the structure represents. If collapsing or typedefing -// structs in this header, make sure the functionality and memory layout is exactly the same. - -struct L8 -{ - unsigned char L; - - static void readColor(gl::ColorF *dst, const L8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = 1.0f; - } - - static void writeColor(L8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - } - - static void average(L8 *dst, const L8 *src1, const L8 *src2) - { - dst->L = gl::average(src1->L, src2->L); - } -}; - -struct R8 -{ - unsigned char R; - - static void readColor(gl::ColorF *dst, const R8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R8 *dst, const R8 *src1, const R8 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct A8 -{ - unsigned char A; - - static void readColor(gl::ColorF *dst, const A8 *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(A8 *dst, const gl::ColorF *src) - { - dst->A = gl::floatToNormalized(src->alpha); - } - - static void average(A8 *dst, const A8 *src1, const A8 *src2) - { - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct L8A8 -{ - unsigned char L; - unsigned char A; - - static void readColor(gl::ColorF *dst, const L8A8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(L8A8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -struct A8L8 -{ - unsigned char A; - unsigned char L; - - static void readColor(gl::ColorF *dst, const A8L8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(A8L8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -struct R8G8 -{ - unsigned char R; - unsigned char G; - - static void readColor(gl::ColorF *dst, const R8G8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8G8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8G8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R8G8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -struct R8G8B8 -{ - unsigned char R; - unsigned char G; - unsigned char B; - - static void readColor(gl::ColorF *dst, const R8G8B8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8G8B8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->G; - dst->alpha = 1; - } - - static void writeColor(R8G8B8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R8G8B8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *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); - } -}; - -struct B8G8R8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - - static void readColor(gl::ColorF *dst, const B8G8R8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const B8G8R8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->G; - dst->alpha = 1; - } - - static void writeColor(B8G8R8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(B8G8R8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *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); - } -}; - -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) - { - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); - dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); - dst->alpha = 1.0f; - } - - static void writeColor(R5G6B5 *dst, const gl::ColorF *src) - { - dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | - gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | - gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); - } - - static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) - { - dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), gl::getShiftedData<5, 11>(src2->RGB))) | - gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), gl::getShiftedData<6, 5>(src2->RGB))) | - gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), gl::getShiftedData<5, 0>(src2->RGB))); - } -}; - -struct A8R8G8B8 -{ - unsigned char A; - unsigned char R; - unsigned char G; - unsigned char B; - - static void readColor(gl::ColorF *dst, const A8R8G8B8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -struct R8G8B8A8 -{ - unsigned char R; - unsigned char G; - unsigned char B; - unsigned char A; - - static void readColor(gl::ColorF *dst, const R8G8B8A8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -struct B8G8R8A8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - unsigned char A; - - static void readColor(gl::ColorF *dst, const B8G8R8A8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -struct B8G8R8X8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - unsigned char X; - - static void readColor(gl::ColorF *dst, const B8G8R8X8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->X = 255; - } - - static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->X = 255; - } - - static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - dst->X = 255; - } -}; - -struct A1R5G5B5 -{ - unsigned short ARGB; - - static void readColor(gl::ColorF *dst, const A1R5G5B5 *src) - { - 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(A1R5G5B5 *dst, const gl::ColorF *src) - { - 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(A1R5G5B5 *dst, const A1R5G5B5 *src1, const A1R5G5B5 *src2) - { - 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->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<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<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 -{ - // 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>(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->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->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 short ARGB; - - static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) - { - 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->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->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))); - } -}; - -struct R16 -{ - unsigned short R; - - static void readColor(gl::ColorF *dst, const R16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R16 *dst, const R16 *src1, const R16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R16G16 -{ - unsigned short R; - unsigned short G; - - static void readColor(gl::ColorF *dst, const R16G16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16G16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16G16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R16G16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R16G16B16 -{ - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const R16G16B16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16G16B16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R16G16B16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R16G16B16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *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); - } -}; - -struct R16G16B16A16 -{ - unsigned short R; - unsigned short G; - unsigned short B; - unsigned short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *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 R32 -{ - unsigned int R; - - static void readColor(gl::ColorF *dst, const R32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R32 *dst, const R32 *src1, const R32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R32G32 -{ - unsigned int R; - unsigned int G; - - static void readColor(gl::ColorF *dst, const R32G32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32G32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32G32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R32G32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32 -{ - unsigned int R; - unsigned int G; - unsigned int B; - - static void readColor(gl::ColorF *dst, const R32G32B32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32G32B32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R32G32B32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R32G32B32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *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); - } -}; - -struct R32G32B32A32 -{ - unsigned int R; - unsigned int G; - unsigned int B; - unsigned int A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *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 R8S -{ - char R; - - static void readColor(gl::ColorF *dst, const R8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R8S *dst, const R8S *src1, const R8S *src2) - { - dst->R = static_cast(gl::average(src1->R, src2->R)); - } -}; - -struct R8G8S -{ - char R; - char G; - - static void readColor(gl::ColorF *dst, const R8G8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8G8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8G8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R8G8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) - { - dst->R = static_cast(gl::average(src1->R, src2->R)); - dst->G = static_cast(gl::average(src1->G, src2->G)); - } -}; - -struct R8G8B8S -{ - char R; - char G; - char B; - - static void readColor(gl::ColorF *dst, const R8G8B8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8G8B8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R8G8B8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R8G8B8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) - { - 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)); - } -}; - -struct R8G8B8A8S -{ - char R; - char G; - char B; - char A; - - static void readColor(gl::ColorF *dst, const R8G8B8A8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R8G8B8A8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) - { - 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)); - } -}; - -struct R16S -{ - short R; - - static void readColor(gl::ColorF *dst, const R16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R16S *dst, const R16S *src1, const R16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R16G16S -{ - short R; - short G; - - static void readColor(gl::ColorF *dst, const R16G16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16G16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16G16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R16G16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R16G16B16S -{ - short R; - short G; - short B; - - static void readColor(gl::ColorF *dst, const R16G16B16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16G16B16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R16G16B16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R16G16B16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *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); - } -}; - -struct R16G16B16A16S -{ - short R; - short G; - short B; - short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R16G16B16A16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *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 R32S -{ - int R; - - static void readColor(gl::ColorF *dst, const R32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R32S *dst, const R32S *src1, const R32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R32G32S -{ - int R; - int G; - - static void readColor(gl::ColorF *dst, const R32G32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32G32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32G32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R32G32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32S -{ - int R; - int G; - int B; - - static void readColor(gl::ColorF *dst, const R32G32B32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32G32B32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R32G32B32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R32G32B32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *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); - } -}; - -struct R32G32B32A32S -{ - int R; - int G; - int B; - int A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R32G32B32A32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *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 A16B16G16R16F -{ - unsigned short A; - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const A16B16G16R16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16G16B16A16F -{ - unsigned short R; - unsigned short G; - unsigned short B; - unsigned short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16F -{ - unsigned short R; - - static void readColor(gl::ColorF *dst, const R16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - } - - static void average(R16F *dst, const R16F *src1, const R16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - } -}; - -struct A16F -{ - unsigned short A; - - static void readColor(gl::ColorF *dst, const A16F *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(A16F *dst, const gl::ColorF *src) - { - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(A16F *dst, const A16F *src1, const A16F *src2) - { - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct L16F -{ - unsigned short L; - - static void readColor(gl::ColorF *dst, const L16F *src) - { - float lum = gl::float16ToFloat32(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = 1.0f; - } - - static void writeColor(L16F *dst, const gl::ColorF *src) - { - dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); - } - - static void average(L16F *dst, const L16F *src1, const L16F *src2) - { - dst->L = gl::averageHalfFloat(src1->L, src2->L); - } -}; - -struct L16A16F -{ - unsigned short L; - unsigned short A; - - static void readColor(gl::ColorF *dst, const L16A16F *src) - { - float lum = gl::float16ToFloat32(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(L16A16F *dst, const gl::ColorF *src) - { - dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) - { - dst->L = gl::averageHalfFloat(src1->L, src2->L); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16G16F -{ - unsigned short R; - unsigned short G; - - static void readColor(gl::ColorF *dst, const R16G16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R16G16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - } - - static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - } -}; - -struct R16G16B16F -{ - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const R16G16B16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = 1.0f; - } - - static void writeColor(R16G16B16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - } - - static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - } -}; - -struct A32B32G32R32F -{ - float A; - float R; - float G; - float B; - - static void readColor(gl::ColorF *dst, const A32B32G32R32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - dst->A = src->alpha; - } - - static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *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 R32G32B32A32F -{ - float R; - float G; - float B; - float A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - dst->A = src->alpha; - } - - static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *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 R32F -{ - float R; - - static void readColor(gl::ColorF *dst, const R32F *src) - { - dst->red = src->R; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - } - - static void average(R32F *dst, const R32F *src1, const R32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct A32F -{ - float A; - - static void readColor(gl::ColorF *dst, const A32F *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = src->A; - } - - static void writeColor(A32F *dst, const gl::ColorF *src) - { - dst->A = src->alpha; - } - - static void average(A32F *dst, const A32F *src1, const A32F *src2) - { - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct L32F -{ - float L; - - static void readColor(gl::ColorF *dst, const L32F *src) - { - dst->red = src->L; - dst->green = src->L; - dst->blue = src->L; - dst->alpha = 1.0f; - } - - static void writeColor(L32F *dst, const gl::ColorF *src) - { - dst->L = (src->red + src->green + src->blue) / 3.0f; - } - - static void average(L32F *dst, const L32F *src1, const L32F *src2) - { - dst->L = gl::average(src1->L, src2->L); - } -}; - -struct L32A32F -{ - float L; - float A; - - static void readColor(gl::ColorF *dst, const L32A32F *src) - { - dst->red = src->L; - dst->green = src->L; - dst->blue = src->L; - dst->alpha = src->A; - } - - static void writeColor(L32A32F *dst, const gl::ColorF *src) - { - dst->L = (src->red + src->green + src->blue) / 3.0f; - dst->A = src->alpha; - } - - static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) - { - dst->L = gl::average(src1->L, src2->L); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32G32F -{ - float R; - float G; - - static void readColor(gl::ColorF *dst, const R32G32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R32G32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - } - - static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32F -{ - float R; - float G; - float B; - - static void readColor(gl::ColorF *dst, const R32G32B32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1.0f; - } - - static void writeColor(R32G32B32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - } - - static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *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); - } -}; - -struct R10G10B10A2 -{ - unsigned int R : 10; - unsigned int G : 10; - unsigned int B : 10; - unsigned int A : 2; - - static void readColor(gl::ColorF *dst, const R10G10B10A2 *src) - { - dst->red = gl::normalizedToFloat<10>(src->R); - dst->green = gl::normalizedToFloat<10>(src->G); - dst->blue = gl::normalizedToFloat<10>(src->B); - dst->alpha = gl::normalizedToFloat< 2>(src->A); - } - - static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized<10, unsigned int>(src->red); - dst->G = gl::floatToNormalized<10, unsigned int>(src->green); - dst->B = gl::floatToNormalized<10, unsigned int>(src->blue); - dst->A = gl::floatToNormalized< 2, unsigned int>(src->alpha); - } - - static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *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 R9G9B9E5 -{ - unsigned int R : 9; - unsigned int G : 9; - unsigned int B : 9; - unsigned int E : 5; - - static void readColor(gl::ColorF *dst, const R9G9B9E5 *src) - { - gl::convert999E5toRGBFloats(gl::bitCast(*src), &dst->red, &dst->green, &dst->blue); - dst->alpha = 1.0f; - } - - static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src) - { - *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(src->red, - src->green, - src->blue); - } - - static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) - { - float r1, g1, b1; - gl::convert999E5toRGBFloats(*reinterpret_cast(src1), &r1, &g1, &b1); - - float r2, g2, b2; - gl::convert999E5toRGBFloats(*reinterpret_cast(src2), &r2, &g2, &b2); - - *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(gl::average(r1, r2), - gl::average(g1, g2), - gl::average(b1, b2)); - } -}; - -struct R11G11B10F -{ - unsigned int R : 11; - unsigned int G : 11; - unsigned int B : 10; - - static void readColor(gl::ColorF *dst, const R11G11B10F *src) - { - dst->red = gl::float11ToFloat32(src->R); - dst->green = gl::float11ToFloat32(src->G); - dst->blue = gl::float10ToFloat32(src->B); - dst->alpha = 1.0f; - } - - static void writeColor(R11G11B10F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat11(src->red); - dst->G = gl::float32ToFloat11(src->green); - dst->B = gl::float32ToFloat10(src->blue); - } - - static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) - { - dst->R = gl::averageFloat11(src1->R, src2->R); - dst->G = gl::averageFloat11(src1->G, src2->G); - dst->B = gl::averageFloat10(src1->B, src2->B); - } -}; - -} - -#endif // LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp deleted file mode 100644 index b9b9e5e4ab..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp +++ /dev/null @@ -1,697 +0,0 @@ -// -// 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.cpp: Defines image loading functions. - -#include "libANGLE/renderer/d3d/loadimage.h" - -namespace rx -{ - -void LoadA8ToRGBA8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = static_cast(source[x]) << 24; - } - } - } -} - -void LoadA8ToBGRA8(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) -{ - // Same as loading to RGBA - LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadA32FToRGBA32F(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 float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0.0f; - dest[4 * x + 1] = 0.0f; - dest[4 * x + 2] = 0.0f; - dest[4 * x + 3] = source[x]; - } - } - } -} - -void LoadA16FToRGBA16F(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[4 * x + 0] = 0; - dest[4 * x + 1] = 0; - dest[4 * x + 2] = 0; - dest[4 * x + 3] = source[x]; - } - } - } -} - -void LoadL8ToRGBA8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint8_t sourceVal = source[x]; - dest[4 * x + 0] = sourceVal; - dest[4 * x + 1] = sourceVal; - dest[4 * x + 2] = sourceVal; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadL8ToBGRA8(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) -{ - // Same as loading to RGBA - LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadL32FToRGBA32F(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 float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x]; - dest[4 * x + 1] = source[x]; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 1.0f; - } - } - } -} - -void LoadL16FToRGBA16F(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[4 * x + 0] = source[x]; - dest[4 * x + 1] = source[x]; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = gl::Float16One; - } - } - } -} - -void LoadLA8ToRGBA8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = source[2 * x + 0]; - dest[4 * x + 1] = source[2 * x + 0]; - dest[4 * x + 2] = source[2 * x + 0]; - dest[4 * x + 3] = source[2 * x + 1]; - } - } - } -} - -void LoadLA8ToBGRA8(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) -{ - // Same as loading to RGBA - LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadLA32FToRGBA32F(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 float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = source[2 * x + 0]; - dest[4 * x + 1] = source[2 * x + 0]; - dest[4 * x + 2] = source[2 * x + 0]; - dest[4 * x + 3] = source[2 * x + 1]; - } - } - } -} - -void LoadLA16FToRGBA16F(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[4 * x + 0] = source[2 * x + 0]; - dest[4 * x + 1] = source[2 * x + 0]; - dest[4 * x + 2] = source[2 * x + 0]; - dest[4 * x + 3] = source[2 * x + 1]; - } - } - } -} - -void LoadRGB8ToBGRX8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = source[x * 3 + 2]; - dest[4 * x + 1] = source[x * 3 + 1]; - dest[4 * x + 2] = source[x * 3 + 0]; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadRG8ToBGRX8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0x00; - dest[4 * x + 1] = source[x * 2 + 1]; - dest[4 * x + 2] = source[x * 2 + 0]; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadR8ToBGRX8(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 uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0x00; - dest[4 * x + 1] = 0x00; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadR5G6B5ToBGRA8(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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgb = source[x]; - 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; - } - } - } -} - -void LoadR5G6B5ToRGBA8(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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgb = source[x]; - 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; - } - } - } -} - -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) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t rgba = source[x]; - dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } - } -} - -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) -{ - 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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - 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)); - } - } - } -} - -void LoadRGBA4ToRGBA8(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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - 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)); - } - } - } -} - -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) -{ - 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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t bgra = source[x]; - 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); - } - } - } -} - -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) -{ - 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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - 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); - } - } - } -} - -void LoadRGB5A1ToRGBA8(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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - 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) -{ - 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); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t bgra = source[x]; - 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); - } - } - } -} - -void LoadRGB10A2ToRGBA8(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 uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t rgba = source[x]; - 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); - } - } - } -} - -void LoadRGB16FToRGB9E5(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); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), - gl::float16ToFloat32(source[x * 3 + 1]), - gl::float16ToFloat32(source[x * 3 + 2])); - } - } - } -} - -void LoadRGB32FToRGB9E5(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 float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], source[x * 3 + 2]); - } - } - } -} - -void LoadRGB16FToRG11B10F(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); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | - (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | - (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); - } - } - } -} - -void LoadRGB32FToRG11B10F(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 float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | - (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | - (gl::float32ToFloat10(source[x * 3 + 2]) << 22); - } - } - } -} - -void LoadG8R24ToR24G8(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 uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t d = source[x] >> 8; - uint8_t s = source[x] & 0xFF; - dest[x] = d | (s << 24); - } - } - } -} - -void LoadRGB32FToRGBA16F(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 float *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 * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); - dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); - dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); - dest[x * 4 + 3] = gl::Float16One; - } - } - } -} - -void LoadR32ToR16(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 uint32_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] = source[x] >> 16; - } - } - } -} - -void LoadR32ToR24G8(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 uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x++) - { - dest[x] = source[x] >> 8; - } - } - } -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h deleted file mode 100644 index 6c5118365e..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h +++ /dev/null @@ -1,201 +0,0 @@ -// -// 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.h: Defines image loading functions - -#ifndef LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ -#define LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ - -#include "libANGLE/angletypes.h" - -#include - -namespace rx -{ - -void LoadA8ToRGBA8(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 LoadA8ToBGRA8(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 LoadA8ToBGRA8_SSE2(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 LoadA32FToRGBA32F(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 LoadA16FToRGBA16F(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 LoadL8ToRGBA8(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 LoadL8ToBGRA8(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 LoadL32FToRGBA32F(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 LoadL16FToRGBA16F(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 LoadLA8ToRGBA8(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 LoadLA8ToBGRA8(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 LoadLA32FToRGBA32F(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 LoadLA16FToRGBA16F(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 LoadRGB8ToBGRX8(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 LoadRG8ToBGRX8(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 LoadR8ToBGRX8(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 LoadR5G6B5ToBGRA8(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 LoadR5G6B5ToRGBA8(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 LoadRGBA8ToBGRA8_SSE2(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 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); - -void LoadRGBA4ToRGBA8(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 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); - -void LoadRGB5A1ToRGBA8(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 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); - -void LoadRGB10A2ToRGBA8(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 LoadRGB16FToRGB9E5(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 LoadRGB32FToRGB9E5(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 LoadRGB16FToRG11B10F(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 LoadRGB32FToRG11B10F(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 LoadG8R24ToR24G8(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); - -template -inline void LoadToNative(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); - -template -inline void LoadToNative3To4(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); - -template -inline void Load32FTo16F(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 LoadRGB32FToRGBA16F(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); - -template -inline void LoadCompressedToNative(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 LoadR32ToR16(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); - -template -inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR32ToR24G8(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); - -template -inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); - -template -inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); - -} - -#include "loadimage.inl" - -#endif // LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl deleted file mode 100644 index 920e667db1..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) 2014-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 "common/mathutil.h" - -namespace rx -{ - -template -inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); -} - -template -inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); -} - -template -inline void LoadToNative(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) -{ - const size_t rowSize = width * sizeof(type) * componentCount; - const size_t layerSize = rowSize * height; - const size_t imageSize = layerSize * depth; - - if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) - { - ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); - memcpy(output, input, imageSize); - } - else if (rowSize == inputRowPitch && rowSize == outputRowPitch) - { - for (size_t z = 0; z < depth; z++) - { - const type *source = OffsetDataPointer(input, 0, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, 0, z, outputRowPitch, outputDepthPitch); - - memcpy(dest, source, layerSize); - } - } - else - { - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - memcpy(dest, source, width * sizeof(type) * componentCount); - } - } - } -} - -template -inline void LoadToNative3To4(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) -{ - const type fourthValue = gl::bitCast(fourthComponentBits); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x * 4 + 0] = source[x * 3 + 0]; - dest[x * 4 + 1] = source[x * 3 + 1]; - dest[x * 4 + 2] = source[x * 3 + 2]; - dest[x * 4 + 3] = fourthValue; - } - } - } -} - -template -inline void Load32FTo16F(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) -{ - const size_t elementWidth = componentCount * width; - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < elementWidth; x++) - { - dest[x] = gl::float32ToFloat16(source[x]); - } - } - } -} - -template -inline void LoadCompressedToNative(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) -{ - const size_t columns = (width + (blockWidth - 1)) / blockWidth; - const size_t rows = (height + (blockHeight - 1)) / blockHeight; - - for (size_t z = 0; z < depth; ++z) - { - for (size_t y = 0; y < rows; ++y) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - memcpy(dest, source, columns * blockSize); - } - } -} - -template -inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - type writeValues[4] = - { - gl::bitCast(firstBits), - gl::bitCast(secondBits), - gl::bitCast(thirdBits), - gl::bitCast(fourthBits), - }; - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - type *destRow = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - type* destPixel = destRow + x * 4; - - // This could potentially be optimized by generating an entire row of initialization - // data and copying row by row instead of pixel by pixel. - memcpy(destPixel, writeValues, sizeof(type) * 4); - } - } - } -} - -} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp deleted file mode 100644 index c87d35c82b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// -// 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. -// - -// loadimageSSE2.cpp: Defines image loading functions. It's -// in a separated file for GCC, which can enable SSE usage only per-file, -// not for code blocks that use SSE2 explicitly. - -#include "libANGLE/renderer/d3d/loadimage.h" - -#include "common/platform.h" - -#ifdef ANGLE_USE_SSE -#include -#endif - -namespace rx -{ - -void LoadA8ToBGRA8_SSE2(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) -{ -#if defined(ANGLE_USE_SSE) - __m128i zeroWide = _mm_setzero_si128(); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - size_t x = 0; - - // Make output writes aligned - for (; ((reinterpret_cast(&dest[x]) & 0xF) != 0 && x < width); x++) - { - dest[x] = static_cast(source[x]) << 24; - } - - for (; x + 7 < width; x += 8) - { - __m128i sourceData = _mm_loadl_epi64(reinterpret_cast(&source[x])); - // Interleave each byte to 16bit, make the lower byte to zero - sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); - // Interleave each 16bit to 32bit, make the lower 16bit to zero - __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); - __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); - - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); - } - - // Handle the remainder - for (; x < width; x++) - { - dest[x] = static_cast(source[x]) << 24; - } - } - } -#else - // Ensure that this function is reported as not implemented for ARM builds because - // the instructions below are not present for that architecture. - UNIMPLEMENTED(); - return; -#endif -} - -void LoadRGBA8ToBGRA8_SSE2(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) -{ -#if defined(ANGLE_USE_SSE) - __m128i brMask = _mm_set1_epi32(0x00ff00ff); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - size_t x = 0; - - // Make output writes aligned - for (; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) - { - uint32_t rgba = source[x]; - dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - - for (; x + 3 < width; x += 4) - { - __m128i sourceData = _mm_loadu_si128(reinterpret_cast(&source[x])); - // Mask out g and a, which don't change - __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); - // Mask out b and r - __m128i brComponents = _mm_and_si128(sourceData, brMask); - // Swap b and r - __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); - __m128i result = _mm_or_si128(gaComponents, brSwapped); - _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); - } - - // Perform leftover writes - for (; x < width; x++) - { - uint32_t rgba = source[x]; - dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } - } -#else - // Ensure that this function is reported as not implemented for ARM builds because - // the instructions below are not present for that architecture. - UNIMPLEMENTED(); - return; -#endif -} - -} - diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp deleted file mode 100644 index 26a3b32ce0..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.cpp +++ /dev/null @@ -1,1435 +0,0 @@ -// -// 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 deleted file mode 100644 index dc64e0461b..0000000000 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage_etc.h +++ /dev/null @@ -1,140 +0,0 @@ -// -// 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/renderer/driver_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp new file mode 100644 index 0000000000..d97b8e7c22 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.cpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// driver_utils.h : provides more information about current driver. + +#include + +#include "libANGLE/renderer/driver_utils.h" + +namespace rx +{ +// Intel +// Referenced from https://cgit.freedesktop.org/vaapi/intel-driver/tree/src/i965_pciids.h +namespace +{ +// gen7 +const uint32_t Haswell[] = { + 0x0402, 0x0406, 0x040A, 0x040B, 0x040E, 0x0C02, 0x0C06, 0x0C0A, 0x0C0B, 0x0C0E, + 0x0A02, 0x0A06, 0x0A0A, 0x0A0B, 0x0A0E, 0x0D02, 0x0D06, 0x0D0A, 0x0D0B, 0x0D0E, // hsw_gt1 + 0x0412, 0x0416, 0x041A, 0x041B, 0x041E, 0x0C12, 0x0C16, 0x0C1A, 0x0C1B, 0x0C1E, + 0x0A12, 0x0A16, 0x0A1A, 0x0A1B, 0x0A1E, 0x0D12, 0x0D16, 0x0D1A, 0x0D1B, 0x0D1E, // hsw_gt2 + 0x0422, 0x0426, 0x042A, 0x042B, 0x042E, 0x0C22, 0x0C26, 0x0C2A, 0x0C2B, 0x0C2E, + 0x0A22, 0x0A26, 0x0A2A, 0x0A2B, 0x0A2E, 0x0D22, 0x0D26, 0x0D2A, 0x0D2B, 0x0D2E // hsw_gt3 +}; + +// gen8 +const uint32_t Broadwell[] = {0x1602, 0x1606, 0x160A, 0x160B, 0x160D, 0x160E, + 0x1612, 0x1616, 0x161A, 0x161B, 0x161D, 0x161E, + 0x1622, 0x1626, 0x162A, 0x162B, 0x162D, 0x162E}; + +const uint32_t CherryView[] = {0x22B0, 0x22B1, 0x22B2, 0x22B3}; + +// gen9 +const uint32_t Skylake[] = {0x1902, 0x1906, 0x190A, 0x190B, 0x190E, 0x1912, 0x1913, 0x1915, 0x1916, + 0x1917, 0x191A, 0x191B, 0x191D, 0x191E, 0x1921, 0x1923, 0x1926, 0x1927, + 0x192A, 0x192B, 0x192D, 0x1932, 0x193A, 0x193B, 0x193D}; + +const uint32_t Broxton[] = {0x0A84, 0x1A84, 0x1A85, 0x5A84, 0x5A85}; + +// gen9p5 +const uint32_t Kabylake[] = {0x5916, 0x5913, 0x5906, 0x5926, 0x5921, 0x5915, 0x590E, + 0x591E, 0x5912, 0x5917, 0x5902, 0x591B, 0x593B, 0x590B, + 0x591A, 0x590A, 0x591D, 0x5908, 0x5923, 0x5927}; + +} // anonymous namespace + +IntelDriverVersion::IntelDriverVersion(uint16_t lastPart) : mVersionPart(lastPart) +{ +} + +bool IntelDriverVersion::operator==(const IntelDriverVersion &version) +{ + return mVersionPart == version.mVersionPart; +} + +bool IntelDriverVersion::operator!=(const IntelDriverVersion &version) +{ + return !(*this == version); +} + +bool IntelDriverVersion::operator<(const IntelDriverVersion &version) +{ + // See http://www.intel.com/content/www/us/en/support/graphics-drivers/000005654.html to + // understand the Intel graphics driver version number on Windows. + // mVersionPart1 changes with OS version. mVersionPart2 changes with DirectX version. + // mVersionPart3 stands for release year. mVersionPart4 is driver specific unique version + // number. + // For example: Intel driver version '20.19.15.4539' + // 20 -> windows 10 driver + // 19 -> DirectX 12 first version(12.0) supported + // 15 -> Driver released in 2015 + // 4539 -> Driver specific unique version number + // For linux, Intel graphics driver version is the mesa version. The version number has three + // parts: major revision, minor revision, release number. So, for linux, we need to compare + // three parts. + // Currently, it's only used in windows. So, checking the last part is enough. Once it's needed + // in other platforms, it's easy to be extended. + return mVersionPart < version.mVersionPart; +} + +bool IntelDriverVersion::operator>=(const IntelDriverVersion &version) +{ + return !(*this < version); +} + +bool IsHaswell(uint32_t DeviceId) +{ + return std::find(std::begin(Haswell), std::end(Haswell), DeviceId) != std::end(Haswell); +} + +bool IsBroadwell(uint32_t DeviceId) +{ + return std::find(std::begin(Broadwell), std::end(Broadwell), DeviceId) != std::end(Broadwell); +} + +bool IsCherryView(uint32_t DeviceId) +{ + return std::find(std::begin(CherryView), std::end(CherryView), DeviceId) != + std::end(CherryView); +} + +bool IsSkylake(uint32_t DeviceId) +{ + return std::find(std::begin(Skylake), std::end(Skylake), DeviceId) != std::end(Skylake); +} + +bool IsBroxton(uint32_t DeviceId) +{ + return std::find(std::begin(Broxton), std::end(Broxton), DeviceId) != std::end(Broxton); +} + +bool IsKabylake(uint32_t DeviceId) +{ + return std::find(std::begin(Kabylake), std::end(Kabylake), DeviceId) != std::end(Kabylake); +} + +} // namespace rx \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h new file mode 100644 index 0000000000..62bdc502fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/driver_utils.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// driver_utils.h : provides more information about current driver. + +#ifndef LIBANGLE_RENDERER_DRIVER_UTILS_H_ +#define LIBANGLE_RENDERER_DRIVER_UTILS_H_ + +#include "libANGLE/angletypes.h" + +namespace rx +{ + +enum VendorID : uint32_t +{ + VENDOR_ID_UNKNOWN = 0x0, + VENDOR_ID_AMD = 0x1002, + VENDOR_ID_INTEL = 0x8086, + VENDOR_ID_NVIDIA = 0x10DE, + // This is Qualcomm PCI Vendor ID. + // Android doesn't have a PCI bus, but all we need is a unique id. + VENDOR_ID_QUALCOMM = 0x5143, +}; + +inline bool IsAMD(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_AMD; +} + +inline bool IsIntel(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_INTEL; +} + +inline bool IsNvidia(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_NVIDIA; +} + +inline bool IsQualcomm(uint32_t vendor_id) +{ + return vendor_id == VENDOR_ID_QUALCOMM; +} + +// Intel +class IntelDriverVersion +{ + public: + // Currently, We only provide the constructor with one parameter. It mainly used in Intel + // version number on windows. If you want to use this class on other platforms, it's easy to + // be extended. + IntelDriverVersion(uint16_t lastPart); + bool operator==(const IntelDriverVersion &); + bool operator!=(const IntelDriverVersion &); + bool operator<(const IntelDriverVersion &); + bool operator>=(const IntelDriverVersion &); + + private: + uint16_t mVersionPart; +}; + +bool IsHaswell(uint32_t DeviceId); +bool IsBroadwell(uint32_t DeviceId); +bool IsCherryView(uint32_t DeviceId); +bool IsSkylake(uint32_t DeviceId); +bool IsBroxton(uint32_t DeviceId); +bool IsKabylake(uint32_t DeviceId); + +} // namespace rx +#endif // LIBANGLE_RENDERER_DRIVER_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json new file mode 100644 index 0000000000..198274998c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_data.json @@ -0,0 +1,602 @@ +{ + "GL_RG8_SNORM": { + "R8G8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_SRGB8": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_RGBA8I": { + "R8G8B8A8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R8_SNORM": { + "R8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_RGBA8_SNORM": { + "R8G8B8A8_SNORM": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R16I": { + "R16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGBA8ToSRGBA8" + } + }, + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8A1ToRGBA8" + } + }, + "GL_RGB32UI": { + "R32G32B32A32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative3To4" + } + }, + "GL_ALPHA32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadA32FToRGBA32F" + } + }, + "GL_R16UI": { + "R16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB9_E5": { + "R9G9B9E5_SHAREDEXP": { + "GL_HALF_FLOAT": "LoadRGB16FToRGB9E5", + "GL_UNSIGNED_INT_5_9_9_9_REV": "LoadToNative", + "GL_FLOAT": "LoadRGB32FToRGB9E5", + "GL_HALF_FLOAT_OES": "LoadRGB16FToRGB9E5" + } + }, + "GL_COMPRESSED_R11_EAC": { + "R8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadEACR11ToR8" + } + }, + "GL_RGBA32UI": { + "R32G32B32A32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_RG8UI": { + "R8G8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadL32FToRGBA32F" + } + }, + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8A1ToRGBA8" + } + }, + "GL_R16F": { + "R16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<1>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_RGBA8UI": { + "R8G8B8A8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_BGRA4_ANGLEX": { + "NONE": { + "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT": "LoadRGBA4ToRGBA8", + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGBA16F": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<4>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_LUMINANCE8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadL8ToRGBA8" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_RGB": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_5_6_5": "UnreachableLoadFunction" + } + }, + "GL_RGB5_A1": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadRGB10A2ToRGBA8", + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_5_5_5_1": "LoadRGB5A1ToRGBA8" + }, + "B5G5R5A1_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadRGB10A2ToBGR5A1", + "GL_UNSIGNED_BYTE": "LoadRGBA8ToBGR5A1", + "GL_UNSIGNED_SHORT_5_5_5_1": "LoadRGB5A1ToA1RGB5" + } + }, + "GL_RGB16UI": { + "R16G16B16A16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative3To4" + } + }, + "GL_BGRA_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + } + }, + "GL_COMPRESSED_RGB8_ETC2": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8ToRGBA8" + } + }, + "GL_RGBA32F": { + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_RGBA32I": { + "R32G32B32A32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_LUMINANCE8_ALPHA8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadLA8ToRGBA8" + } + }, + "GL_RG8": { + "R8G8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGB10_A2": { + "R10G10B10A2_UNORM": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadToNative" + } + }, + "GL_COMPRESSED_SIGNED_RG11_EAC": { + "R8G8_SNORM": { + "GL_UNSIGNED_BYTE": "LoadEACRG11SToRG8" + } + }, + "GL_DEPTH_COMPONENT16": { + "D16_UNORM": { + "GL_UNSIGNED_INT": "LoadR32ToR16", + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB32I": { + "R32G32B32A32_SINT": { + "GL_INT": "LoadToNative3To4" + } + }, + "GL_R8": { + "R8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_RGB32F": { + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadToNative3To4" + } + }, + "GL_R11F_G11F_B10F": { + "R11G11B10_FLOAT": { + "GL_UNSIGNED_INT_10F_11F_11F_REV": "LoadToNative", + "GL_HALF_FLOAT": "LoadRGB16FToRG11B10F", + "GL_FLOAT": "LoadRGB32FToRG11B10F", + "GL_HALF_FLOAT_OES": "LoadRGB16FToRG11B10F" + } + }, + "GL_RGB8": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_LUMINANCE_ALPHA": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadLA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadLA32FToRGBA32F" + } + }, + "GL_RGBA16I": { + "R16G16B16A16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_R8I": { + "R8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_RGB8_SNORM": { + "R8G8B8A8_SNORM": { + "GL_BYTE": "LoadToNative3To4" + } + }, + "GL_RG32F": { + "R32G32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_DEPTH_COMPONENT32F": { + "D32_FLOAT": { + "GL_FLOAT": "LoadD32FToD32F" + } + }, + "GL_RG32I": { + "R32G32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_ALPHA8_EXT": { + "A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + }, + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadA8ToRGBA8" + } + }, + "GL_RG32UI": { + "R32G32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_RGBA16UI": { + "R16G16B16A16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_RGBA8_ETC2_EAC": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC2RGBA8ToRGBA8" + } + }, + "GL_RGB8I": { + "R8G8B8A8_SINT": { + "GL_BYTE": "LoadToNative3To4" + } + }, + "GL_COMPRESSED_SRGB8_ETC2": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8ToRGBA8" + } + }, + "GL_DEPTH32F_STENCIL8": { + "D32_FLOAT_S8X24_UINT": { + "GL_FLOAT_32_UNSIGNED_INT_24_8_REV": "LoadD32FS8X24ToD32FS8X24" + } + }, + "GL_RG8I": { + "R8G8_SINT": { + "GL_BYTE": "LoadToNative" + } + }, + "GL_R32UI": { + "R32_UINT": { + "GL_UNSIGNED_INT": "LoadToNative" + } + }, + "GL_BGR5_A1_ANGLEX": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT": "LoadRGB5A1ToRGBA8" + } + }, + "GL_BGR565_ANGLEX": { + "B5G6R5_UNORM": { + "GL_UNSIGNED_SHORT_5_6_5": "LoadRGB565ToBGR565", + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_COMPRESSED_RG11_EAC": { + "R8G8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadEACRG11ToRG8" + } + }, + "GL_SRGB8_ALPHA8": { + "R8G8B8A8_UNORM_SRGB": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE_ALPHA16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadLA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadLA16FToRGBA16F" + } + }, + "GL_RGBA": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_4_4_4_4": "UnreachableLoadFunction", + "GL_UNSIGNED_SHORT_5_5_5_1": "UnreachableLoadFunction" + } + }, + "GL_DEPTH24_STENCIL8": { + "D24_UNORM_S8_UINT": { + "GL_UNSIGNED_INT_24_8": "LoadR32ToR24G8" + } + }, + "GL_RGB16I": { + "R16G16B16A16_SINT": { + "GL_SHORT": "LoadToNative3To4" + } + }, + "GL_R8UI": { + "R8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_ALPHA": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadA32FToRGBA32F" + } + }, + "GL_RGB16F": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative3To4", + "GL_FLOAT": "LoadRGB32FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadToNative3To4" + } + }, + "GL_COMPRESSED_SIGNED_R11_EAC": { + "R8_SNORM": { + "GL_UNSIGNED_BYTE": "LoadEACR11SToR8" + } + }, + "GL_COMPRESSED_RGB_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_STENCIL_INDEX8": { + "NONE": { + "GL_UNSIGNED_BYTE": "UnimplementedLoadFunction" + } + }, + "GL_LUMINANCE_ALPHA32F_EXT": { + "NONE": { + "GL_FLOAT": "LoadLA32FToRGBA32F" + } + }, + "GL_RGB8UI": { + "R8G8B8A8_UINT": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4" + } + }, + "GL_DEPTH_COMPONENT24": { + "D24_UNORM_S8_UINT": { + "GL_UNSIGNED_INT": "LoadR32ToR24G8" + } + }, + "GL_R32I": { + "R32_SINT": { + "GL_INT": "LoadToNative" + } + }, + "GL_DEPTH_COMPONENT32_OES": { + "NONE": { + "GL_UNSIGNED_INT": "LoadR32ToR24G8" + } + }, + "GL_R32F": { + "R32_FLOAT": { + "GL_FLOAT": "LoadToNative" + } + }, + "GL_RG16F": { + "R16G16_FLOAT": { + "GL_HALF_FLOAT": "LoadToNative", + "GL_FLOAT": "Load32FTo16F<2>", + "GL_HALF_FLOAT_OES": "LoadToNative" + } + }, + "GL_RGB565": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative3To4", + "GL_UNSIGNED_SHORT_5_6_5": "LoadR5G6B5ToRGBA8" + }, + "B5G6R5_UNORM": { + "GL_UNSIGNED_BYTE": "LoadRGB8ToBGR565", + "GL_UNSIGNED_SHORT_5_6_5": "LoadToNative" + } + }, + "GL_LUMINANCE16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadL16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F" + } + }, + "GL_RG16UI": { + "R16G16_UINT": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_RG16I": { + "R16G16_SINT": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_BGRA8_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_ALPHA16F_EXT": { + "NONE": { + "GL_HALF_FLOAT": "LoadA16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadA16FToRGBA16F" + } + }, + "GL_RGBA4": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative", + "GL_UNSIGNED_SHORT_4_4_4_4": "LoadRGBA4ToRGBA8" + }, + "B4G4R4A4_UNORM": { + "GL_UNSIGNED_BYTE": "LoadRGBA8ToBGRA4", + "GL_UNSIGNED_SHORT_4_4_4_4": "LoadRGBA4ToARGB4" + } + }, + "GL_RGBA8": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadToNative" + } + }, + "GL_LUMINANCE": { + "R16G16B16A16_FLOAT": { + "GL_HALF_FLOAT": "LoadL16FToRGBA16F", + "GL_HALF_FLOAT_OES": "LoadL16FToRGBA16F" + }, + "NONE": { + "GL_UNSIGNED_BYTE": "UnreachableLoadFunction" + }, + "R32G32B32A32_FLOAT": { + "GL_FLOAT": "LoadL32FToRGBA32F" + } + }, + "GL_RGB10_A2UI": { + "R10G10B10A2_UINT": { + "GL_UNSIGNED_INT_2_10_10_10_REV": "LoadToNative" + } + }, + "GL_ETC1_RGB8_OES": { + "R8G8B8A8_UNORM": { + "GL_UNSIGNED_BYTE": "LoadETC1RGB8ToRGBA8" + } + }, + "GL_ETC1_RGB8_LOSSY_DECODE_ANGLE": { + "BC1_RGB_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC1RGB8ToBC1" + } + }, + "GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGB_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8ToBC1" + } + }, + "GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGB_UNORM_SRGB_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8ToBC1" + } + }, + "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGBA_UNORM_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2RGB8A1ToBC1" + } + }, + "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE": { + "BC1_RGBA_UNORM_SRGB_BLOCK": { + "GL_UNSIGNED_BYTE": "LoadETC2SRGB8A1ToBC1" + } + }, + "GL_R16_EXT": { + "R16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RG16_EXT": { + "R16G16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_RGB16_EXT": { + "R16G16B16A16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative3To4" + } + }, + "GL_RGBA16_EXT": { + "R16G16B16A16_UNORM": { + "GL_UNSIGNED_SHORT": "LoadToNative" + } + }, + "GL_R16_SNORM_EXT": { + "R16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_RG16_SNORM_EXT": { + "R16G16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_RGB16_SNORM_EXT": { + "R16G16B16A16_SNORM": { + "GL_SHORT": "LoadToNative3To4" + } + }, + "GL_RGBA16_SNORM_EXT": { + "R16G16B16A16_SNORM": { + "GL_SHORT": "LoadToNative" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + }, + "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 8>" + } + }, + "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT": { + "NONE": { + "GL_UNSIGNED_BYTE": "LoadCompressedToNative<4, 4, 16>" + } + } +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h new file mode 100644 index 0000000000..f3da31c100 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table.h @@ -0,0 +1,22 @@ +// +// 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 ANGLE format. +// + +#ifndef LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ +#define LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ + +#include "libANGLE/renderer/Format.h" + +namespace angle +{ + +rx::LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, Format::ID angleFormat); + +} // namespace angle + +#endif // LIBANGLE_RENDERER_LOADFUNCTIONSTABLE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp new file mode 100644 index 0000000000..ed9fe2864c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/load_functions_table_autogen.cpp @@ -0,0 +1,2459 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_load_functions_table.py using data from load_functions_data.json +// +// Copyright 2016 The ANGLE Project 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/load_functions_table.h" + +#include "image_util/copyimage.h" +#include "image_util/generatemip.h" +#include "image_util/loadimage.h" + +using namespace rx; + +namespace angle +{ + +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(); +} + +LoadImageFunctionInfo ALPHA_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadA32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadA16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadA32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA8_EXT_to_A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ALPHA8_EXT_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGR565_ANGLEX_to_B5G6R5_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadRGB565ToBGR565, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGR5_A1_ANGLEX_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + return LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA4_ANGLEX_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo BGRA_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_R11_EAC_to_R8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACR11ToR8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RG11_EAC_to_R8G8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACRG11ToRG8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_ETC2_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo +COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGB8A1ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA8_ETC2_EAC_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2RGBA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT3_ANGLE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGBA_S3TC_DXT5_ANGLE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_RGB_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SIGNED_R11_EAC_to_R8_SNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACR11SToR8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SIGNED_RG11_EAC_to_R8G8_SNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadEACRG11SToRG8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGBA8ToSRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK( + GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo +COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK( + GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC2SRGB8A1ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 16>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo COMPRESSED_SRGB_S3TC_DXT1_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadCompressedToNative<4, 4, 8>, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH24_STENCIL8_to_D24_UNORM_S8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_24_8: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH32F_STENCIL8_to_D32_FLOAT_S8X24_UINT(GLenum type) +{ + switch (type) + { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return LoadImageFunctionInfo(LoadD32FS8X24ToD32FS8X24, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT16_to_D16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR16, true); + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT32F_to_D32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadD32FToD32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo DEPTH_COMPONENT32_OES_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadR32ToR24G8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ETC1_RGB8_LOSSY_DECODE_ANGLE_to_BC1_RGB_UNORM_BLOCK(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC1RGB8ToBC1, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo ETC1_RGB8_OES_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadETC1RGB8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadL32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadL16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadL32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE8_ALPHA8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadLA8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE8_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadL8ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA16F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadLA16FToRGBA16F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo LUMINANCE_ALPHA32F_EXT_to_default(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadLA32FToRGBA32F, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R11F_G11F_B10F_to_R11G11B10_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRG11B10F, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadRGB16FToRG11B10F, true); + case GL_UNSIGNED_INT_10F_11F_11F_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16F_to_R16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<1>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16I_to_R16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16UI_to_R16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16_EXT_to_R16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R16_SNORM_EXT_to_R16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32F_to_R32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32I_to_R32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R32UI_to_R32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8_to_R8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8I_to_R8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8UI_to_R8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo R8_SNORM_to_R8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16F_to_R16G16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<2>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16I_to_R16G16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16UI_to_R16G16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16_EXT_to_R16G16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG16_SNORM_EXT_to_R16G16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32F_to_R32G32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32I_to_R32G32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG32UI_to_R32G32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8_to_R8G8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8I_to_R8G8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8UI_to_R8G8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RG8_SNORM_to_R8G8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB10_A2_to_R10G10B10A2_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB10_A2UI_to_R10G10B10A2_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16F_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRGBA16F, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16I_to_R16G16B16A16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16UI_to_R16G16B16A16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16_EXT_to_R16G16B16A16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB16_SNORM_EXT_to_R16G16B16A16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32F_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32I_to_R32G32B32A32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB32UI_to_R32G32B32A32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB565_to_B5G6R5_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGB8ToBGR565, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB565_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + case GL_UNSIGNED_SHORT_5_6_5: + return LoadImageFunctionInfo(LoadR5G6B5ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB5_A1_to_B5G5R5A1_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGBA8ToBGR5A1, true); + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadRGB10A2ToBGR5A1, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(LoadRGB5A1ToA1RGB5, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB5_A1_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_INT_2_10_10_10_REV: + return LoadImageFunctionInfo(LoadRGB10A2ToRGBA8, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(LoadRGB5A1ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8I_to_R8G8B8A8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8UI_to_R8G8B8A8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB8_SNORM_to_R8G8B8A8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGB9_E5_to_R9G9B9E5_SHAREDEXP(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadRGB32FToRGB9E5, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadRGB16FToRGB9E5, true); + case GL_UNSIGNED_INT_5_9_9_9_REV: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + case GL_UNSIGNED_SHORT_5_5_5_1: + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16F_to_R16G16B16A16_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(Load32FTo16F<4>, true); + case GL_HALF_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_HALF_FLOAT_OES: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16I_to_R16G16B16A16_SINT(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16UI_to_R16G16B16A16_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16_EXT_to_R16G16B16A16_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA16_SNORM_EXT_to_R16G16B16A16_SNORM(GLenum type) +{ + switch (type) + { + case GL_SHORT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32F_to_R32G32B32A32_FLOAT(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32I_to_R32G32B32A32_SINT(GLenum type) +{ + switch (type) + { + case GL_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA32UI_to_R32G32B32A32_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_INT: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA4_to_B4G4R4A4_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadRGBA8ToBGRA4, true); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(LoadRGBA4ToARGB4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA4_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + case GL_UNSIGNED_SHORT_4_4_4_4: + return LoadImageFunctionInfo(LoadRGBA4ToRGBA8, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8_to_R8G8B8A8_UNORM(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8I_to_R8G8B8A8_SINT(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8UI_to_R8G8B8A8_UINT(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo RGBA8_SNORM_to_R8G8B8A8_SNORM(GLenum type) +{ + switch (type) + { + case GL_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo SRGB8_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative3To4, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo SRGB8_ALPHA8_to_R8G8B8A8_UNORM_SRGB(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(LoadToNative, false); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +LoadImageFunctionInfo STENCIL_INDEX8_to_default(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return LoadImageFunctionInfo(UnimplementedLoadFunction, true); + default: + UNREACHABLE(); + return LoadImageFunctionInfo(UnreachableLoadFunction, true); + } +} + +} // namespace + +LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, Format::ID angleFormat) +{ + // clang-format off + switch (internalFormat) + { + case GL_ALPHA: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return ALPHA_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return ALPHA_to_R32G32B32A32_FLOAT; + default: + return ALPHA_to_default; + } + } + case GL_ALPHA16F_EXT: + return ALPHA16F_EXT_to_default; + case GL_ALPHA32F_EXT: + return ALPHA32F_EXT_to_default; + case GL_ALPHA8_EXT: + { + switch (angleFormat) + { + case Format::ID::A8_UNORM: + return ALPHA8_EXT_to_A8_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return ALPHA8_EXT_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_BGR565_ANGLEX: + { + switch (angleFormat) + { + case Format::ID::B5G6R5_UNORM: + return BGR565_ANGLEX_to_B5G6R5_UNORM; + default: + break; + } + } + case GL_BGR5_A1_ANGLEX: + return BGR5_A1_ANGLEX_to_default; + case GL_BGRA4_ANGLEX: + return BGRA4_ANGLEX_to_default; + case GL_BGRA8_EXT: + return BGRA8_EXT_to_default; + case GL_BGRA_EXT: + return BGRA_EXT_to_default; + case GL_COMPRESSED_R11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8_UNORM: + return COMPRESSED_R11_EAC_to_R8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RG11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8_UNORM: + return COMPRESSED_RG11_EAC_to_R8G8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGB8_ETC2_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_BLOCK: + return COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGBA_UNORM_BLOCK: + return COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_RGBA8_ETC2_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return COMPRESSED_RGBA8_ETC2_EAC_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return COMPRESSED_RGBA_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return COMPRESSED_RGBA_S3TC_DXT3_ANGLE_to_default; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return COMPRESSED_RGBA_S3TC_DXT5_ANGLE_to_default; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return COMPRESSED_RGB_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_SIGNED_R11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8_SNORM: + return COMPRESSED_SIGNED_R11_EAC_to_R8_SNORM; + default: + break; + } + } + case GL_COMPRESSED_SIGNED_RG11_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8_SNORM: + return COMPRESSED_SIGNED_RG11_EAC_to_R8G8_SNORM; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_ETC2_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_SRGB_BLOCK: + return COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGB_UNORM_SRGB_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGBA_UNORM_SRGB_BLOCK: + return COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE_to_BC1_RGBA_UNORM_SRGB_BLOCK; + default: + break; + } + } + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT_to_default; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT_to_default; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT_to_default; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return COMPRESSED_SRGB_S3TC_DXT1_EXT_to_default; + case GL_DEPTH24_STENCIL8: + { + switch (angleFormat) + { + case Format::ID::D24_UNORM_S8_UINT: + return DEPTH24_STENCIL8_to_D24_UNORM_S8_UINT; + default: + break; + } + } + case GL_DEPTH32F_STENCIL8: + { + switch (angleFormat) + { + case Format::ID::D32_FLOAT_S8X24_UINT: + return DEPTH32F_STENCIL8_to_D32_FLOAT_S8X24_UINT; + default: + break; + } + } + case GL_DEPTH_COMPONENT16: + { + switch (angleFormat) + { + case Format::ID::D16_UNORM: + return DEPTH_COMPONENT16_to_D16_UNORM; + default: + break; + } + } + case GL_DEPTH_COMPONENT24: + { + switch (angleFormat) + { + case Format::ID::D24_UNORM_S8_UINT: + return DEPTH_COMPONENT24_to_D24_UNORM_S8_UINT; + default: + break; + } + } + case GL_DEPTH_COMPONENT32F: + { + switch (angleFormat) + { + case Format::ID::D32_FLOAT: + return DEPTH_COMPONENT32F_to_D32_FLOAT; + default: + break; + } + } + case GL_DEPTH_COMPONENT32_OES: + return DEPTH_COMPONENT32_OES_to_default; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + { + switch (angleFormat) + { + case Format::ID::BC1_RGB_UNORM_BLOCK: + return ETC1_RGB8_LOSSY_DECODE_ANGLE_to_BC1_RGB_UNORM_BLOCK; + default: + break; + } + } + case GL_ETC1_RGB8_OES: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return ETC1_RGB8_OES_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_LUMINANCE: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return LUMINANCE_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return LUMINANCE_to_R32G32B32A32_FLOAT; + default: + return LUMINANCE_to_default; + } + } + case GL_LUMINANCE16F_EXT: + return LUMINANCE16F_EXT_to_default; + case GL_LUMINANCE32F_EXT: + return LUMINANCE32F_EXT_to_default; + case GL_LUMINANCE8_ALPHA8_EXT: + return LUMINANCE8_ALPHA8_EXT_to_default; + case GL_LUMINANCE8_EXT: + return LUMINANCE8_EXT_to_default; + case GL_LUMINANCE_ALPHA: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return LUMINANCE_ALPHA_to_R16G16B16A16_FLOAT; + case Format::ID::R32G32B32A32_FLOAT: + return LUMINANCE_ALPHA_to_R32G32B32A32_FLOAT; + default: + return LUMINANCE_ALPHA_to_default; + } + } + case GL_LUMINANCE_ALPHA16F_EXT: + return LUMINANCE_ALPHA16F_EXT_to_default; + case GL_LUMINANCE_ALPHA32F_EXT: + return LUMINANCE_ALPHA32F_EXT_to_default; + case GL_R11F_G11F_B10F: + { + switch (angleFormat) + { + case Format::ID::R11G11B10_FLOAT: + return R11F_G11F_B10F_to_R11G11B10_FLOAT; + default: + break; + } + } + case GL_R16F: + { + switch (angleFormat) + { + case Format::ID::R16_FLOAT: + return R16F_to_R16_FLOAT; + default: + break; + } + } + case GL_R16I: + { + switch (angleFormat) + { + case Format::ID::R16_SINT: + return R16I_to_R16_SINT; + default: + break; + } + } + case GL_R16UI: + { + switch (angleFormat) + { + case Format::ID::R16_UINT: + return R16UI_to_R16_UINT; + default: + break; + } + } + case GL_R16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16_UNORM: + return R16_EXT_to_R16_UNORM; + default: + break; + } + } + case GL_R16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16_SNORM: + return R16_SNORM_EXT_to_R16_SNORM; + default: + break; + } + } + case GL_R32F: + { + switch (angleFormat) + { + case Format::ID::R32_FLOAT: + return R32F_to_R32_FLOAT; + default: + break; + } + } + case GL_R32I: + { + switch (angleFormat) + { + case Format::ID::R32_SINT: + return R32I_to_R32_SINT; + default: + break; + } + } + case GL_R32UI: + { + switch (angleFormat) + { + case Format::ID::R32_UINT: + return R32UI_to_R32_UINT; + default: + break; + } + } + case GL_R8: + { + switch (angleFormat) + { + case Format::ID::R8_UNORM: + return R8_to_R8_UNORM; + default: + break; + } + } + case GL_R8I: + { + switch (angleFormat) + { + case Format::ID::R8_SINT: + return R8I_to_R8_SINT; + default: + break; + } + } + case GL_R8UI: + { + switch (angleFormat) + { + case Format::ID::R8_UINT: + return R8UI_to_R8_UINT; + default: + break; + } + } + case GL_R8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8_SNORM: + return R8_SNORM_to_R8_SNORM; + default: + break; + } + } + case GL_RG16F: + { + switch (angleFormat) + { + case Format::ID::R16G16_FLOAT: + return RG16F_to_R16G16_FLOAT; + default: + break; + } + } + case GL_RG16I: + { + switch (angleFormat) + { + case Format::ID::R16G16_SINT: + return RG16I_to_R16G16_SINT; + default: + break; + } + } + case GL_RG16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16_UINT: + return RG16UI_to_R16G16_UINT; + default: + break; + } + } + case GL_RG16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16_UNORM: + return RG16_EXT_to_R16G16_UNORM; + default: + break; + } + } + case GL_RG16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16_SNORM: + return RG16_SNORM_EXT_to_R16G16_SNORM; + default: + break; + } + } + case GL_RG32F: + { + switch (angleFormat) + { + case Format::ID::R32G32_FLOAT: + return RG32F_to_R32G32_FLOAT; + default: + break; + } + } + case GL_RG32I: + { + switch (angleFormat) + { + case Format::ID::R32G32_SINT: + return RG32I_to_R32G32_SINT; + default: + break; + } + } + case GL_RG32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32_UINT: + return RG32UI_to_R32G32_UINT; + default: + break; + } + } + case GL_RG8: + { + switch (angleFormat) + { + case Format::ID::R8G8_UNORM: + return RG8_to_R8G8_UNORM; + default: + break; + } + } + case GL_RG8I: + { + switch (angleFormat) + { + case Format::ID::R8G8_SINT: + return RG8I_to_R8G8_SINT; + default: + break; + } + } + case GL_RG8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8_UINT: + return RG8UI_to_R8G8_UINT; + default: + break; + } + } + case GL_RG8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8_SNORM: + return RG8_SNORM_to_R8G8_SNORM; + default: + break; + } + } + case GL_RGB: + return RGB_to_default; + case GL_RGB10_A2: + { + switch (angleFormat) + { + case Format::ID::R10G10B10A2_UNORM: + return RGB10_A2_to_R10G10B10A2_UNORM; + default: + break; + } + } + case GL_RGB10_A2UI: + { + switch (angleFormat) + { + case Format::ID::R10G10B10A2_UINT: + return RGB10_A2UI_to_R10G10B10A2_UINT; + default: + break; + } + } + case GL_RGB16F: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return RGB16F_to_R16G16B16A16_FLOAT; + default: + break; + } + } + case GL_RGB16I: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SINT: + return RGB16I_to_R16G16B16A16_SINT; + default: + break; + } + } + case GL_RGB16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UINT: + return RGB16UI_to_R16G16B16A16_UINT; + default: + break; + } + } + case GL_RGB16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UNORM: + return RGB16_EXT_to_R16G16B16A16_UNORM; + default: + break; + } + } + case GL_RGB16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SNORM: + return RGB16_SNORM_EXT_to_R16G16B16A16_SNORM; + default: + break; + } + } + case GL_RGB32F: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_FLOAT: + return RGB32F_to_R32G32B32A32_FLOAT; + default: + break; + } + } + case GL_RGB32I: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_SINT: + return RGB32I_to_R32G32B32A32_SINT; + default: + break; + } + } + case GL_RGB32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_UINT: + return RGB32UI_to_R32G32B32A32_UINT; + default: + break; + } + } + case GL_RGB565: + { + switch (angleFormat) + { + case Format::ID::B5G6R5_UNORM: + return RGB565_to_B5G6R5_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGB565_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB5_A1: + { + switch (angleFormat) + { + case Format::ID::B5G5R5A1_UNORM: + return RGB5_A1_to_B5G5R5A1_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGB5_A1_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return RGB8_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGB8I: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SINT: + return RGB8I_to_R8G8B8A8_SINT; + default: + break; + } + } + case GL_RGB8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UINT: + return RGB8UI_to_R8G8B8A8_UINT; + default: + break; + } + } + case GL_RGB8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SNORM: + return RGB8_SNORM_to_R8G8B8A8_SNORM; + default: + break; + } + } + case GL_RGB9_E5: + { + switch (angleFormat) + { + case Format::ID::R9G9B9E5_SHAREDEXP: + return RGB9_E5_to_R9G9B9E5_SHAREDEXP; + default: + break; + } + } + case GL_RGBA: + return RGBA_to_default; + case GL_RGBA16F: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_FLOAT: + return RGBA16F_to_R16G16B16A16_FLOAT; + default: + break; + } + } + case GL_RGBA16I: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SINT: + return RGBA16I_to_R16G16B16A16_SINT; + default: + break; + } + } + case GL_RGBA16UI: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UINT: + return RGBA16UI_to_R16G16B16A16_UINT; + default: + break; + } + } + case GL_RGBA16_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_UNORM: + return RGBA16_EXT_to_R16G16B16A16_UNORM; + default: + break; + } + } + case GL_RGBA16_SNORM_EXT: + { + switch (angleFormat) + { + case Format::ID::R16G16B16A16_SNORM: + return RGBA16_SNORM_EXT_to_R16G16B16A16_SNORM; + default: + break; + } + } + case GL_RGBA32F: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_FLOAT: + return RGBA32F_to_R32G32B32A32_FLOAT; + default: + break; + } + } + case GL_RGBA32I: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_SINT: + return RGBA32I_to_R32G32B32A32_SINT; + default: + break; + } + } + case GL_RGBA32UI: + { + switch (angleFormat) + { + case Format::ID::R32G32B32A32_UINT: + return RGBA32UI_to_R32G32B32A32_UINT; + default: + break; + } + } + case GL_RGBA4: + { + switch (angleFormat) + { + case Format::ID::B4G4R4A4_UNORM: + return RGBA4_to_B4G4R4A4_UNORM; + case Format::ID::R8G8B8A8_UNORM: + return RGBA4_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGBA8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM: + return RGBA8_to_R8G8B8A8_UNORM; + default: + break; + } + } + case GL_RGBA8I: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SINT: + return RGBA8I_to_R8G8B8A8_SINT; + default: + break; + } + } + case GL_RGBA8UI: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UINT: + return RGBA8UI_to_R8G8B8A8_UINT; + default: + break; + } + } + case GL_RGBA8_SNORM: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_SNORM: + return RGBA8_SNORM_to_R8G8B8A8_SNORM; + default: + break; + } + } + case GL_SRGB8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return SRGB8_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_SRGB8_ALPHA8: + { + switch (angleFormat) + { + case Format::ID::R8G8B8A8_UNORM_SRGB: + return SRGB8_ALPHA8_to_R8G8B8A8_UNORM_SRGB; + default: + break; + } + } + case GL_STENCIL_INDEX8: + return STENCIL_INDEX8_to_default; + + default: + { + static LoadFunctionMap emptyLoadFunctionsMap; + return emptyLoadFunctionsMap; + } + } + // clang-format on + +} // GetLoadFunctionsMap + +} // namespace angle diff --git a/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp new file mode 100644 index 0000000000..55471c1d20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.cpp @@ -0,0 +1,549 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// renderer_utils: +// Helper methods pertaining to most or all back-ends. +// + +#include "libANGLE/renderer/renderer_utils.h" + +#include "image_util/copyimage.h" +#include "image_util/imageformats.h" + +#include "libANGLE/AttributeMap.h" +#include "libANGLE/Context.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/ContextImpl.h" +#include "libANGLE/renderer/Format.h" + +#include + +namespace rx +{ + +namespace +{ +typedef std::pair FormatWriteFunctionPair; +typedef std::map FormatWriteFunctionMap; + +static inline void InsertFormatWriteFunctionMapping(FormatWriteFunctionMap *map, + GLenum format, + GLenum type, + ColorWriteFunction writeFunc) +{ + map->insert(FormatWriteFunctionPair(gl::FormatType(format, type), writeFunc)); +} + +static FormatWriteFunctionMap BuildFormatWriteFunctionMap() +{ + using namespace angle; // For image writing functions + + FormatWriteFunctionMap map; + + // clang-format off + // | Format | Type | Color write function | + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT, + WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_SHORT, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_SHORT, + WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_SHORT, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_UNSIGNED_SHORT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_SHORT, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_UNSIGNED_SHORT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_SHORT, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT, WriteColor ); + 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_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, nullptr ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, nullptr ); + // clang-format on + + return map; +} + +void CopyColor(gl::ColorF *color) +{ + // No-op +} + +void PremultiplyAlpha(gl::ColorF *color) +{ + color->red *= color->alpha; + color->green *= color->alpha; + color->blue *= color->alpha; +} + +void UnmultiplyAlpha(gl::ColorF *color) +{ + if (color->alpha != 0.0f) + { + float invAlpha = 1.0f / color->alpha; + color->red *= invAlpha; + color->green *= invAlpha; + color->blue *= invAlpha; + } +} + +void ClipChannelsR(gl::ColorF *color) +{ + color->green = 0.0f; + color->blue = 0.0f; + color->alpha = 1.0f; +} + +void ClipChannelsRG(gl::ColorF *color) +{ + color->blue = 0.0f; + color->alpha = 1.0f; +} + +void ClipChannelsRGB(gl::ColorF *color) +{ + color->alpha = 1.0f; +} + +void ClipChannelsLuminance(gl::ColorF *color) +{ + color->alpha = 1.0f; +} + +void ClipChannelsAlpha(gl::ColorF *color) +{ + color->red = 0.0f; + color->green = 0.0f; + color->blue = 0.0f; +} + +void ClipChannelsNoOp(gl::ColorF *color) +{ +} + +void WriteUintColor(const gl::ColorF &color, + ColorWriteFunction colorWriteFunction, + uint8_t *destPixelData) +{ + gl::ColorUI destColor( + static_cast(color.red * 255), static_cast(color.green * 255), + static_cast(color.blue * 255), static_cast(color.alpha * 255)); + colorWriteFunction(reinterpret_cast(&destColor), destPixelData); +} + +void WriteFloatColor(const gl::ColorF &color, + ColorWriteFunction colorWriteFunction, + uint8_t *destPixelData) +{ + colorWriteFunction(reinterpret_cast(&color), destPixelData); +} + +} // anonymous namespace + +PackPixelsParams::PackPixelsParams() + : 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, + gl::Buffer *packBufferIn, + ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packBufferIn), + pack(), + offset(offsetIn) +{ + pack.alignment = packIn.alignment; + pack.reverseRowOrder = packIn.reverseRowOrder; +} + +void PackPixels(const PackPixelsParams ¶ms, + const angle::Format &sourceFormat, + int inputPitchIn, + const uint8_t *sourceIn, + uint8_t *destWithoutOffset) +{ + uint8_t *destWithOffset = destWithoutOffset + params.offset; + + const uint8_t *source = sourceIn; + int inputPitch = inputPitchIn; + + if (params.pack.reverseRowOrder) + { + source += inputPitch * (params.area.height - 1); + inputPitch = -inputPitch; + } + + const auto &sourceGLInfo = gl::GetSizedInternalFormatInfo(sourceFormat.glInternalFormat); + + if (sourceGLInfo.format == params.format && sourceGLInfo.type == params.type) + { + // Direct copy possible + for (int y = 0; y < params.area.height; ++y) + { + memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch, + params.area.width * sourceGLInfo.pixelBytes); + } + return; + } + + ASSERT(sourceGLInfo.sized); + + gl::FormatType formatType(params.format, params.type); + ColorCopyFunction fastCopyFunc = + GetFastCopyFunction(sourceFormat.fastCopyFunctions, formatType); + const auto &destFormatInfo = gl::GetInternalFormatInfo(formatType.format, formatType.type); + + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < params.area.height; ++y) + { + for (int x = 0; x < params.area.width; ++x) + { + uint8_t *dest = + destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + return; + } + + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(formatType); + + // Maximum size of any Color type used. + uint8_t temp[16]; + static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI), + "Unexpected size of gl::Color struct."); + + const auto &colorReadFunction = sourceFormat.colorReadFunction; + + for (int y = 0; y < params.area.height; ++y) + { + for (int x = 0; x < params.area.width; ++x) + { + uint8_t *dest = destWithOffset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceGLInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + colorReadFunction(src, temp); + colorWriteFunction(temp, dest); + } + } +} + +ColorWriteFunction GetColorWriteFunction(const gl::FormatType &formatType) +{ + static const FormatWriteFunctionMap formatTypeMap = BuildFormatWriteFunctionMap(); + auto iter = formatTypeMap.find(formatType); + ASSERT(iter != formatTypeMap.end()); + if (iter != formatTypeMap.end()) + { + return iter->second; + } + else + { + return nullptr; + } +} + +ColorCopyFunction GetFastCopyFunction(const FastCopyFunctionMap &fastCopyFunctions, + const gl::FormatType &formatType) +{ + return fastCopyFunctions.get(formatType); +} + +bool FastCopyFunctionMap::has(const gl::FormatType &formatType) const +{ + return (get(formatType) != nullptr); +} + +ColorCopyFunction FastCopyFunctionMap::get(const gl::FormatType &formatType) const +{ + for (size_t index = 0; index < mSize; ++index) + { + if (mData[index].format == formatType.format && mData[index].type == formatType.type) + { + return mData[index].func; + } + } + + return nullptr; +} + +bool ShouldUseDebugLayers(const egl::AttributeMap &attribs) +{ + EGLAttrib debugSetting = + attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); + +// Prefer to enable debug layers if compiling in Debug, and disabled in Release. +#if !defined(NDEBUG) + return (debugSetting != EGL_FALSE); +#else + return (debugSetting == EGL_TRUE); +#endif // !defined(NDEBUG) +} + +void CopyImageCHROMIUM(const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourcePixelBytes, + ColorReadFunction colorReadFunction, + uint8_t *destData, + size_t destRowPitch, + size_t destPixelBytes, + ColorWriteFunction colorWriteFunction, + GLenum destUnsizedFormat, + GLenum destComponentType, + size_t width, + size_t height, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha) +{ + using ConversionFunction = void (*)(gl::ColorF *); + ConversionFunction conversionFunction = CopyColor; + if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha) + { + if (unpackPremultiplyAlpha) + { + conversionFunction = PremultiplyAlpha; + } + else + { + conversionFunction = UnmultiplyAlpha; + } + } + + auto clipChannelsFunction = ClipChannelsNoOp; + switch (destUnsizedFormat) + { + case GL_RED: + clipChannelsFunction = ClipChannelsR; + break; + case GL_RG: + clipChannelsFunction = ClipChannelsRG; + break; + case GL_RGB: + clipChannelsFunction = ClipChannelsRGB; + break; + case GL_LUMINANCE: + clipChannelsFunction = ClipChannelsLuminance; + break; + case GL_ALPHA: + clipChannelsFunction = ClipChannelsAlpha; + break; + } + + auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor; + + for (size_t y = 0; y < height; y++) + { + for (size_t x = 0; x < width; x++) + { + const uint8_t *sourcePixelData = sourceData + y * sourceRowPitch + x * sourcePixelBytes; + + gl::ColorF sourceColor; + colorReadFunction(sourcePixelData, reinterpret_cast(&sourceColor)); + + conversionFunction(&sourceColor); + clipChannelsFunction(&sourceColor); + + size_t destY = 0; + if (unpackFlipY) + { + destY += (height - 1); + destY -= y; + } + else + { + destY += y; + } + + uint8_t *destPixelData = destData + destY * destRowPitch + x * destPixelBytes; + writeFunction(sourceColor, colorWriteFunction, destPixelData); + } + } +} + +// IncompleteTextureSet implementation. +IncompleteTextureSet::IncompleteTextureSet() +{ +} + +IncompleteTextureSet::~IncompleteTextureSet() +{ +} + +void IncompleteTextureSet::onDestroy(const gl::Context *context) +{ + // Clear incomplete textures. + for (auto &incompleteTexture : mIncompleteTextures) + { + ANGLE_SWALLOW_ERR(incompleteTexture.second->onDestroy(context)); + incompleteTexture.second.set(context, nullptr); + } + mIncompleteTextures.clear(); +} + +gl::Error IncompleteTextureSet::getIncompleteTexture( + const gl::Context *context, + GLenum type, + MultisampleTextureInitializer *multisampleInitializer, + gl::Texture **textureOut) +{ + auto iter = mIncompleteTextures.find(type); + if (iter != mIncompleteTextures.end()) + { + *textureOut = iter->second.get(); + return gl::NoError(); + } + + ContextImpl *implFactory = context->getImplementation(); + + const GLubyte color[] = {0, 0, 0, 255}; + const gl::Extents colorSize(1, 1, 1); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + const gl::Box area(0, 0, 0, 1, 1, 1); + + // If a texture is external use a 2D texture for the incomplete texture + GLenum createType = (type == GL_TEXTURE_EXTERNAL_OES) ? GL_TEXTURE_2D : type; + + gl::Texture *tex = new gl::Texture(implFactory, std::numeric_limits::max(), createType); + angle::UniqueObjectPointer t(tex, context); + + if (createType == GL_TEXTURE_2D_MULTISAMPLE) + { + ANGLE_TRY(t->setStorageMultisample(context, createType, 1, GL_RGBA8, colorSize, true)); + } + else + { + ANGLE_TRY(t->setStorage(context, createType, 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++) + { + ANGLE_TRY( + t->setSubImage(context, unpack, face, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color)); + } + } + else if (type == GL_TEXTURE_2D_MULTISAMPLE) + { + // Call a specialized clear function to init a multisample texture. + ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get())); + } + else + { + ANGLE_TRY( + t->setSubImage(context, unpack, createType, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color)); + } + + t->syncState(); + + mIncompleteTextures[type].set(context, t.release()); + *textureOut = mIncompleteTextures[type].get(); + return gl::NoError(); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h new file mode 100644 index 0000000000..5a1cb38a6a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/renderer_utils.h @@ -0,0 +1,254 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// renderer_utils: +// Helper methods pertaining to most or all back-ends. +// + +#ifndef LIBANGLE_RENDERER_RENDERER_UTILS_H_ +#define LIBANGLE_RENDERER_RENDERER_UTILS_H_ + +#include + +#include +#include + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace angle +{ +struct Format; +} // namespace angle + +namespace gl +{ +struct FormatType; +struct InternalFormat; +} // namespace gl + +namespace egl +{ +class AttributeMap; +} // namespace egl + +namespace rx +{ + +class ResourceSerial +{ + public: + constexpr ResourceSerial() : mValue(kDirty) {} + explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {} + constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; } + constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; } + + void dirty() { mValue = kDirty; } + void clear() { mValue = kEmpty; } + + constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; } + constexpr bool empty() const { return mValue == kEmpty; } + + private: + constexpr static uintptr_t kDirty = std::numeric_limits::max(); + constexpr static uintptr_t kEmpty = 0; + + uintptr_t mValue; +}; + +class SerialFactory; + +class Serial final +{ + public: + constexpr Serial() : mValue(kInvalid) {} + constexpr Serial(const Serial &other) = default; + Serial &operator=(const Serial &other) = default; + + constexpr bool operator==(const Serial &other) const + { + return mValue != kInvalid && mValue == other.mValue; + } + constexpr bool operator!=(const Serial &other) const + { + return mValue == kInvalid || mValue != other.mValue; + } + constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; } + constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; } + constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; } + constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; } + + private: + friend class SerialFactory; + constexpr explicit Serial(uint64_t value) : mValue(value) {} + uint64_t mValue; + static constexpr uint64_t kInvalid = 0; +}; + +class SerialFactory final : angle::NonCopyable +{ + public: + SerialFactory() : mSerial(1) {} + + Serial generate() + { + ASSERT(mSerial != std::numeric_limits::max()); + return Serial(mSerial++); + } + + private: + uint64_t mSerial; +}; + +using MipGenerationFunction = void (*)(size_t sourceWidth, + size_t sourceHeight, + size_t sourceDepth, + const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourceDepthPitch, + uint8_t *destData, + size_t destRowPitch, + size_t destDepthPitch); + +typedef void (*ColorReadFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorWriteFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorCopyFunction)(const uint8_t *source, uint8_t *dest); + +class FastCopyFunctionMap +{ + public: + struct Entry + { + GLenum format; + GLenum type; + ColorCopyFunction func; + }; + + constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {} + + constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {} + + bool has(const gl::FormatType &formatType) const; + ColorCopyFunction get(const gl::FormatType &formatType) const; + + private: + size_t mSize; + const Entry *mData; +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, + GLenum format, + GLenum type, + GLuint outputPitch, + const gl::PixelPackState &pack, + gl::Buffer *packBufferIn, + ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +void PackPixels(const PackPixelsParams ¶ms, + const angle::Format &sourceFormat, + int inputPitch, + const uint8_t *source, + uint8_t *destination); + +ColorWriteFunction GetColorWriteFunction(const gl::FormatType &formatType); +ColorCopyFunction GetFastCopyFunction(const FastCopyFunctionMap &fastCopyFunctions, + const gl::FormatType &formatType); + +using InitializeTextureDataFunction = void (*)(size_t width, + size_t height, + size_t depth, + uint8_t *output, + size_t outputRowPitch, + size_t outputDepthPitch); + +using LoadImageFunction = void (*)(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); + +struct LoadImageFunctionInfo +{ + LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} + LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) + : loadFunction(loadFunction), requiresConversion(requiresConversion) + { + } + + LoadImageFunction loadFunction; + bool requiresConversion; +}; + +using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum); + +bool ShouldUseDebugLayers(const egl::AttributeMap &attribs); + +void CopyImageCHROMIUM(const uint8_t *sourceData, + size_t sourceRowPitch, + size_t sourcePixelBytes, + ColorReadFunction readFunction, + uint8_t *destData, + size_t destRowPitch, + size_t destPixelBytes, + ColorWriteFunction colorWriteFunction, + GLenum destUnsizedFormat, + GLenum destComponentType, + size_t width, + size_t height, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha); + +// Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete. +// This helper class encapsulates handling incomplete textures. Because the GL back-end +// can take advantage of the driver's incomplete textures, and because clearing multisample +// textures is so difficult, we can keep an instance of this class in the back-end instead +// of moving the logic to the Context front-end. + +// This interface allows us to call-back to init a multisample texture. +class MultisampleTextureInitializer +{ + public: + virtual ~MultisampleTextureInitializer() {} + virtual gl::Error initializeMultisampleTextureToBlack(const gl::Context *context, + gl::Texture *glTexture) = 0; +}; + +class IncompleteTextureSet final : angle::NonCopyable +{ + public: + IncompleteTextureSet(); + ~IncompleteTextureSet(); + + void onDestroy(const gl::Context *context); + + gl::Error getIncompleteTexture(const gl::Context *context, + GLenum type, + MultisampleTextureInitializer *multisampleInitializer, + gl::Texture **textureOut); + + private: + gl::TextureMap mIncompleteTextures; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/signal_utils.h b/src/3rdparty/angle/src/libANGLE/signal_utils.h new file mode 100644 index 0000000000..3dd1332013 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/signal_utils.h @@ -0,0 +1,187 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// signal_utils: +// Helper classes for tracking dependent state changes between objects. +// These changes are signaled to the dependent class via channels. +// See design document: +// https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/ + +#ifndef LIBANGLE_SIGNAL_UTILS_H_ +#define LIBANGLE_SIGNAL_UTILS_H_ + +#include + +#include "common/angleutils.h" +#include "common/debug.h" + +namespace angle +{ + +// Interface that the depending class inherits from. +template +class SignalReceiver +{ + public: + virtual ~SignalReceiver() = default; + virtual void signal(ChannelID channelID, MessageT... message) = 0; +}; + +template +class ChannelBinding; + +// The host class owns the channel. It uses the channel to fire signals to the receiver. +template +class BroadcastChannel final : NonCopyable +{ + public: + BroadcastChannel(); + ~BroadcastChannel(); + + void signal(MessageT... message) const; + + void reset(); + + bool empty() const; + + private: + // Only the ChannelBinding class should add or remove receivers. + friend class ChannelBinding; + void addReceiver(ChannelBinding *receiver); + void removeReceiver(ChannelBinding *receiver); + + std::vector *> mReceivers; +}; + +template +BroadcastChannel::BroadcastChannel() +{ +} + +template +BroadcastChannel::~BroadcastChannel() +{ + reset(); +} + +template +void BroadcastChannel::addReceiver( + ChannelBinding *receiver) +{ + ASSERT(std::find(mReceivers.begin(), mReceivers.end(), receiver) == mReceivers.end()); + mReceivers.push_back(receiver); +} + +template +void BroadcastChannel::removeReceiver( + ChannelBinding *receiver) +{ + auto iter = std::find(mReceivers.begin(), mReceivers.end(), receiver); + ASSERT(iter != mReceivers.end()); + mReceivers.erase(iter); +} + +template +void BroadcastChannel::signal(MessageT... message) const +{ + if (mReceivers.empty()) + return; + + for (const auto *receiver : mReceivers) + { + receiver->signal(message...); + } +} + +template +void BroadcastChannel::reset() +{ + for (auto receiver : mReceivers) + { + receiver->onChannelClosed(); + } + mReceivers.clear(); +} + +template +bool BroadcastChannel::empty() const +{ + return mReceivers.empty(); +} + +// The dependent class keeps bindings to the host's BroadcastChannel. +template +class ChannelBinding final +{ + public: + ChannelBinding(SignalReceiver *receiver, ChannelID channelID); + ~ChannelBinding(); + ChannelBinding(const ChannelBinding &other) = default; + ChannelBinding &operator=(const ChannelBinding &other) = default; + + void bind(BroadcastChannel *channel); + void reset(); + void signal(MessageT... message) const; + void onChannelClosed(); + + private: + BroadcastChannel *mChannel; + SignalReceiver *mReceiver; + ChannelID mChannelID; +}; + +template +ChannelBinding::ChannelBinding( + SignalReceiver *receiver, + ChannelID channelID) + : mChannel(nullptr), mReceiver(receiver), mChannelID(channelID) +{ + ASSERT(receiver); +} + +template +ChannelBinding::~ChannelBinding() +{ + reset(); +} + +template +void ChannelBinding::bind(BroadcastChannel *channel) +{ + ASSERT(mReceiver); + if (mChannel) + { + mChannel->removeReceiver(this); + } + + mChannel = channel; + + if (mChannel) + { + mChannel->addReceiver(this); + } +} + +template +void ChannelBinding::reset() +{ + bind(nullptr); +} + +template +void ChannelBinding::signal(MessageT... message) const +{ + mReceiver->signal(mChannelID, message...); +} + +template +void ChannelBinding::onChannelClosed() +{ + mChannel = nullptr; +} + +} // namespace angle + +#endif // LIBANGLE_SIGNAL_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp index 903f51b158..13a3a9e280 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -14,10 +14,15 @@ #include "libANGLE/Device.h" #include "libANGLE/Display.h" #include "libANGLE/Image.h" +#include "libANGLE/Stream.h" #include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" #include +namespace egl +{ namespace { size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) @@ -30,6 +35,9 @@ size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) case GL_TEXTURE_2D: maxDimension = caps.max2DTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; case GL_TEXTURE_CUBE_MAP: maxDimension = caps.maxCubeMapTextureSize; break; @@ -56,7 +64,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { - if (texture->getInternalFormat(face, level) != GL_NONE) + if (texture->getFormat(face, level).valid()) { return true; } @@ -64,7 +72,7 @@ bool TextureHasNonZeroMipLevelsSpecified(const gl::Context *context, const gl::T } else { - if (texture->getInternalFormat(texture->getTarget(), level) != GL_NONE) + if (texture->getFormat(texture->getTarget(), level).valid()) { return true; } @@ -79,7 +87,7 @@ 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) + if (!texture->getFormat(face, 0).valid()) { return true; } @@ -87,114 +95,482 @@ bool CubeTextureHasUnspecifiedLevel0Face(const gl::Texture *texture) return false; } + +Error ValidateStreamAttribute(const EGLAttrib attribute, + const EGLAttrib value, + const DisplayExtensions &extensions) +{ + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_PRODUCER_FRAME_KHR: + case EGL_CONSUMER_FRAME_KHR: + return EglBadAccess() << "Attempt to initialize readonly parameter"; + case EGL_CONSUMER_LATENCY_USEC_KHR: + // Technically not in spec but a latency < 0 makes no sense so we check it + if (value < 0) + { + return EglBadParameter() << "Latency must be positive"; + } + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!extensions.streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GL extension not enabled"; + } + // Again not in spec but it should be positive anyways + if (value < 0) + { + return EglBadParameter() << "Timeout must be positive"; + } + break; + default: + return EglBadAttribute() << "Invalid stream attribute"; + } + return NoError(); +} + +Error ValidateCreateImageKHRMipLevelCommon(gl::Context *context, + const gl::Texture *texture, + EGLAttrib level) +{ + // Note that the spec EGL_KHR_create_image spec does not explicitly specify an error + // when the level is outside the base/max level range, but it does mention that the + // level "must be a part of the complete texture object ". It can be argued + // that out-of-range levels are not a part of the complete texture. + const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel(); + if (level > 0 && + (!texture->isMipmapComplete() || static_cast(level) < effectiveBaseLevel || + static_cast(level) > texture->getTextureState().getMipmapMaxLevel())) + { + return EglBadParameter() << "texture must be complete if level is non-zero."; + } + + if (level == 0 && !texture->isMipmapComplete() && + TextureHasNonZeroMipLevelsSpecified(context, texture)) + { + return EglBadParameter() << "if level is zero and the texture is incomplete, it must " + "have no mip levels specified except zero."; + } + + return NoError(); } -namespace egl +Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute) +{ + switch (attribute) + { + case EGL_BUFFER_SIZE: + case EGL_ALPHA_SIZE: + case EGL_BLUE_SIZE: + case EGL_GREEN_SIZE: + case EGL_RED_SIZE: + case EGL_DEPTH_SIZE: + case EGL_STENCIL_SIZE: + case EGL_CONFIG_CAVEAT: + case EGL_CONFIG_ID: + case EGL_LEVEL: + case EGL_NATIVE_RENDERABLE: + case EGL_NATIVE_VISUAL_ID: + case EGL_NATIVE_VISUAL_TYPE: + case EGL_SAMPLES: + case EGL_SAMPLE_BUFFERS: + case EGL_SURFACE_TYPE: + case EGL_TRANSPARENT_TYPE: + case EGL_TRANSPARENT_BLUE_VALUE: + case EGL_TRANSPARENT_GREEN_VALUE: + case EGL_TRANSPARENT_RED_VALUE: + case EGL_BIND_TO_TEXTURE_RGB: + case EGL_BIND_TO_TEXTURE_RGBA: + case EGL_MIN_SWAP_INTERVAL: + case EGL_MAX_SWAP_INTERVAL: + case EGL_LUMINANCE_SIZE: + case EGL_ALPHA_MASK_SIZE: + case EGL_COLOR_BUFFER_TYPE: + case EGL_RENDERABLE_TYPE: + case EGL_MATCH_NATIVE_PIXMAP: + case EGL_CONFORMANT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_PIXELS: + break; + + case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; + } + break; + + case EGL_COLOR_COMPONENT_TYPE_EXT: + if (!display->getExtensions().pixelFormatFloat) + { + return EglBadAttribute() << "EGL_EXT_pixel_format_float is not enabled."; + } + break; + + default: + return EglBadAttribute() << "Unknown attribute."; + } + + return NoError(); +} + +Error ValidateConfigAttributes(const Display *display, const AttributeMap &attributes) +{ + for (const auto &attrib : attributes) + { + ANGLE_TRY(ValidateConfigAttribute(display, attrib.first)); + } + + return NoError(); +} + +Error ValidatePlatformType(const ClientExtensions &clientExtensions, EGLAttrib platformType) +{ + switch (platformType) + { + 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) + { + return EglBadAttribute() << "Direct3D platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + if (!clientExtensions.platformANGLEOpenGL) + { + return EglBadAttribute() << "OpenGL platform is unsupported."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE: + if (!clientExtensions.platformANGLENULL) + { + return EglBadAttribute() << "Display type EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE " + "requires EGL_ANGLE_platform_angle_null."; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE: + if (!clientExtensions.platformANGLEVulkan) + { + return EglBadAttribute() << "Vulkan platform is unsupported."; + } + break; + + default: + return EglBadAttribute() << "Unknown platform type."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplayCommon(EGLenum platform, + void *native_display, + const AttributeMap &attribMap) { + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); + + switch (platform) + { + case EGL_PLATFORM_ANGLE_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadParameter() << "Platform ANGLE extension is not active"; + } + break; + case EGL_PLATFORM_DEVICE_EXT: + if (!clientExtensions.platformDevice) + { + return EglBadParameter() << "Platform Device extension is not active"; + } + break; + default: + return EglBadConfig() << "Bad platform type."; + } + + if (platform == EGL_PLATFORM_ANGLE_ANGLE) + { + EGLAttrib platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + EGLAttrib deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; + bool enableAutoTrimSpecified = false; + bool deviceTypeSpecified = false; + bool presentPathSpecified = false; + + Optional majorVersion; + Optional minorVersion; + + for (const auto &curAttrib : attribMap) + { + const EGLAttrib value = curAttrib.second; + + switch (curAttrib.first) + { + case EGL_PLATFORM_ANGLE_TYPE_ANGLE: + { + ANGLE_TRY(ValidatePlatformType(clientExtensions, value)); + platformType = value; + break; + } + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: + if (value != EGL_DONT_CARE) + { + majorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: + if (value != EGL_DONT_CARE) + { + minorVersion = value; + } + break; + + case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE: + switch (value) + { + case EGL_TRUE: + case EGL_FALSE: + break; + default: + return EglBadAttribute() << "Invalid automatic trim attribute"; + } + enableAutoTrimSpecified = true; + break; + + case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE: + if (!clientExtensions.experimentalPresentPath) + { + return EglBadAttribute() + << "EGL_ANGLE_experimental_present_path extension not active"; + } + + switch (value) + { + case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE: + case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE: + break; + default: + return EglBadAttribute() + << "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE"; + } + presentPathSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE: + switch (value) + { + 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: + return EglBadAttribute() << "Invalid value for " + "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE " + "attrib"; + } + deviceType = value; + break; + + case EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE: + if (!clientExtensions.platformANGLE) + { + return EglBadAttribute() << "EGL_ANGLE_platform_angle extension not active"; + } + if (value != EGL_TRUE && value != EGL_FALSE && value != EGL_DONT_CARE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE " + "must be EGL_TRUE, EGL_FALSE, or " + "EGL_DONT_CARE."; + } + break; + + default: + break; + } + } + + if (!majorVersion.valid() && minorVersion.valid()) + { + return EglBadAttribute() + << "Must specify major version if you specify a minor version."; + } + + if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE " + "requires a device type of " + "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."; + } + + if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a " + "device type of EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or " + "EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."; + } + + if (platformType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) + { + if ((majorVersion.valid() && majorVersion.value() != 1) || + (minorVersion.valid() && minorVersion.value() != 0)) + { + return EglBadAttribute() << "EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE currently " + "only supports Vulkan 1.0."; + } + } + } + else if (platform == EGL_PLATFORM_DEVICE_EXT) + { + Device *eglDevice = reinterpret_cast(native_display); + if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice)) + { + return EglBadAttribute() << "native_display should be a valid EGL device if " + "platform equals EGL_PLATFORM_DEVICE_EXT"; + } + } + else + { + UNREACHABLE(); + } + + return NoError(); +} + +} // namespace Error ValidateDisplay(const Display *display) { if (display == EGL_NO_DISPLAY) { - return Error(EGL_BAD_DISPLAY, "display is EGL_NO_DISPLAY."); + return EglBadDisplay() << "display is EGL_NO_DISPLAY."; } if (!Display::isValidDisplay(display)) { - return Error(EGL_BAD_DISPLAY, "display is not a valid display."); + return EglBadDisplay() << "display is not a valid display."; } if (!display->isInitialized()) { - return Error(EGL_NOT_INITIALIZED, "display is not initialized."); + return EglNotInitialized() << "display is not initialized."; } - return Error(EGL_SUCCESS); + if (display->isDeviceLost()) + { + return EglContextLost() << "display had a context loss"; + } + + return NoError(); } -Error ValidateSurface(const Display *display, Surface *surface) +Error ValidateSurface(const Display *display, const Surface *surface) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidSurface(surface)) { - return Error(EGL_BAD_SURFACE); + return EglBadSurface(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateConfig(const Display *display, const Config *config) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidConfig(config)) { - return Error(EGL_BAD_CONFIG); + return EglBadConfig(); } - return Error(EGL_SUCCESS); + return NoError(); } -Error ValidateContext(const Display *display, gl::Context *context) +Error ValidateContext(const Display *display, const gl::Context *context) { - Error error = ValidateDisplay(display); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateDisplay(display)); if (!display->isValidContext(context)) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateImage(const Display *display, const Image *image) { - Error error = ValidateDisplay(display); - if (error.isError()) + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->isValidImage(image)) { - return error; + return EglBadParameter() << "image is not valid."; } - if (!display->isValidImage(image)) + return NoError(); +} + +Error ValidateStream(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAccess() << "Stream extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) { - return Error(EGL_BAD_PARAMETER, "image is not valid."); + return EglBadStream() << "Invalid stream"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, const AttributeMap& attributes) { - Error error = ValidateConfig(display, configuration); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, configuration)); // Get the requested client version (default is 1) and check it is 2 or 3. - EGLint clientMajorVersion = 1; - EGLint clientMinorVersion = 0; - EGLint contextFlags = 0; + EGLAttrib clientMajorVersion = 1; + EGLAttrib clientMinorVersion = 0; + EGLAttrib contextFlags = 0; bool resetNotification = false; - bool robustAccess = false; for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -215,28 +591,27 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: // Only valid for OpenGL (non-ES) contexts - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - robustAccess = (value == EGL_TRUE); break; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: - static_assert(EGL_LOSE_CONTEXT_ON_RESET_EXT == EGL_LOSE_CONTEXT_ON_RESET_KHR, "EGL extension enums not equal."); - static_assert(EGL_NO_RESET_NOTIFICATION_EXT == EGL_NO_RESET_NOTIFICATION_KHR, "EGL extension enums not equal."); - // same as EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, fall through + return EglBadAttribute() << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is not" + << " valid for GLES with EGL 1.4 and KHR_create_context. Use" + << " EXT_create_context_robustness."; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: if (!display->getExtensions().createContextRobustness) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT) { @@ -244,34 +619,143 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context } else if (value != EGL_NO_RESET_NOTIFICATION_EXT) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_CONTEXT_OPENGL_NO_ERROR_KHR: if (!display->getExtensions().createContextNoError) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute."); + return EglBadAttribute() << "Invalid Context attribute."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "Attribute must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE: + if (!display->getExtensions().createContextWebGLCompatibility) + { + return EglBadAttribute() << "Attribute " + "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires " + "EGL_ANGLE_create_context_webgl_compatibility."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() + << "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM: + if (!display->getExtensions().createContextBindGeneratesResource) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM requires " + "EGL_CHROMIUM_create_context_bind_generates_resource."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM " + "must be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE: + if (!display->getExtensions().displayTextureShareGroup) + { + return EglBadAttribute() << "Attribute " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE requires " + "EGL_ANGLE_display_texture_share_group."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() + << "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE must be EGL_TRUE or EGL_FALSE."; + } + if (shareContext && + (shareContext->usingDisplayTextureShareGroup() != (value == EGL_TRUE))) + { + return EglBadAttribute() << "All contexts within a share group must be " + "created with the same value of " + "EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE."; + } + break; + + case EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE: + if (!display->getExtensions().createContextClientArrays) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE requires " + "EGL_ANGLE_create_context_client_arrays."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE: + if (!display->getExtensions().programCacheControl) + { + return EglBadAttribute() + << "Attribute EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE " + "requires EGL_ANGLE_program_cache_control."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE must " + "be EGL_TRUE or EGL_FALSE."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; } if (value != EGL_TRUE && value != EGL_FALSE) { - return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE."); + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute() << "Unknown attribute."; } } - if ((clientMajorVersion != 2 && clientMajorVersion != 3) || clientMinorVersion != 0) + switch (clientMajorVersion) { - return Error(EGL_BAD_CONFIG); - } - - if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR) && !(configuration->configCaveat & EGL_NON_CONFORMANT_CONFIG)) - { - return Error(EGL_BAD_CONFIG); + case 2: + if (clientMinorVersion != 0) + { + return EglBadConfig(); + } + break; + case 3: + if (clientMinorVersion != 0 && clientMinorVersion != 1) + { + return EglBadConfig(); + } + if (!(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR)) + { + return EglBadConfig(); + } + if (display->getMaxSupportedESVersion() < + gl::Version(static_cast(clientMajorVersion), + static_cast(clientMinorVersion))) + { + return EglBadConfig() << "Requested GLES version is not supported."; + } + break; + default: + return EglBadConfig(); + break; } // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES @@ -279,18 +763,7 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR); if ((contextFlags & ~validContextFlags) != 0) { - return Error(EGL_BAD_ATTRIBUTE); - } - - if ((contextFlags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) > 0) - { - robustAccess = true; - } - - if (robustAccess) - { - // Unimplemented - return Error(EGL_BAD_CONFIG); + return EglBadAttribute(); } if (shareContext) @@ -298,43 +771,40 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context // Shared context is invalid or is owned by another display if (!display->isValidContext(shareContext)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if (shareContext->isResetNotificationEnabled() != resetNotification) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - if (shareContext->getClientVersion() != clientMajorVersion) + if (shareContext->getClientMajorVersion() != clientMajorVersion || + shareContext->getClientMinorVersion() != clientMinorVersion) { - return Error(EGL_BAD_CONTEXT); + return EglBadContext(); } } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); if (!display->isValidNativeWindow(window)) { - return Error(EGL_BAD_NATIVE_WINDOW); + return EglBadNativeWindow(); } const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -344,23 +814,23 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_BACK_BUFFER: break; case EGL_SINGLE_BUFFER: - return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported + return EglBadMatch(); // Rendering directly to front buffer not supported default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: if (!displayExtensions.postSubBuffer) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: if (!displayExtensions.flexibleSurfaceCompatibility) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -368,68 +838,77 @@ Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWin case EGL_HEIGHT: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; case EGL_FIXED_SIZE_ANGLE: if (!displayExtensions.windowFixedSize) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; case EGL_SURFACE_ORIENTATION_ANGLE: if (!displayExtensions.surfaceOrientation) { - return Error(EGL_BAD_ATTRIBUTE, "EGL_ANGLE_surface_orientation is not enabled."); + return EglBadAttribute() << "EGL_ANGLE_surface_orientation is not enabled."; } break; case EGL_VG_COLORSPACE: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_VG_ALPHA_FORMAT: - return Error(EGL_BAD_MATCH); + return EglBadMatch(); case EGL_DIRECT_COMPOSITION_ANGLE: if (!displayExtensions.directComposition) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (Display::hasExistingWindowSurface(window)) { - return Error(EGL_BAD_ALLOC); + return EglBadAlloc(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -437,7 +916,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_HEIGHT: if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -452,7 +931,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -463,7 +942,7 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -479,60 +958,66 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri 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."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "Attribute EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE " + "requires EGL_ANGLE_robust_resource_initialization."; + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE must be " + "either EGL_TRUE or EGL_FALSE."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#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); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast(attributes.get(EGL_HEIGHT, 0)); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#endif - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes) { - Error error = ValidateConfig(display, config); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateConfig(display, config)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -541,22 +1026,33 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (buffer == nullptr) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; + case EGL_D3D_TEXTURE_ANGLE: + if (!displayExtensions.d3dTextureClientBuffer) + { + return EglBadParameter(); + } + if (buffer == nullptr) + { + return EglBadParameter(); + } + break; + default: - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -564,11 +1060,11 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_HEIGHT: if (!displayExtensions.d3dShareHandleClientBuffer) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } if (value < 0) { - return Error(EGL_BAD_PARAMETER); + return EglBadParameter(); } break; @@ -580,7 +1076,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_RGBA: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -591,7 +1087,7 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E case EGL_TEXTURE_2D: break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } break; @@ -601,63 +1097,148 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E 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."); + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used " + "without EGL_ANGLE_flexible_surface_compatibility support."; } break; default: - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } } if (!(config->surfaceType & EGL_PBUFFER_BIT)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } - EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); - EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + EGLAttrib textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLAttrib textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) { - EGLint width = attributes.get(EGL_WIDTH, 0); - EGLint height = attributes.get(EGL_HEIGHT, 0); + EGLint width = static_cast(attributes.get(EGL_WIDTH, 0)); + EGLint height = static_cast(attributes.get(EGL_HEIGHT, 0)); if (width == 0 || height == 0) { - return Error(EGL_BAD_ATTRIBUTE); + return EglBadAttribute(); } -// On Windows Store, we know the originating texture came from D3D11, so bypass this check -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) const Caps &caps = display->getCaps(); if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return Error(EGL_BAD_MATCH); + return EglBadMatch(); } -#endif } - return Error(EGL_SUCCESS); + ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes)); + + return NoError(); } -Error ValidateCompatibleConfigs(const Display *display, - const Config *config1, - const Surface *surface, +Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context) +{ + if (context == EGL_NO_CONTEXT && (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is EGL_NO_CONTEXT, surfaces must be EGL_NO_SURFACE"; + } + + // If ctx is EGL_NO_CONTEXT and either draw or read are not EGL_NO_SURFACE, an EGL_BAD_MATCH + // error is generated. EGL_KHR_surfaceless_context allows both surfaces to be EGL_NO_SURFACE. + if (context != EGL_NO_CONTEXT && (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE)) + { + if (display->getExtensions().surfacelessContext) + { + if ((draw == EGL_NO_SURFACE) != (read == EGL_NO_SURFACE)) + { + return EglBadMatch() << "If ctx is not EGL_NOT_CONTEXT, draw or read must " + "both be EGL_NO_SURFACE, or both not"; + } + } + else + { + return EglBadMatch() + << "If ctx is not EGL_NO_CONTEXT, surfaces must not be EGL_NO_SURFACE"; + } + } + + // 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)) + { + return EglBadMatch() + << "read and draw must both be valid surfaces, or both be EGL_NO_SURFACE"; + } + + if (display == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) + { + return EglBadDisplay() << "'dpy' not a valid EGLDisplay handle"; + } + + // EGL 1.5 spec: dpy can be uninitialized if all other parameters are null + if (!display->isInitialized() && + (context != EGL_NO_CONTEXT || draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE)) + { + return EglNotInitialized() << "'dpy' not initialized"; + } + + if (context != EGL_NO_CONTEXT) + { + ANGLE_TRY(ValidateContext(display, context)); + } + + if (display->isInitialized() && display->testDeviceLost()) + { + return EglContextLost(); + } + + Surface *drawSurface = static_cast(draw); + if (draw != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, drawSurface)); + } + + Surface *readSurface = static_cast(read); + if (read != EGL_NO_SURFACE) + { + ANGLE_TRY(ValidateSurface(display, readSurface)); + } + + if (readSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, readSurface->getConfig(), readSurface, + context->getConfig(), readSurface->getType())); + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + + if (drawSurface) + { + ANGLE_TRY(ValidateCompatibleConfigs(display, drawSurface->getConfig(), drawSurface, + context->getConfig(), drawSurface->getType())); + } + } + return NoError(); +} + +Error ValidateCompatibleConfigs(const Display *display, + const Config *config1, + const Surface *surface, const Config *config2, EGLint surfaceType) { @@ -669,7 +1250,7 @@ Error ValidateCompatibleConfigs(const Display *display, bool colorBufferCompat = config1->colorBufferType == config2->colorBufferType; if (!colorBufferCompat) { - return Error(EGL_BAD_MATCH, "Color buffer types are not compatible."); + return EglBadMatch() << "Color buffer types are not compatible."; } bool colorCompat = @@ -678,24 +1259,30 @@ Error ValidateCompatibleConfigs(const Display *display, config1->luminanceSize == config2->luminanceSize; if (!colorCompat) { - return Error(EGL_BAD_MATCH, "Color buffer sizes are not compatible."); + return EglBadMatch() << "Color buffer sizes are not compatible."; + } + + bool componentTypeCompat = config1->colorComponentType == config2->colorComponentType; + if (!componentTypeCompat) + { + return EglBadMatch() << "Color buffer component types 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."); + return EglBadMatch() << "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 EglBadMatch() << "Surface types are not compatible."; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateImageKHR(const Display *display, @@ -704,11 +1291,7 @@ Error ValidateCreateImageKHR(const Display *display, EGLClientBuffer buffer, const AttributeMap &attributes) { - Error error = ValidateContext(display, context); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateContext(display, context)); const DisplayExtensions &displayExtensions = display->getExtensions(); @@ -717,7 +1300,7 @@ Error ValidateCreateImageKHR(const Display *display, // 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."); + return EglBadDisplay() << "EGL_KHR_image not supported."; } // TODO(geofflang): Complete validation from EGL_KHR_image_base: @@ -727,8 +1310,8 @@ Error ValidateCreateImageKHR(const Display *display, for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) { - EGLint attribute = attributeIter->first; - EGLint value = attributeIter->second; + EGLAttrib attribute = attributeIter->first; + EGLAttrib value = attributeIter->second; switch (attribute) { @@ -740,8 +1323,8 @@ Error ValidateCreateImageKHR(const Display *display, break; default: - return Error(EGL_BAD_PARAMETER, - "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."); + return EglBadParameter() + << "EGL_IMAGE_PRESERVED_KHR must be EGL_TRUE or EGL_FALSE."; } break; @@ -749,28 +1332,27 @@ Error ValidateCreateImageKHR(const Display *display, 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."); + return EglBadParameter() << "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."); + return EglBadParameter() << "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."); + return EglBadParameter() << "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); + return EglBadParameter() + << "invalid attribute: 0x" << std::hex << std::uppercase << attribute; } } @@ -780,48 +1362,35 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture2DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_2D_image not supported."); + return EglBadParameter() << "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."); + return EglBadParameter() << "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."); + return EglBadParameter() << "target is not a 2D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib 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."); + return EglBadParameter() + << "target 2D texture does not have a valid size at specified level."; } - 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."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -834,57 +1403,44 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTextureCubemapImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_cubemap_image not supported."); + return EglBadParameter() << "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."); + return EglBadParameter() + << "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."); + return EglBadParameter() << "target is not a cubemap texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "texture has a surface bound to it."; } - EGLint level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib 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."); + return EglBadParameter() << "target cubemap texture does not have a valid " + "size at specified level and face."; } - 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."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); 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."); + return EglBadParameter() << "if level is zero and the texture is incomplete, " + "it must have all of its faces specified at level " + "zero."; } } break; @@ -893,58 +1449,45 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glTexture3DImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_texture_3D_image not supported."); + return EglBadParameter() << "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."); + return EglBadParameter() << "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."); + return EglBadParameter() << "target is not a 3D texture."; } if (texture->getBoundSurface() != nullptr) { - return Error(EGL_BAD_ACCESS, "texture has a surface bound to it."); + return EglBadAccess() << "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); + EGLAttrib level = attributes.get(EGL_GL_TEXTURE_LEVEL_KHR, 0); + EGLAttrib 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."); + return EglBadParameter() + << "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."); + return EglBadParameter() << "target 3D texture does not have enough layers " + "for the specified Z offset at the specified " + "level."; } - 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."); - } + ANGLE_TRY(ValidateCreateImageKHRMipLevelCommon(context, texture, level)); } break; @@ -952,75 +1495,71 @@ Error ValidateCreateImageKHR(const Display *display, { if (!displayExtensions.glRenderbufferImage) { - return Error(EGL_BAD_PARAMETER, "KHR_gl_renderbuffer_image not supported."); + return EglBadParameter() << "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."); + return EglBadParameter() << "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."); + return EglBadParameter() + << "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."); + return EglBadParameter() << "target is not a renderbuffer."; } if (renderbuffer->getSamples() > 0) { - return Error(EGL_BAD_PARAMETER, "target renderbuffer cannot be multisampled."); + return EglBadParameter() << "target renderbuffer cannot be multisampled."; } } break; default: - return Error(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); + return EglBadParameter() + << "invalid target: 0x" << std::hex << std::uppercase << target; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateDestroyImageKHR(const Display *display, const Image *image) { - Error error = ValidateImage(display, image); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ValidateImage(display, image)); 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 EglBadDisplay(); } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (attrib_list != nullptr && attrib_list[0] != EGL_NONE) { - return Error(EGL_BAD_ATTRIBUTE, "Invalid attrib_list parameter"); + return EglBadAttribute() << "Invalid attrib_list parameter"; } switch (device_type) @@ -1028,35 +1567,935 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, case EGL_D3D11_DEVICE_ANGLE: if (!clientExtensions.deviceCreationD3D11) { - return Error(EGL_BAD_ATTRIBUTE, "D3D11 device creation extension not active"); + return EglBadAttribute() << "D3D11 device creation extension not active"; } break; default: - return Error(EGL_BAD_ATTRIBUTE, "Invalid device_type parameter"); + return EglBadAttribute() << "Invalid device_type parameter"; } - return Error(EGL_SUCCESS); + return NoError(); } Error ValidateReleaseDeviceANGLE(Device *device) { - const ClientExtensions &clientExtensions = Display::getClientExtensions(); + const ClientExtensions &clientExtensions = Display::GetClientExtensions(); if (!clientExtensions.deviceCreation) { - return Error(EGL_BAD_ACCESS, "Device creation extension not active"); + return EglBadAccess() << "Device creation extension not active"; } if (device == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(device)) { - return Error(EGL_BAD_DEVICE_EXT, "Invalid device parameter"); + return EglBadDevice() << "Invalid device parameter"; } Display *owningDisplay = device->getOwningDisplay(); if (owningDisplay != nullptr) { - return Error(EGL_BAD_DEVICE_EXT, "Device must have been created using eglCreateDevice"); + return EglBadDevice() << "Device must have been created using eglCreateDevice"; + } + + return NoError(); +} + +Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.stream) + { + return EglBadAlloc() << "Stream extension not active"; + } + + for (const auto &attributeIter : attributes) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + ANGLE_TRY(ValidateStreamAttribute(attribute, value, displayExtensions)); + } + + return NoError(); +} + +Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream) +{ + ANGLE_TRY(ValidateStream(display, stream)); + return NoError(); +} + +Error ValidateStreamAttribKHR(const Display *display, + const Stream *stream, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR) + { + return EglBadState() << "Bad stream state"; + } + + return ValidateStreamAttribute(attribute, value, display->getExtensions()); +} + +Error ValidateQueryStreamKHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + case EGL_CONSUMER_LATENCY_USEC_KHR: + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + if (!display->getExtensions().streamConsumerGLTexture) + { + return EglBadAttribute() << "Consumer GLTexture extension not active"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + + return NoError(); +} + +Error ValidateQueryStreamu64KHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLuint64KHR *value) +{ + ANGLE_TRY(ValidateStream(display, stream)); + + switch (attribute) + { + case EGL_CONSUMER_FRAME_KHR: + case EGL_PRODUCER_FRAME_KHR: + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + + return NoError(); +} + +Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; } - return Error(EGL_SUCCESS); + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + + return NoError(); +} + +Error ValidateStreamConsumerAcquireKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + // Note: technically EGL_STREAM_STATE_EMPTY_KHR is a valid state when the timeout is non-zero. + // However, the timeout is effectively ignored since it has no useful functionality with the + // current producers that are implemented, so we don't allow that state + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); } + +Error ValidateStreamConsumerReleaseKHR(const Display *display, + gl::Context *context, + const Stream *stream) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (!stream->isConsumerBoundToContext(context)) + { + return EglBadAccess() << "Current GL context not associated with stream consumer"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureRGB && + stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV) + { + return EglBadAccess() << "Invalid stream consumer type"; + } + + if (stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + return NoError(); } + +Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display, + gl::Context *context, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamConsumerGLTexture) + { + return EglBadAccess() << "Stream consumer extension not active"; + } + + // Although technically not a requirement in spec, the context needs to be checked for support + // for external textures or future logic will cause assertations. This extension is also + // effectively useless without external textures. + if (!context->getExtensions().eglStreamConsumerExternal) + { + return EglBadAccess() << "EGL stream consumer external GL extension not enabled"; + } + + if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream)) + { + return EglBadStream() << "Invalid stream"; + } + + if (!context) + { + return EglBadAccess() << "No GL context current to calling thread."; + } + + ANGLE_TRY(ValidateContext(display, context)); + + if (stream->getState() != EGL_STREAM_STATE_CREATED_KHR) + { + return EglBadState() << "Invalid stream state"; + } + + const gl::Caps &glCaps = context->getCaps(); + + EGLAttrib colorBufferType = EGL_RGB_BUFFER; + EGLAttrib planeCount = -1; + EGLAttrib plane[3]; + for (int i = 0; i < 3; i++) + { + plane[i] = -1; + } + for (const auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_COLOR_BUFFER_TYPE: + if (value != EGL_RGB_BUFFER && value != EGL_YUV_BUFFER_EXT) + { + return EglBadParameter() << "Invalid color buffer type"; + } + colorBufferType = value; + break; + case EGL_YUV_NUMBER_OF_PLANES_EXT: + // planeCount = -1 is a tag for the default plane count so the value must be checked + // to be positive here to ensure future logic doesn't break on invalid negative + // inputs + if (value < 0) + { + return EglBadMatch() << "Invalid plane count"; + } + planeCount = value; + break; + default: + if (attribute >= EGL_YUV_PLANE0_TEXTURE_UNIT_NV && + attribute <= EGL_YUV_PLANE2_TEXTURE_UNIT_NV) + { + if ((value < 0 || + value >= static_cast(glCaps.maxCombinedTextureImageUnits)) && + value != EGL_NONE) + { + return EglBadAccess() << "Invalid texture unit"; + } + plane[attribute - EGL_YUV_PLANE0_TEXTURE_UNIT_NV] = value; + } + else + { + return EglBadAttribute() << "Invalid attribute"; + } + } + } + + if (colorBufferType == EGL_RGB_BUFFER) + { + if (planeCount > 0) + { + return EglBadMatch() << "Plane count must be 0 for RGB buffer"; + } + for (int i = 0; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Planes cannot be specified"; + } + } + + // Lookup the texture and ensure it is correct + gl::Texture *texture = context->getGLState().getTargetTexture(GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() << "No external texture bound"; + } + } + else + { + if (planeCount == -1) + { + planeCount = 2; + } + if (planeCount < 1 || planeCount > 3) + { + return EglBadMatch() << "Invalid YUV plane count"; + } + for (EGLAttrib i = planeCount; i < 3; i++) + { + if (plane[i] != -1) + { + return EglBadMatch() << "Invalid plane specified"; + } + } + + // Set to ensure no texture is referenced more than once + std::set textureSet; + for (EGLAttrib i = 0; i < planeCount; i++) + { + if (plane[i] == -1) + { + return EglBadMatch() << "Not all planes specified"; + } + if (plane[i] != EGL_NONE) + { + gl::Texture *texture = context->getGLState().getSamplerTexture( + static_cast(plane[i]), GL_TEXTURE_EXTERNAL_OES); + if (texture == nullptr || texture->getId() == 0) + { + return EglBadAccess() + << "No external texture bound at one or more specified texture units"; + } + if (textureSet.find(texture) != textureSet.end()) + { + return EglBadAccess() << "Multiple planes bound to same texture object"; + } + textureSet.insert(texture); + } + } + } + + return NoError(); +} + +Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + if (!attribs.isEmpty()) + { + return EglBadAttribute() << "Invalid attribute"; + } + + if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR) + { + return EglBadState() << "Stream not in connecting state"; + } + + if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV || + stream->getPlaneCount() != 2) + { + return EglBadMatch() << "Incompatible stream consumer type"; + } + + return NoError(); +} + +Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + void *texture, + const AttributeMap &attribs) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.streamProducerD3DTextureNV12) + { + return EglBadAccess() << "Stream producer extension not active"; + } + + ANGLE_TRY(ValidateStream(display, stream)); + + for (auto &attributeIter : attribs) + { + EGLAttrib attribute = attributeIter.first; + EGLAttrib value = attributeIter.second; + + switch (attribute) + { + case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE: + if (value < 0) + { + return EglBadParameter() << "Invalid subresource index"; + } + break; + default: + return EglBadAttribute() << "Invalid attribute"; + } + } + + if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR && + stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR && + stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR) + { + return EglBadState() << "Stream not fully configured"; + } + + if (stream->getProducerType() != Stream::ProducerType::D3D11TextureNV12) + { + return EglBadMatch() << "Incompatible stream producer"; + } + + if (texture == nullptr) + { + return EglBadParameter() << "Texture is null"; + } + + return stream->validateD3D11NV12Texture(texture); +} + +Error ValidateGetSyncValuesCHROMIUM(const Display *display, + const Surface *surface, + const EGLuint64KHR *ust, + const EGLuint64KHR *msc, + const EGLuint64KHR *sbc) +{ + ANGLE_TRY(ValidateDisplay(display)); + + const DisplayExtensions &displayExtensions = display->getExtensions(); + if (!displayExtensions.getSyncValues) + { + return EglBadAccess() << "getSyncValues extension not active"; + } + + if (display->isDeviceLost()) + { + return EglContextLost() << "Context is lost."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "getSyncValues surface cannot be EGL_NO_SURFACE"; + } + + if (!surface->directComposition()) + { + return EglBadSurface() << "getSyncValues surface requires Direct Composition to be enabled"; + } + + if (ust == nullptr) + { + return EglBadParameter() << "ust is null"; + } + + if (msc == nullptr) + { + return EglBadParameter() << "msc is null"; + } + + if (sbc == nullptr) + { + return EglBadParameter() << "sbc is null"; + } + + return NoError(); +} + +Error ValidateSwapBuffersWithDamageEXT(const Display *display, + const Surface *surface, + EGLint *rects, + EGLint n_rects) +{ + Error error = ValidateSurface(display, surface); + if (error.isError()) + { + return error; + } + + if (!display->getExtensions().swapBuffersWithDamage) + { + // 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 EglBadDisplay() << "EGL_EXT_swap_buffers_with_damage is not available."; + } + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Swap surface cannot be EGL_NO_SURFACE."; + } + + if (n_rects < 0) + { + return EglBadParameter() << "n_rects cannot be negative."; + } + + if (n_rects > 0 && rects == nullptr) + { + return EglBadParameter() << "n_rects cannot be greater than zero when rects is NULL."; + } + + // TODO(jmadill): Validate Surface is bound to the thread. + + return NoError(); +} + +Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute) +{ + ANGLE_TRY(ValidateConfig(display, config)); + ANGLE_TRY(ValidateConfigAttribute(display, static_cast(attribute))); + return NoError(); +} + +Error ValidateChooseConfig(const Display *display, + const AttributeMap &attribs, + EGLint configSize, + EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateConfigAttributes(display, attribs)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (numConfig == nullptr) + { + return EglBadParameter() << "num_config cannot be null."; + } + + return NoError(); +} + +Error ValidateGetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateGetPlatformDisplayEXT(EGLenum platform, + void *native_display, + const EGLint *attrib_list) +{ + const auto &attribMap = AttributeMap::CreateFromIntArray(attrib_list); + return ValidateGetPlatformDisplayCommon(platform, native_display, attribMap); +} + +Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + switch (attrib) + { + case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE: + case EGL_PROGRAM_CACHE_SIZE_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid program cache attribute."; + } + + return NoError(); +} + +Error ValidateProgramCacheQueryANGLE(const Display *display, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (index < 0 || index >= display->programCacheGetAttrib(EGL_PROGRAM_CACHE_SIZE_ANGLE)) + { + return EglBadParameter() << "Program index out of range."; + } + + if (keysize == nullptr || binarysize == nullptr) + { + return EglBadParameter() << "keysize and binarysize must always be valid pointers."; + } + + if (binary && *keysize != static_cast(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if ((key == nullptr) != (binary == nullptr)) + { + return EglBadParameter() << "key and binary must both be null or both non-null."; + } + + return NoError(); +} + +Error ValidateProgramCachePopulateANGLE(const Display *display, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (keysize != static_cast(gl::kProgramHashLength)) + { + return EglBadParameter() << "Invalid program key size."; + } + + if (key == nullptr || binary == nullptr) + { + return EglBadParameter() << "null pointer in arguments."; + } + + // Upper bound for binarysize is arbitrary. + if (binarysize <= 0 || binarysize > egl::kProgramCacheSizeAbsoluteMax) + { + return EglBadParameter() << "binarysize out of valid range."; + } + + return NoError(); +} + +Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode) +{ + ANGLE_TRY(ValidateDisplay(display)); + + if (!display->getExtensions().programCacheControl) + { + return EglBadAccess() << "Extension not supported"; + } + + if (limit < 0) + { + return EglBadParameter() << "limit must be non-negative."; + } + + switch (mode) + { + case EGL_PROGRAM_CACHE_RESIZE_ANGLE: + case EGL_PROGRAM_CACHE_TRIM_ANGLE: + break; + + default: + return EglBadParameter() << "Invalid cache resize mode."; + } + + return NoError(); +} + +Error ValidateSurfaceAttrib(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_MIPMAP_LEVEL: + break; + + case EGL_MULTISAMPLE_RESOLVE: + switch (value) + { + case EGL_MULTISAMPLE_RESOLVE_DEFAULT: + break; + + case EGL_MULTISAMPLE_RESOLVE_BOX: + if ((surface->getConfig()->surfaceType & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_MULTISAMPLE_RESOLVE_BOX."; + } + break; + + default: + return EglBadAttribute() << "Invalid multisample resolve type."; + } + + case EGL_SWAP_BEHAVIOR: + switch (value) + { + case EGL_BUFFER_PRESERVED: + if ((surface->getConfig()->surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == 0) + { + return EglBadMatch() + << "Surface does not support EGL_SWAP_BEHAVIOR_PRESERVED."; + } + break; + + case EGL_BUFFER_DESTROYED: + break; + + default: + return EglBadAttribute() << "Invalid swap behaviour."; + } + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQuerySurface(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateSurface(display, surface)); + + if (surface == EGL_NO_SURFACE) + { + return EglBadSurface() << "Surface cannot be EGL_NO_SURFACE."; + } + + switch (attribute) + { + case EGL_GL_COLORSPACE: + case EGL_VG_ALPHA_FORMAT: + case EGL_VG_COLORSPACE: + case EGL_CONFIG_ID: + case EGL_HEIGHT: + case EGL_HORIZONTAL_RESOLUTION: + case EGL_LARGEST_PBUFFER: + case EGL_MIPMAP_TEXTURE: + case EGL_MIPMAP_LEVEL: + case EGL_MULTISAMPLE_RESOLVE: + case EGL_PIXEL_ASPECT_RATIO: + case EGL_RENDER_BUFFER: + case EGL_SWAP_BEHAVIOR: + case EGL_TEXTURE_FORMAT: + case EGL_TEXTURE_TARGET: + case EGL_VERTICAL_RESOLUTION: + case EGL_WIDTH: + break; + + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!display->getExtensions().postSubBuffer) + { + return EglBadAttribute() << "EGL_POST_SUB_BUFFER_SUPPORTED_NV cannot be used " + "without EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_FIXED_SIZE_ANGLE: + if (!display->getExtensions().windowFixedSize) + { + return EglBadAttribute() << "EGL_FIXED_SIZE_ANGLE cannot be used without " + "EGL_ANGLE_window_fixed_size support."; + } + break; + + case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: + if (!display->getExtensions().flexibleSurfaceCompatibility) + { + return EglBadAttribute() + << "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be " + "used without EGL_ANGLE_flexible_surface_compatibility support."; + } + break; + + case EGL_SURFACE_ORIENTATION_ANGLE: + if (!display->getExtensions().surfaceOrientation) + { + return EglBadAttribute() << "EGL_SURFACE_ORIENTATION_ANGLE cannot be " + "queried without " + "EGL_ANGLE_surface_orientation support."; + } + break; + + case EGL_DIRECT_COMPOSITION_ANGLE: + if (!display->getExtensions().directComposition) + { + return EglBadAttribute() << "EGL_DIRECT_COMPOSITION_ANGLE cannot be " + "used without " + "EGL_ANGLE_direct_composition support."; + } + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid surface attribute."; + } + + return NoError(); +} + +Error ValidateQueryContext(const Display *display, + const gl::Context *context, + EGLint attribute, + EGLint *value) +{ + ANGLE_TRY(ValidateDisplay(display)); + ANGLE_TRY(ValidateContext(display, context)); + + switch (attribute) + { + case EGL_CONFIG_ID: + case EGL_CONTEXT_CLIENT_TYPE: + case EGL_CONTEXT_CLIENT_VERSION: + case EGL_RENDER_BUFFER: + break; + + case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + if (!display->getExtensions().robustResourceInitialization) + { + return EglBadAttribute() << "EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE cannot be " + "used without EGL_ANGLE_robust_resource_initialization " + "support."; + } + break; + + default: + return EglBadAttribute() << "Invalid context attribute."; + } + + return NoError(); +} + +} // namespace egl diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.h b/src/3rdparty/angle/src/libANGLE/validationEGL.h index eaafddc20d..3ab8232c7f 100644 --- a/src/3rdparty/angle/src/libANGLE/validationEGL.h +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.h @@ -12,6 +12,7 @@ #include "libANGLE/Error.h" #include +#include namespace gl { @@ -22,17 +23,19 @@ namespace egl { class AttributeMap; +struct ClientExtensions; struct Config; class Device; class Display; class Image; +class Stream; class Surface; // Object validation Error ValidateDisplay(const Display *display); -Error ValidateSurface(const Display *display, Surface *surface); +Error ValidateSurface(const Display *display, const Surface *surface); Error ValidateConfig(const Display *display, const Config *config); -Error ValidateContext(const Display *display, gl::Context *context); +Error ValidateContext(const Display *display, const gl::Context *context); Error ValidateImage(const Display *display, const Image *image); // Entry point validation @@ -46,6 +49,8 @@ Error ValidateCreatePbufferSurface(Display *display, Config *config, const Attri Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, Config *config, const AttributeMap& attributes); +Error ValidateMakeCurrent(Display *display, EGLSurface draw, EGLSurface read, gl::Context *context); + Error ValidateCreateImageKHR(const Display *display, gl::Context *context, EGLenum target, @@ -58,12 +63,120 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, const EGLAttrib *attrib_list); Error ValidateReleaseDeviceANGLE(Device *device); +Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes); +Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream); +Error ValidateStreamAttribKHR(const Display *display, + const Stream *stream, + EGLint attribute, + EGLint value); +Error ValidateQueryStreamKHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLint *value); +Error ValidateQueryStreamu64KHR(const Display *display, + const Stream *stream, + EGLenum attribute, + EGLuint64KHR *value); +Error ValidateStreamConsumerGLTextureExternalKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerAcquireKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerReleaseKHR(const Display *display, + gl::Context *context, + const Stream *stream); +Error ValidateStreamConsumerGLTextureExternalAttribsNV(const Display *display, + gl::Context *context, + const Stream *stream, + const AttributeMap &attribs); +Error ValidateCreateStreamProducerD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + const AttributeMap &attribs); +Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display, + const Stream *stream, + void *texture, + const AttributeMap &attribs); + +Error ValidateGetSyncValuesCHROMIUM(const Display *display, + const Surface *surface, + const EGLuint64KHR *ust, + const EGLuint64KHR *msc, + const EGLuint64KHR *sbc); + +Error ValidateSwapBuffersWithDamageEXT(const Display *display, + const Surface *surface, + EGLint *rects, + EGLint n_rects); + +Error ValidateGetConfigAttrib(const Display *display, const Config *config, EGLint attribute); +Error ValidateChooseConfig(const Display *display, + const AttributeMap &attribs, + EGLint configSize, + EGLint *numConfig); +Error ValidateGetConfigs(const Display *display, EGLint configSize, EGLint *numConfig); + // Other validation Error ValidateCompatibleConfigs(const Display *display, const Config *config1, const Surface *surface, const Config *config2, EGLint surfaceType); -} + +Error ValidateGetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list); +Error ValidateGetPlatformDisplayEXT(EGLenum platform, + void *native_display, + const EGLint *attrib_list); + +Error ValidateProgramCacheGetAttribANGLE(const Display *display, EGLenum attrib); + +Error ValidateProgramCacheQueryANGLE(const Display *display, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize); + +Error ValidateProgramCachePopulateANGLE(const Display *display, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize); + +Error ValidateProgramCacheResizeANGLE(const Display *display, EGLint limit, EGLenum mode); + +Error ValidateSurfaceAttrib(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint value); +Error ValidateQuerySurface(const Display *display, + const Surface *surface, + EGLint attribute, + EGLint *value); +Error ValidateQueryContext(const Display *display, + const gl::Context *context, + EGLint attribute, + EGLint *value); + +} // namespace egl + +#define ANGLE_EGL_TRY(THREAD, EXPR) \ + { \ + auto ANGLE_LOCAL_VAR = (EXPR); \ + if (ANGLE_LOCAL_VAR.isError()) \ + return THREAD->setError(ANGLE_LOCAL_VAR); \ + } + +#define ANGLE_EGL_TRY_RETURN(THREAD, EXPR, RETVAL) \ + { \ + auto ANGLE_LOCAL_VAR = (EXPR); \ + if (ANGLE_LOCAL_VAR.isError()) \ + { \ + THREAD->setError(ANGLE_LOCAL_VAR); \ + return RETVAL; \ + } \ + } #endif // LIBANGLE_VALIDATIONEGL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES.cpp b/src/3rdparty/angle/src/libANGLE/validationES.cpp index 12c76120bd..ae564b7412 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES.cpp @@ -7,2629 +7,5822 @@ // validationES.h: Validation functions for generic OpenGL ES entry point parameters #include "libANGLE/validationES.h" -#include "libANGLE/validationES2.h" -#include "libANGLE/validationES3.h" + #include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.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/Query.h" +#include "libANGLE/Texture.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" #include "common/mathutil.h" #include "common/utilities.h" +using namespace angle; + namespace gl { -const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index."; - namespace { -bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex) + +bool ValidateDrawAttribs(ValidationContext *context, + GLint primcount, + GLint maxVertex, + GLint vertexCount) { - const gl::State &state = context->getState(); + const gl::State &state = context->getGLState(); const gl::Program *program = state.getProgram(); + bool webglCompatibility = context->getExtensions().webglCompatibility; + const VertexArray *vao = state.getVertexArray(); const auto &vertexAttribs = vao->getVertexAttributes(); - size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); + const auto &vertexBindings = vao->getVertexBindings(); + size_t maxEnabledAttrib = vao->getMaxEnabledAttribute(); for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex) { const VertexAttribute &attrib = vertexAttribs[attributeIndex]; - if (program->isAttribLocationActive(attributeIndex) && attrib.enabled) + + // No need to range check for disabled attribs. + if (!attrib.enabled) { - gl::Buffer *buffer = attrib.buffer.get(); + continue; + } - if (buffer) + // If we have no buffer, then we either get an error, or there are no more checks to be + // done. + const VertexBinding &binding = vertexBindings[attrib.bindingIndex]; + gl::Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + if (webglCompatibility || !state.areClientArraysEnabled()) { - 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; - } - } + // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking + // If a vertex attribute is enabled as an array via enableVertexAttribArray but + // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer, + // then calls to drawArrays or drawElements will generate an INVALID_OPERATION + // error. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBuffer); + return false; } - else if (attrib.pointer == NULL) + else if (attrib.pointer == nullptr) { // 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.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBufferPointer); return false; } + continue; } - } - return true; -} - -} // anonymous namespace + // This needs to come after the check for client arrays as even unused attributes cannot use + // client-side arrays + if (!program->isAttribLocationActive(attributeIndex)) + { + continue; + } -bool ValidCap(const Context *context, GLenum cap) -{ - switch (cap) - { - case GL_CULL_FACE: - case GL_POLYGON_OFFSET_FILL: - case GL_SAMPLE_ALPHA_TO_COVERAGE: - case GL_SAMPLE_COVERAGE: - case GL_SCISSOR_TEST: - case GL_STENCIL_TEST: - case GL_DEPTH_TEST: - case GL_BLEND: - case GL_DITHER: - return true; + // If we're drawing zero vertices, we have enough data. + if (vertexCount <= 0 || primcount <= 0) + { + continue; + } - case GL_PRIMITIVE_RESTART_FIXED_INDEX: - case GL_RASTERIZER_DISCARD: - return (context->getClientVersion() >= 3); + GLint maxVertexElement = 0; + GLuint divisor = binding.getDivisor(); + if (divisor == 0) + { + maxVertexElement = maxVertex; + } + else + { + maxVertexElement = (primcount - 1) / divisor; + } - case GL_DEBUG_OUTPUT_SYNCHRONOUS: - case GL_DEBUG_OUTPUT: - return context->getExtensions().debug; + // We do manual overflow checks here instead of using safe_math.h because it was + // a bottleneck. Thanks to some properties of GL we know inequalities that can + // help us make the overflow checks faster. + + // The max possible attribSize is 16 for a vector of 4 32 bit values. + constexpr uint64_t kMaxAttribSize = 16; + constexpr uint64_t kIntMax = std::numeric_limits::max(); + constexpr uint64_t kUint64Max = std::numeric_limits::max(); + + // We know attribStride is given as a GLsizei which is typedefed to int. + // We also know an upper bound for attribSize. + static_assert(std::is_same::value, ""); + uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding); + uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib); + ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize); + + // Computing the max offset using uint64_t without attrib.offset is overflow + // safe. Note: Last vertex element does not take the full stride! + static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, ""); + uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize; + + // An overflow can happen when adding the offset, check for it. + uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding); + if (attribDataSizeNoOffset > kUint64Max - attribOffset) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset; - default: - return false; + // [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 (attribDataSizeWithOffset > static_cast(buffer->getSize())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientVertexBufferSize); + return false; + } } -} -bool ValidTextureTarget(const ValidationContext *context, GLenum target) -{ - switch (target) - { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - return true; - - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return (context->getClientVersion() >= 3); - - default: - return false; - } + return true; } -bool ValidTexture2DTarget(const ValidationContext *context, GLenum target) +bool ValidReadPixelsTypeEnum(ValidationContext *context, GLenum type) { - switch (target) + switch (type) { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - return true; + // Types referenced in Table 3.4 of the ES 2.0.25 spec + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5: + return context->getClientVersion() >= ES_2_0; + + // Types referenced in Table 3.2 of the ES 3.0.5 spec (Except depth stencil) + case GL_BYTE: + case GL_INT: + case GL_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + return context->getClientVersion() >= ES_3_0; + + case GL_FLOAT: + return context->getClientVersion() >= ES_3_0 || context->getExtensions().textureFloat || + context->getExtensions().colorBufferHalfFloat; + + case GL_HALF_FLOAT: + return context->getClientVersion() >= ES_3_0 || + context->getExtensions().textureHalfFloat; + + case GL_HALF_FLOAT_OES: + return context->getExtensions().colorBufferHalfFloat; default: return false; } } -bool ValidTexture3DTarget(const ValidationContext *context, GLenum target) +bool ValidReadPixelsFormatEnum(ValidationContext *context, GLenum format) { - switch (target) - { - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return (context->getClientVersion() >= 3); + switch (format) + { + // Formats referenced in Table 3.4 of the ES 2.0.25 spec (Except luminance) + case GL_RGBA: + case GL_RGB: + case GL_ALPHA: + return context->getClientVersion() >= ES_2_0; + + // Formats referenced in Table 3.2 of the ES 3.0.5 spec + case GL_RG: + case GL_RED: + case GL_RGBA_INTEGER: + case GL_RGB_INTEGER: + case GL_RG_INTEGER: + case GL_RED_INTEGER: + return context->getClientVersion() >= ES_3_0; + + case GL_SRGB_ALPHA_EXT: + case GL_SRGB_EXT: + return context->getExtensions().sRGB; + + case GL_BGRA_EXT: + return context->getExtensions().readFormatBGRA; 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 ValidationContext *context, GLenum target) +bool ValidReadPixelsFormatType(ValidationContext *context, + GLenum framebufferComponentType, + GLenum format, + GLenum type) { - switch (target) + switch (framebufferComponentType) { - case GL_TEXTURE_2D: - 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: - return true; - default: - return false; - } -} + case GL_UNSIGNED_NORMALIZED: + // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use + // ReadPixels with BGRA even if the extension is not present + return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) || + (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE); -bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target) -{ - switch (target) - { - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return true; - default: - return false; - } -} + case GL_SIGNED_NORMALIZED: + return (format == GL_RGBA && type == GL_UNSIGNED_BYTE); -bool ValidFramebufferTarget(GLenum target) -{ - static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER, - "ANGLE framebuffer enums must equal the ES3 framebuffer enums."); + case GL_INT: + return (format == GL_RGBA_INTEGER && type == GL_INT); - switch (target) - { - case GL_FRAMEBUFFER: return true; - case GL_READ_FRAMEBUFFER: return true; - case GL_DRAW_FRAMEBUFFER: return true; - default: return false; + case GL_UNSIGNED_INT: + return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT); + + case GL_FLOAT: + return (format == GL_RGBA && type == GL_FLOAT); + + default: + UNREACHABLE(); + return false; } } -bool ValidBufferTarget(const Context *context, GLenum target) +template +bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool restrictedWrapModes) { - switch (target) + switch (ConvertToGLenum(params[0])) { - case GL_ARRAY_BUFFER: - case GL_ELEMENT_ARRAY_BUFFER: - return true; - - case GL_PIXEL_PACK_BUFFER: - case GL_PIXEL_UNPACK_BUFFER: - return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3); + case GL_CLAMP_TO_EDGE: + break; - case GL_COPY_READ_BUFFER: - case GL_COPY_WRITE_BUFFER: - case GL_TRANSFORM_FEEDBACK_BUFFER: - case GL_UNIFORM_BUFFER: - return (context->getClientVersion() >= 3); + case GL_REPEAT: + case GL_MIRRORED_REPEAT: + if (restrictedWrapModes) + { + // OES_EGL_image_external and ANGLE_texture_rectangle specifies this error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidWrapModeTexture); + return false; + } + break; - default: - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureWrap); + return false; } + + return true; } -bool ValidBufferParameter(const Context *context, GLenum pname) +template +bool ValidateTextureMinFilterValue(Context *context, ParamType *params, bool restrictedMinFilter) { - const Extensions &extensions = context->getExtensions(); - - switch (pname) + switch (ConvertToGLenum(params[0])) { - 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; + case GL_NEAREST: + case GL_LINEAR: + break; - // GL_BUFFER_MAP_POINTER is a special case, and may only be - // queried with GetBufferPointerv - case GL_BUFFER_ACCESS_FLAGS: - case GL_BUFFER_MAP_OFFSET: - case GL_BUFFER_MAP_LENGTH: - return (context->getClientVersion() >= 3) || extensions.mapBufferRange; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + if (restrictedMinFilter) + { + // OES_EGL_image_external specifies this error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFilterTexture); + return false; + } + break; - default: - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureFilterParam); + return false; } + + return true; } -bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level) +template +bool ValidateTextureMagFilterValue(Context *context, ParamType *params) { - const auto &caps = context->getCaps(); - size_t maxDimension = 0; - switch (target) + switch (ConvertToGLenum(params[0])) { - case GL_TEXTURE_2D: - maxDimension = caps.max2DTextureSize; + case GL_NEAREST: + case GL_LINEAR: 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 = caps.maxCubeMapTextureSize; - break; - case GL_TEXTURE_3D: - maxDimension = caps.max3DTextureSize; - break; - case GL_TEXTURE_2D_ARRAY: - maxDimension = caps.max2DTextureSize; - break; - default: UNREACHABLE(); + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureFilterParam); + return false; } - return level <= gl::log2(static_cast(maxDimension)); + return true; } -bool ValidImageSizeParameters(const Context *context, - GLenum target, - GLint level, - GLsizei width, - GLsizei height, - GLsizei depth, - bool isSubImage) +template +bool ValidateTextureCompareModeValue(Context *context, ParamType *params) { - if (level < 0 || width < 0 || height < 0 || depth < 0) - { - return false; - } - - // 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)))) + // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 + switch (ConvertToGLenum(params[0])) { - return false; - } + case GL_NONE: + case GL_COMPARE_REF_TO_TEXTURE: + break; - if (!ValidMipLevel(context, target, level)) - { - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); + return false; } return true; } -bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat) +template +bool ValidateTextureCompareFuncValue(Context *context, ParamType *params) { - // 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; + // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 + switch (ConvertToGLenum(params[0])) + { + case GL_LEQUAL: + case GL_GEQUAL: + case GL_LESS: + case GL_GREATER: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + case GL_NEVER: + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); return false; } + + return true; } -bool ValidCompressedImageSize(const ValidationContext *context, - GLenum internalFormat, - GLsizei width, - GLsizei height) +template +bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params) { - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (!formatInfo.compressed) + if (!context->getExtensions().textureSRGBDecode) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); return false; } - if (width < 0 || height < 0) + switch (ConvertToGLenum(params[0])) { - return false; - } + case GL_DECODE_EXT: + case GL_SKIP_DECODE_EXT: + break; - if (CompressedTextureFormatRequiresExactSize(internalFormat)) - { - if ((static_cast(width) > formatInfo.compressedBlockWidth && - width % formatInfo.compressedBlockWidth != 0) || - (static_cast(height) > formatInfo.compressedBlockHeight && - height % formatInfo.compressedBlockHeight != 0)) - { + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), UnknownParameter); return false; - } } return true; } -bool ValidQueryType(const Context *context, GLenum queryType) -{ - static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal."); - static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal."); - - switch (queryType) - { - case GL_ANY_SAMPLES_PASSED: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: - return true; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: - return (context->getClientVersion() >= 3); - case GL_TIME_ELAPSED_EXT: - return context->getExtensions().disjointTimerQuery; - default: - return false; - } -} - -Program *GetValidProgram(Context *context, GLuint id) +bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context) { - // 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." - - Program *validProgram = context->getProgram(id); + const Program *program = context->getGLState().getProgram(); + const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer(); - if (!validProgram) + const auto &programOutputTypes = program->getOutputVariableTypes(); + for (size_t drawBufferIdx = 0; drawBufferIdx < programOutputTypes.size(); drawBufferIdx++) { - if (context->getShader(id)) - { - context->recordError( - Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name")); - } - else + GLenum outputType = programOutputTypes[drawBufferIdx]; + GLenum inputType = framebuffer->getDrawbufferWriteType(drawBufferIdx); + if (outputType != GL_NONE && inputType != GL_NONE && inputType != outputType) { - context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid")); + context->handleError(InvalidOperation() << "Fragment shader output type does not " + "match the bound framebuffer attachment " + "type."); + return false; } } - return validProgram; + return true; } -Shader *GetValidShader(Context *context, GLuint id) +bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context) { - // See ValidProgram for spec details. - - Shader *validShader = context->getShader(id); + const auto &glState = context->getGLState(); + const Program *program = context->getGLState().getProgram(); + const VertexArray *vao = context->getGLState().getVertexArray(); + const auto &vertexAttribs = vao->getVertexAttributes(); + const auto ¤tValues = glState.getVertexAttribCurrentValues(); - if (!validShader) + for (const sh::Attribute &shaderAttribute : program->getAttributes()) { - if (context->getProgram(id)) + // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute. + if (shaderAttribute.isBuiltIn()) { - context->recordError( - Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name")); + continue; } - else + + GLenum shaderInputType = VariableComponentType(shaderAttribute.type); + + const auto &attrib = vertexAttribs[shaderAttribute.location]; + GLenum vertexType = attrib.enabled ? GetVertexAttributeBaseType(attrib) + : currentValues[shaderAttribute.location].Type; + + if (shaderInputType != GL_NONE && vertexType != GL_NONE && shaderInputType != vertexType) { - context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid")); + context->handleError(InvalidOperation() << "Vertex shader input type does not " + "match the type of the bound vertex " + "attribute."); + return false; } } - return validShader; + return true; } -bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +} // anonymous namespace + +bool ValidTextureTarget(const ValidationContext *context, GLenum target) { - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + switch (target) { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; - if (colorAttachment >= context->getCaps().maxColorAttachments) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; - case GL_DEPTH_STENCIL_ATTACHMENT: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientMajorVersion() >= 3); - default: - context->recordError(Error(GL_INVALID_ENUM)); + case GL_TEXTURE_2D_MULTISAMPLE: + return (context->getClientVersion() >= Version(3, 1)); + + default: return false; - } } - - return true; } -bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height) +bool ValidTexture2DTarget(const ValidationContext *context, GLenum target) { switch (target) { - case GL_RENDERBUFFER: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; + + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + default: + return false; + } +} + +bool ValidTexture3DTarget(const ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientMajorVersion() >= 3); + + default: + return false; + } +} + +// Most texture GL calls are not compatible with external textures, so we have a separate validation +// function for use in the GL calls that do +bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target) +{ + return (target == GL_TEXTURE_EXTERNAL_OES) && + (context->getExtensions().eglImageExternal || + context->getExtensions().eglStreamConsumerExternal); +} + +// 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 ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + 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: + return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + default: + return false; + } +} + +bool ValidateDrawElementsInstancedBase(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const GLvoid *indices, + GLsizei primcount) +{ + if (primcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativePrimcount); + return false; + } + + if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount)) + { + return false; + } + + // No-op zero primitive count + return (primcount > 0); +} + +bool ValidateDrawArraysInstancedBase(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (primcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativePrimcount); + return false; + } + + if (!ValidateDrawArraysCommon(context, mode, first, count, primcount)) + { + return false; + } + + // No-op if zero primitive count + return (primcount > 0); +} + +bool ValidateDrawInstancedANGLE(ValidationContext *context) +{ + // Verify there is at least one active attribute with a divisor of zero + const State &state = context->getGLState(); + + Program *program = state.getProgram(); + + const auto &attribs = state.getVertexArray()->getVertexAttributes(); + const auto &bindings = state.getVertexArray()->getVertexBindings(); + for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = attribs[attributeIndex]; + const VertexBinding &binding = bindings[attrib.bindingIndex]; + if (program->isAttribLocationActive(attributeIndex) && binding.getDivisor() == 0) + { + return true; + } + } + + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoZeroDivisor); + return false; +} + +bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return true; + default: + return false; + } +} + +bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + 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: + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE: + return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + default: + return false; + } +} + +bool ValidFramebufferTarget(const ValidationContext *context, GLenum target) +{ + static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && + GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER, + "ANGLE framebuffer enums must equal the ES3 framebuffer enums."); + + switch (target) + { + case GL_FRAMEBUFFER: + return true; + + case GL_READ_FRAMEBUFFER: + case GL_DRAW_FRAMEBUFFER: + return (context->getExtensions().framebufferBlit || + context->getClientMajorVersion() >= 3); + + default: + return false; + } +} + +bool ValidBufferType(const ValidationContext *context, BufferBinding target) +{ + switch (target) + { + case BufferBinding::ElementArray: + case BufferBinding::Array: + return true; + + case BufferBinding::PixelPack: + case BufferBinding::PixelUnpack: + return (context->getExtensions().pixelBufferObject || + context->getClientMajorVersion() >= 3); + + case BufferBinding::CopyRead: + case BufferBinding::CopyWrite: + case BufferBinding::TransformFeedback: + case BufferBinding::Uniform: + return (context->getClientMajorVersion() >= 3); + + case BufferBinding::AtomicCounter: + case BufferBinding::ShaderStorage: + case BufferBinding::DrawIndirect: + case BufferBinding::DispatchIndirect: + return context->getClientVersion() >= Version(3, 1); + + default: + return false; + } +} + +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 = 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 = caps.maxCubeMapTextureSize; + break; + case GL_TEXTURE_RECTANGLE_ANGLE: + return level == 0; + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + case GL_TEXTURE_2D_MULTISAMPLE: + maxDimension = caps.max2DTextureSize; + break; + default: + UNREACHABLE(); + } + + return level <= gl::log2(static_cast(maxDimension)) && level >= 0; +} + +bool ValidImageSizeParameters(ValidationContext *context, + GLenum target, + GLint level, + GLsizei width, + GLsizei height, + GLsizei depth, + bool isSubImage) +{ + if (width < 0 || height < 0 || depth < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + // TexSubImage parameters can be NPOT without textureNPOT extension, + // as long as the destination texture is POT. + bool hasNPOTSupport = + context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0); + if (!isSubImage && !hasNPOTSupport && + (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), TextureNotPow2); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + return true; +} + +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_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE: + case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE: + return true; + + default: + return false; + } +} + +bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed) +{ + return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) || + (size % blockSize == 0); +} + +bool ValidCompressedImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint level, + GLsizei width, + GLsizei height) +{ + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (width < 0 || height < 0) + { + return false; + } + + if (CompressedTextureFormatRequiresExactSize(internalFormat)) + { + // The ANGLE extensions allow specifying compressed textures with sizes smaller than the + // block size for level 0 but WebGL disallows this. + bool smallerThanBlockSizeAllowed = + level > 0 || !context->getExtensions().webglCompatibility; + + if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth, + smallerThanBlockSizeAllowed) || + !ValidCompressedDimension(height, formatInfo.compressedBlockHeight, + smallerThanBlockSizeAllowed)) + { + return false; + } + } + + return true; +} + +bool ValidCompressedSubImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + size_t textureWidth, + size_t textureHeight) +{ + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + { + return false; + } + + if (CompressedTextureFormatRequiresExactSize(internalFormat)) + { + if (xoffset % formatInfo.compressedBlockWidth != 0 || + yoffset % formatInfo.compressedBlockHeight != 0) + { + return false; + } + + // Allowed to either have data that is a multiple of block size or is smaller than the block + // size but fills the entire mip + bool fillsEntireMip = xoffset == 0 && yoffset == 0 && + static_cast(width) == textureWidth && + static_cast(height) == textureHeight; + bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 && + (height % formatInfo.compressedBlockHeight) == 0; + if (!sizeMultipleOfBlockSize && !fillsEntireMip) + { + return false; + } + } + + return true; +} + +bool ValidImageDataSize(ValidationContext *context, + GLenum textureTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels, + GLsizei imageSize) +{ + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer == nullptr && imageSize < 0) + { + // Checks are not required + return true; + } + + // ...the data would be unpacked from the buffer object such that the memory reads required + // would exceed the data store size. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type); + ASSERT(formatInfo.internalFormat != GL_NONE); + const gl::Extents size(width, height, depth); + const auto &unpack = context->getGLState().getUnpackState(); + + bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY; + auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D); + if (endByteOrErr.isError()) + { + context->handleError(endByteOrErr.getError()); + return false; + } + + GLuint endByte = endByteOrErr.getResult(); + + if (pixelUnpackBuffer) + { + CheckedNumeric checkedEndByte(endByteOrErr.getResult()); + CheckedNumeric checkedOffset(reinterpret_cast(pixels)); + checkedEndByte += checkedOffset; + + if (!checkedEndByte.IsValid() || + (checkedEndByte.ValueOrDie() > static_cast(pixelUnpackBuffer->getSize()))) + { + // Overflow past the end of the buffer + context->handleError(InvalidOperation()); + return false; + } + } + else + { + ASSERT(imageSize >= 0); + if (pixels == nullptr && imageSize != 0) + { + context->handleError(InvalidOperation() + << "imageSize must be 0 if no texture data is provided."); + return false; + } + + if (pixels != nullptr && endByte > static_cast(imageSize)) + { + context->handleError(InvalidOperation() << "imageSize must be at least " << endByte); + return false; + } + } + + return true; +} + +bool ValidQueryType(const Context *context, GLenum queryType) +{ + static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, + "GL extension enums not equal."); + static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, + "GL extension enums not equal."); + + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return context->getClientMajorVersion() >= 3 || + context->getExtensions().occlusionQueryBoolean; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return (context->getClientMajorVersion() >= 3); + case GL_TIME_ELAPSED_EXT: + return context->getExtensions().disjointTimerQuery; + case GL_COMMANDS_COMPLETED_CHROMIUM: + return context->getExtensions().syncQuery; + default: + return false; + } +} + +bool ValidateWebGLVertexAttribPointer(ValidationContext *context, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr, + bool pureInteger) +{ + ASSERT(context->getExtensions().webglCompatibility); + // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride + // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to + // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride + // parameter exceeds 255. + constexpr GLsizei kMaxWebGLStride = 255; + if (stride > kMaxWebGLStride) + { + context->handleError(InvalidValue() + << "Stride is over the maximum stride allowed by WebGL."); + return false; + } + + // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements + // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to + // vertexAttribPointer, must be a multiple of the size of the data type passed to the call, + // or an INVALID_OPERATION error is generated. + VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger); + size_t typeSize = GetVertexFormatTypeSize(internalType); + + ASSERT(isPow2(typeSize) && typeSize > 0); + size_t sizeMask = (typeSize - 1); + if ((reinterpret_cast(ptr) & sizeMask) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), OffsetMustBeMultipleOfType); + return false; + } + + if ((stride & sizeMask) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), StrideMustBeMultipleOfType); + return false; + } + + return true; +} + +Program *GetValidProgram(ValidationContext *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." + + Program *validProgram = context->getProgram(id); + + if (!validProgram) + { + if (context->getShader(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); + } + } + + return validProgram; +} + +Shader *GetValidShader(ValidationContext *context, GLuint id) +{ + // See ValidProgram for spec details. + + Shader *validShader = context->getShader(id); + + if (!validShader) + { + if (context->getProgram(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedShaderName); + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidShaderName); + } + } + + return validShader; +} + +bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +{ + if (attachment >= GL_COLOR_ATTACHMENT1_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + if (context->getClientMajorVersion() < 3 && !context->getExtensions().drawBuffers) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + + // Color attachment 0 is validated below because it is always valid + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + if (colorAttachment >= context->getCaps().maxColorAttachments) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } + else + { + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (!context->getExtensions().webglCompatibility && + context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + } + + return true; +} + +bool ValidateRenderbufferStorageParametersBase(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); + return false; + } + if (width < 0 || height < 0 || samples < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRenderbufferWidthHeight); + return false; + } + + // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format. + GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat); + + const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat); + if (!formatCaps.renderable) + { + context->handleError(InvalidEnum()); + return false; + } + + // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be + // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains + // only sized internal formats. + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat); + if (formatInfo.internalFormat == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferInternalFormat); + return false; + } + + if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + { + context->handleError(InvalidValue()); + return false; + } + + GLuint handle = context->getGLState().getRenderbufferId(); + if (handle == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidRenderbufferTarget); + return false; + } + + return true; +} + +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } + + gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + + ASSERT(framebuffer); + if (framebuffer->id() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + // [OpenGL ES 2.0.25] Section 4.4.3 page 112 + // [OpenGL ES 3.0.2] Section 4.4.2 page 201 + // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of + // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. + if (renderbuffer != 0) + { + if (!context->getRenderbuffer(renderbuffer)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidRenderbufferTarget); + return false; + } + } + + return true; +} + +bool ValidateBlitFramebufferParameters(ValidationContext *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: + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + context->handleError(InvalidValue()); + return false; + } + + if (mask == 0) + { + // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no + // buffers are copied. + 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) + { + context->handleError(InvalidOperation()); + return false; + } + + const auto &glState = context->getGLState(); + gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer(); + gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); + + if (!readFramebuffer || !drawFramebuffer) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (readFramebuffer->id() == drawFramebuffer->id()) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (drawFramebuffer->getSamples(context) != 0) + { + context->handleError(InvalidOperation()); + return false; + } + + bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + + if (mask & GL_COLOR_BUFFER_BIT) + { + const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); + const Extensions &extensions = context->getExtensions(); + + if (readColorBuffer) + { + const Format &readFormat = readColorBuffer->getFormat(); + + for (size_t drawbufferIdx = 0; + drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) + { + const FramebufferAttachment *attachment = + drawFramebuffer->getDrawBuffer(drawbufferIdx); + if (attachment) + { + const Format &drawFormat = attachment->getFormat(); + + // 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 + // Changes with EXT_color_buffer_float: + // Case 1) is changed to fixed point OR floating point + GLenum readComponentType = readFormat.info->componentType; + GLenum drawComponentType = drawFormat.info->componentType; + bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED || + readComponentType == GL_SIGNED_NORMALIZED); + bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED || + drawComponentType == GL_SIGNED_NORMALIZED); + + if (extensions.colorBufferFloat) + { + bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT); + bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT); + + if (readFixedOrFloat != drawFixedOrFloat) + { + context->handleError(InvalidOperation() + << "If the read buffer contains fixed-point or " + "floating-point values, the draw buffer must " + "as well."); + return false; + } + } + else if (readFixedPoint != drawFixedPoint) + { + context->handleError(InvalidOperation() + << "If the read buffer contains fixed-point values, " + "the draw buffer must as well."); + return false; + } + + if (readComponentType == GL_UNSIGNED_INT && + drawComponentType != GL_UNSIGNED_INT) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readComponentType == GL_INT && drawComponentType != GL_INT) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readColorBuffer->getSamples() > 0 && + (!Format::EquivalentForBlit(readFormat, drawFormat) || !sameBounds)) + { + context->handleError(InvalidOperation()); + return false; + } + + if (context->getExtensions().webglCompatibility && + *readColorBuffer == *attachment) + { + context->handleError( + InvalidOperation() + << "Read and write color attachments cannot be the same image."); + return false; + } + } + } + + if ((readFormat.info->componentType == GL_INT || + readFormat.info->componentType == GL_UNSIGNED_INT) && + filter == GL_LINEAR) + { + context->handleError(InvalidOperation()); + return false; + } + } + // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment + // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionally as the + // situation is an application error that would lead to a crash in ANGLE. + else if (drawFramebuffer->hasEnabledDrawBuffer()) + { + context->handleError( + InvalidOperation() + << "Attempt to read from a missing color attachment of a complete framebuffer."); + 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 gl::FramebufferAttachment *readBuffer = + readFramebuffer->getAttachment(attachments[i]); + const gl::FramebufferAttachment *drawBuffer = + drawFramebuffer->getAttachment(attachments[i]); + + if (readBuffer && drawBuffer) + { + if (!Format::EquivalentForBlit(readBuffer->getFormat(), drawBuffer->getFormat())) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readBuffer->getSamples() > 0 && !sameBounds) + { + context->handleError(InvalidOperation()); + return false; + } + + if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer) + { + context->handleError( + InvalidOperation() + << "Read and write depth stencil attachments cannot be the same image."); + return false; + } + } + // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment + else if (drawBuffer) + { + context->handleError(InvalidOperation() << "Attempt to read from a missing " + "depth/stencil attachment of a " + "complete framebuffer."); + return false; + } + } + } + + // ANGLE_multiview, Revision 1: + // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the + // multi-view layout of the current draw framebuffer or read framebuffer is not NONE. + if (readFramebuffer->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "Attempt to read from a multi-view framebuffer."); + return false; + } + if (drawFramebuffer->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "Attempt to write to a multi-view framebuffer."); + return false; + } + + return true; +} + +bool ValidateReadPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length, + columns, rows, pixels)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateReadnPixelsEXT(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + void *pixels) +{ + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr, + nullptr, nullptr, pixels); +} + +bool ValidateReadnPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length, + columns, rows, data)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, GLuint *ids) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateIsQueryEXT(gl::Context *context, GLuint id) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return true; +} + +bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id) +{ + if (!ValidQueryType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + if (id == 0) + { + context->handleError(InvalidOperation() << "Query id is 0"); + return false; + } + + // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an + // of zero, if the active query object name for is non-zero (for the + // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if + // the active query for either target is non-zero), if is the name of an + // existing query object whose type does not match , or if is the + // active query object name for any query type, the error INVALID_OPERATION is + // generated. + + // Ensure no other queries are active + // NOTE: If other queries than occlusion are supported, we will need to check + // separately that: + // a) The query ID passed is not the current active query for any target/type + // 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. + + if (context->getGLState().isQueryActive(target)) + { + context->handleError(InvalidOperation() << "Other query is active"); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + // check for type mismatch + if (queryObject->getType() != target) + { + context->handleError(InvalidOperation() << "Query type does not match target"); + return false; + } + + return true; +} + +bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateBeginQueryBase(context, target, id); +} + +bool ValidateEndQueryBase(gl::Context *context, GLenum target) +{ + if (!ValidQueryType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + const Query *queryObject = context->getGLState().getActiveQuery(target); + + if (queryObject == nullptr) + { + context->handleError(InvalidOperation() << "Query target not active"); + return false; + } + + return true; +} + +bool ValidateEndQueryEXT(gl::Context *context, GLenum target) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryExtensionNotEnabled); + return false; + } + + return ValidateEndQueryBase(context, target); +} + +bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Disjoint timer query not enabled"); + return false; + } + + if (target != GL_TIMESTAMP_EXT) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryTarget); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + if (queryObject == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + if (context->getGLState().isQueryActive(queryObject)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryActive); + return false; + } + + return true; +} + +bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams) +{ + if (numParams) + { + *numParams = 0; + } + + if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidQueryType); + return false; + } + + switch (pname) + { + case GL_CURRENT_QUERY_EXT: + if (target == GL_TIMESTAMP_EXT) + { + context->handleError(InvalidEnum() << "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)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + if (numParams) + { + // All queries return only one value + *numParams = 1; + } + + return true; +} + +bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params) +{ + if (!context->getExtensions().occlusionQueryBoolean && + !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGetQueryivBase(context, target, pname, nullptr); +} + +bool ValidateGetQueryivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryivBase(context, target, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams) +{ + if (numParams) + { + *numParams = 0; + } + + Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidQueryId); + return false; + } + + if (context->getGLState().isQueryActive(queryObject)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), QueryActive); + return false; + } + + switch (pname) + { + case GL_QUERY_RESULT_EXT: + case GL_QUERY_RESULT_AVAILABLE_EXT: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + if (numParams) + { + *numParams = 1; + } + + return true; +} + +bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Timer query extension not enabled"); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + context->handleError(InvalidOperation() << "Timer query extension not enabled"); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params) +{ + if (!context->getExtensions().disjointTimerQuery && + !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectuivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + if (!context->getExtensions().disjointTimerQuery && + !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjecti64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); +} + +bool ValidateGetQueryObjectui64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params) +{ + if (!context->getExtensions().disjointTimerQuery) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetQueryObjectValueBase(context, id, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateUniformCommonBase(ValidationContext *context, + gl::Program *program, + GLint location, + GLsizei count, + const LinkedUniform **uniformOut) +{ + // TODO(Jiajia): Add image uniform check in future. + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidProgramName); + return false; + } + + if (!program->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (location == -1) + { + // Silently ignore the uniform command + return false; + } + + const auto &uniformLocations = program->getUniformLocations(); + size_t castedLocation = static_cast(location); + if (castedLocation >= uniformLocations.size()) + { + context->handleError(InvalidOperation() << "Invalid uniform location"); + return false; + } + + const auto &uniformLocation = uniformLocations[castedLocation]; + if (uniformLocation.ignored) + { + // Silently ignore the uniform command + return false; + } + + if (!uniformLocation.used()) + { + context->handleError(InvalidOperation()); + return false; + } + + const auto &uniform = program->getUniformByIndex(uniformLocation.index); + + // attempting to write an array to a non-array uniform is an INVALID_OPERATION + if (!uniform.isArray() && count > 1) + { + context->handleError(InvalidOperation()); + return false; + } + + *uniformOut = &uniform; + return true; +} + +bool ValidateUniform1ivValue(ValidationContext *context, + GLenum uniformType, + GLsizei count, + const GLint *value) +{ + // Value type is GL_INT, because we only get here from glUniform1i{v}. + // It is compatible with INT or BOOL. + // Do these cheap tests first, for a little extra speed. + if (GL_INT == uniformType || GL_BOOL == uniformType) + { + return true; + } + + if (IsSamplerType(uniformType)) + { + // Check that the values are in range. + const GLint max = context->getCaps().maxCombinedTextureImageUnits; + for (GLsizei i = 0; i < count; ++i) + { + if (value[i] < 0 || value[i] >= max) + { + context->handleError(InvalidValue() << "sampler uniform value out of range"); + return false; + } + } + return true; + } + + context->handleError(InvalidOperation() << "wrong type of value for uniform"); + return false; +} + +bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType) +{ + // Check that the value type is compatible with uniform type. + // Do the cheaper test first, for a little extra speed. + if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType) + { + return true; + } + + ANGLE_VALIDATION_ERR(context, InvalidOperation(), UniformSizeMismatch); + return false; +} + +bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType) +{ + // Check that the value type is compatible with uniform type. + if (valueType == uniformType) + { + return true; + } + + context->handleError(InvalidOperation() << "wrong type of value for uniform"); + return false; +} + +bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count) +{ + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformValue(context, valueType, uniform->type); +} + +bool ValidateUniform1iv(ValidationContext *context, + GLint location, + GLsizei count, + const GLint *value) +{ + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniform1ivValue(context, uniform->type, count, value); +} + +bool ValidateUniformMatrix(ValidationContext *context, + GLenum valueType, + GLint location, + GLsizei count, + GLboolean transpose) +{ + if (ConvertToBool(transpose) && context->getClientMajorVersion() < 3) + { + context->handleError(InvalidValue()); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = context->getGLState().getProgram(); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformMatrixValue(context, valueType, uniform->type); +} + +bool ValidateStateQuery(ValidationContext *context, + GLenum pname, + GLenum *nativeType, + unsigned int *numParams) +{ + if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + { + context->handleError(InvalidEnum()); + return false; + } + + const Caps &caps = context->getCaps(); + + if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); + + if (colorAttachment >= caps.maxDrawBuffers) + { + context->handleError(InvalidOperation()); + return false; + } + } + + switch (pname) + { + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_TEXTURE_BINDING_2D_MULTISAMPLE: + break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "ANGLE_texture_rectangle extension not present"); + return false; + } + break; + case GL_TEXTURE_BINDING_EXTERNAL_OES: + if (!context->getExtensions().eglStreamConsumerExternal && + !context->getExtensions().eglImageExternal) + { + context->handleError(InvalidEnum() << "Neither NV_EGL_stream_consumer_external " + "nor GL_OES_EGL_image_external " + "extensions enabled"); + return false; + } + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + if (context->getGLState().getReadFramebuffer()->checkStatus(context) != + GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidOperation()); + return false; + } + + const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + ASSERT(framebuffer); + + if (framebuffer->getReadBufferState() == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); + return false; + } + + const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + if (!attachment) + { + context->handleError(InvalidOperation()); + return false; + } + } + break; + + default: + break; + } + + // pname is valid, but there are no parameters to return + if (*numParams == 0) + { + return false; + } + + return true; +} + +bool ValidateRobustStateQuery(ValidationContext *context, + GLenum pname, + GLsizei bufSize, + GLenum *nativeType, + unsigned int *numParams) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateStateQuery(context, pname, nativeType, numParams)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) + { + return false; + } + + return true; +} + +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, + Format *textureFormatOut) +{ + if (xoffset < 0 || yoffset < 0 || zoffset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (width < 0 || height < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + context->handleError(InvalidValue()); + return false; + } + + if (border != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidBorder); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + const auto &state = context->getGLState(); + Framebuffer *readFramebuffer = state.getReadFramebuffer(); + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0) + { + context->handleError(InvalidOperation()); + return false; + } + + if (readFramebuffer->getReadBufferState() == GL_NONE) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); + return false; + } + + // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment + // In OpenGL ES it is undefined what happens when an operation tries to read from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionally as the + // situation is an application error that would lead to a crash in ANGLE. + const FramebufferAttachment *source = readFramebuffer->getReadColorbuffer(); + if (source == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MissingReadAttachment); + return false; + } + + // ANGLE_multiview spec, Revision 1: + // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an + // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer + // is not NONE. + if (source->getMultiviewLayout() != GL_NONE) + { + context->handleError(InvalidFramebufferOperation() + << "The active read framebuffer object has multiview attachments."); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + GLuint maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: + maxDimension = caps.max2DTextureSize; + break; + + 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 = caps.maxCubeMapTextureSize; + break; + + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; + + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + gl::Texture *texture = + state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotBound); + return false; + } + + if (texture->getImmutableFormat() && !isSubImage) + { + context->handleError(InvalidOperation()); + return false; + } + + const gl::InternalFormat &formatInfo = + isSubImage ? *texture->getFormat(target, level).info + : gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE); + + if (formatInfo.depthBits > 0 || formatInfo.compressed) + { + context->handleError(InvalidOperation()); + return false; + } + + if (isSubImage) + { + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level) || + static_cast(zoffset) >= texture->getDepth(target, level)) + { + context->handleError(InvalidValue()); + return false; + } + } + else + { + if (IsCubeMapTextureTarget(target) && width != height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CubemapIncomplete); + return false; + } + + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + int maxLevelDimension = (maxDimension >> level); + if (static_cast(width) > maxLevelDimension || + static_cast(height) > maxLevelDimension) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ResourceMaxTextureSize); + return false; + } + } + + if (textureFormatOut) + { + *textureFormatOut = texture->getFormat(target, level); + } + + // Detect texture copying feedback loops for WebGL. + if (context->getExtensions().webglCompatibility) + { + if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop); + return false; + } + } + + return true; +} + +bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count) +{ + switch (mode) + { + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDrawMode); + return false; + } + + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + const State &state = context->getGLState(); + + const Extensions &extensions = context->getExtensions(); + + // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange, + // and UnmapBuffer entry points are removed from the WebGL 2.0 API. + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14 + if (!extensions.webglCompatibility) + { + // Check for mapped buffers + // TODO(jmadill): Optimize this check for non - WebGL contexts. + if (state.hasMappedBuffer(BufferBinding::Array)) + { + context->handleError(InvalidOperation()); + return false; + } + } + + // Note: these separate values are not supported in WebGL, due to D3D's limitations. See + // Section 6.10 of the WebGL 1.0 spec. + Framebuffer *framebuffer = state.getDrawFramebuffer(); + if (context->getLimitations().noSeparateStencilRefsAndMasks || extensions.webglCompatibility) + { + const FramebufferAttachment *dsAttachment = + framebuffer->getStencilOrDepthStencilAttachment(); + GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0; + GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1; + const DepthStencilState &depthStencilState = state.getDepthStencilState(); + + bool differentRefs = state.getStencilRef() != state.getStencilBackRef(); + bool differentWritemasks = + (depthStencilState.stencilWritemask & minimumRequiredStencilMask) != + (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask); + bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) != + (depthStencilState.stencilBackMask & minimumRequiredStencilMask); + + if (differentRefs || differentWritemasks || differentMasks) + { + if (!extensions.webglCompatibility) + { + ERR() << "This ANGLE implementation does not support separate front/back stencil " + "writemasks, reference values, or stencil mask values."; + } + ANGLE_VALIDATION_ERR(context, InvalidOperation(), StencilReferenceMaskOrMismatch); + return false; + } + } + + if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + gl::Program *program = state.getProgram(); + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + // In OpenGL ES spec for UseProgram at section 7.3, trying to render without + // vertex shader stage or fragment shader stage is a undefined behaviour. + // But ANGLE should clearly generate an INVALID_OPERATION error instead of + // produce undefined result. + if (program->isLinked() && + (!program->hasLinkedVertexShader() || !program->hasLinkedFragmentShader())) + { + context->handleError(InvalidOperation() << "It is a undefined behaviour to render without " + "vertex shader stage or fragment shader stage."); + return false; + } + + if (!program->validateSamplers(nullptr, context->getCaps())) + { + context->handleError(InvalidOperation()); + return false; + } + + if (extensions.multiview) + { + const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1; + const int framebufferNumViews = framebuffer->getNumViews(); + if (framebufferNumViews != programNumViews) + { + context->handleError(InvalidOperation() << "The number of views in the active program " + "and draw framebuffer does not match."); + return false; + } + + const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback(); + if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() && + framebufferNumViews > 1) + { + context->handleError(InvalidOperation() + << "There is an active transform feedback object " + "when the number of views in the active draw " + "framebuffer is greater than 1."); + return false; + } + + if (extensions.disjointTimerQuery && framebufferNumViews > 1 && + state.isQueryActive(GL_TIME_ELAPSED_EXT)) + { + context->handleError(InvalidOperation() << "There is an active query for target " + "GL_TIME_ELAPSED_EXT when the number of " + "views in the active draw framebuffer is " + "greater than 1."); + return false; + } + } + + // Uniform buffer validation + for (unsigned int uniformBlockIndex = 0; + uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + { + const gl::InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); + GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); + const OffsetBindingPointer &uniformBuffer = + state.getIndexedUniformBuffer(blockBinding); + + if (uniformBuffer.get() == nullptr) + { + // undefined behaviour + context->handleError( + InvalidOperation() + << "It is undefined behaviour to have a used but unbound uniform buffer."); + return false; + } + + size_t uniformBufferSize = uniformBuffer.getSize(); + if (uniformBufferSize == 0) + { + // Bind the whole buffer. + uniformBufferSize = static_cast(uniformBuffer->getSize()); + } + + if (uniformBufferSize < uniformBlock.dataSize) + { + // undefined behaviour + context->handleError( + InvalidOperation() + << "It is undefined behaviour to use a uniform buffer that is too small."); + return false; + } + } + + // Do some additonal WebGL-specific validation + if (extensions.webglCompatibility) + { + // Detect rendering feedback loops for WebGL. + if (framebuffer->formsRenderingFeedbackLoopWith(state)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop); + return false; + } + + // Detect that the vertex shader input types match the attribute types + if (!ValidateVertexShaderAttributeTypeMatch(context)) + { + return false; + } + + // Detect that the color buffer types match the fragment shader output types + if (!ValidateFragmentShaderColorBufferTypeMatch(context)) + { + return false; + } + } + + // No-op if zero count + return (count > 0); +} + +bool ValidateDrawArraysCommon(ValidationContext *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (first < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStart); + return false; + } + + const State &state = context->getGLState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + 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 + // is active), (3.0.2, section 2.14, pg 86) + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidDrawModeTransformFeedback); + return false; + } + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + // Check the computation of maxVertex doesn't overflow. + // - first < 0 or count < 0 have been checked as an error condition + // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop + // From this we know maxVertex will be positive, and only need to check if it overflows GLint. + ASSERT(count > 0 && first >= 0); + int64_t maxVertex = static_cast(first) + static_cast(count) - 1; + if (maxVertex > static_cast(std::numeric_limits::max())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + if (!ValidateDrawAttribs(context, primcount, static_cast(maxVertex), count)) + { + return false; + } + + return true; +} + +bool ValidateDrawArraysInstancedANGLE(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (!context->getExtensions().instancedArrays) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount)) + { + return false; + } + + return ValidateDrawInstancedANGLE(context); +} + +bool ValidateDrawElementsBase(ValidationContext *context, GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TypeNotUnsignedShortByte); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TypeNotUnsignedShortByte); + return false; + } + + const State &state = context->getGLState(); + + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + 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) + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateDrawElementsCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + if (!ValidateDrawElementsBase(context, type)) + return false; + + const State &state = context->getGLState(); + + if (!ValidateDrawBase(context, mode, count)) + { + return false; + } + + // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange, + // and UnmapBuffer entry points are removed from the WebGL 2.0 API. + // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14 + if (!context->getExtensions().webglCompatibility) + { + // Check for mapped buffers + // TODO(jmadill): Optimize this check for non - WebGL contexts. + if (state.hasMappedBuffer(gl::BufferBinding::ElementArray)) + { + context->handleError(InvalidOperation() << "Index buffer is mapped."); + return false; + } + } + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + + GLuint typeBytes = gl::GetTypeInfo(type).bytes; + + if (context->getExtensions().webglCompatibility) + { + ASSERT(isPow2(typeBytes) && typeBytes > 0); + if ((reinterpret_cast(indices) & static_cast(typeBytes - 1)) != 0) + { + // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements + // The offset arguments to drawElements and [...], must be a multiple of the size of the + // data type passed to the call, or an INVALID_OPERATION error is generated. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), OffsetMustBeMultipleOfType); + return false; + } + + // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements + // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE + // error is generated. + if (reinterpret_cast(indices) < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + } + + if (context->getExtensions().webglCompatibility || + !context->getGLState().areClientArraysEnabled()) + { + if (!elementArrayBuffer && count > 0) + { + // [WebGL 1.0] Section 6.2 No Client Side Arrays + // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound + // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated. + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MustHaveElementArrayBinding); + return false; + } + } + + if (count > 0) + { + if (elementArrayBuffer) + { + // The max possible type size is 8 and count is on 32 bits so doing the multiplication + // in a 64 bit integer is safe. Also we are guaranteed that here count > 0. + static_assert(std::is_same::value, "GLsizei isn't the expected type"); + constexpr uint64_t kMaxTypeSize = 8; + constexpr uint64_t kIntMax = std::numeric_limits::max(); + constexpr uint64_t kUint64Max = std::numeric_limits::max(); + static_assert(kIntMax < kUint64Max / kMaxTypeSize, ""); + + uint64_t typeSize = typeBytes; + uint64_t elementCount = static_cast(count); + ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize); + + // Doing the multiplication here is overflow-safe + uint64_t elementDataSizeNoOffset = typeSize * elementCount; + + // The offset can be any value, check for overflows + uint64_t offset = static_cast(reinterpret_cast(indices)); + if (elementDataSizeNoOffset > kUint64Max - offset) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset; + if (elementDataSizeWithOffset > static_cast(elementArrayBuffer->getSize())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + ASSERT(isPow2(typeSize) && typeSize > 0); + if ((elementArrayBuffer->getSize() & (typeSize - 1)) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedByteCountType); + return false; + } + } + else if (!indices) + { + // This is an application error that would normally result in a crash, + // but we catch it and return an error + context->handleError(InvalidOperation() << "No element array buffer and no pointer."); + return false; + } + } + + if (context->getExtensions().robustBufferAccessBehavior) + { + // Here we use maxVertex = 0 and vertexCount = 1 to avoid retrieving IndexRange when robust + // access is enabled. + if (!ValidateDrawAttribs(context, primcount, 0, 1)) + { + return false; + } + } + else + { + // Use the parameter buffer to retrieve and cache the index range. + const auto ¶ms = context->getParams(); + const auto &indexRangeOpt = params.getIndexRange(); + if (!indexRangeOpt.valid()) + { + // Unexpected error. + return false; + } + + // 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(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExceedsMaxElement); + return false; + } + + if (!ValidateDrawAttribs(context, primcount, static_cast(indexRangeOpt.value().end), + static_cast(indexRangeOpt.value().vertexCount()))) + { + return false; + } + + // No op if there are no real indices in the index data (all are primitive restart). + return (indexRangeOpt.value().vertexIndexCount > 0); + } + + return true; +} + +bool ValidateDrawElementsInstancedCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount); +} + +bool ValidateDrawElementsInstancedANGLE(Context *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) +{ + if (!context->getExtensions().instancedArrays) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount)) + { + return false; + } + + return ValidateDrawInstancedANGLE(context); +} + +bool ValidateFramebufferTextureBase(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level) +{ + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + context->handleError(InvalidOperation()); + return false; + } + + if (level < 0) + { + context->handleError(InvalidValue()); + return false; + } + } + + const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); + return false; + } + + return true; +} + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) +{ + if (program == 0) + { + context->handleError(InvalidValue()); + return false; + } + + gl::Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (!programObject || !programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (!programObject->isValidUniformLocation(location)) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +static bool ValidateSizedGetUniform(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length) +{ + if (length) + { + *length = 0; + } + + if (!ValidateGetUniformBase(context, program, location)) + { + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); + + // sized queries -- ensure the provided buffer is large enough + const LinkedUniform &uniform = programObject->getUniformByLocation(location); + size_t requiredBytes = VariableExternalSize(uniform.type); + if (static_cast(bufSize) < requiredBytes) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + if (length) + { + *length = VariableComponentCount(uniform.type); + } + + return true; +} + +bool ValidateGetnUniformfvEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLfloat *params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize, nullptr); +} + +bool ValidateGetnUniformivEXT(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLint *params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize, nullptr); +} + +bool ValidateGetUniformfvRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateGetUniformivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateGetUniformuivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + // bufSize is validated in ValidateSizedGetUniform + return ValidateSizedGetUniform(context, program, location, bufSize, length); +} + +bool ValidateDiscardFramebufferBase(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + bool defaultFramebuffer) +{ + if (numAttachments < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeAttachments); + return false; + } + + for (GLsizei i = 0; i < numAttachments; ++i) + { + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31) + { + if (defaultFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), DefaultFramebufferInvalidAttachment); + return false; + } + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + { + context->handleError(InvalidOperation() << "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) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + DefaultFramebufferInvalidAttachment); + return false; + } + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (!defaultFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + DefaultFramebufferInvalidAttachment); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + 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, + GLenum target, + egl::Image *image) +{ + if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal) + { + context->handleError(InvalidOperation()); + return false; + } + + switch (target) + { + case GL_TEXTURE_2D: + if (!context->getExtensions().eglImage) + { + context->handleError(InvalidEnum() + << "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."); + } + break; + + case GL_TEXTURE_EXTERNAL_OES: + if (!context->getExtensions().eglImageExternal) + { + context->handleError(InvalidEnum() << "GL_TEXTURE_EXTERNAL_OES texture target " + "requires GL_OES_EGL_image_external."); + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + ASSERT(context->getCurrentDisplay()); + if (!context->getCurrentDisplay()->isValidImage(image)) + { + context->handleError(InvalidValue() << "EGL image is not valid."); + return false; + } + + if (image->getSamples() > 0) + { + context->handleError(InvalidOperation() + << "cannot create a 2D texture from a multisampled EGL image."); + return false; + } + + const TextureCaps &textureCaps = + context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat); + if (!textureCaps.texturable) + { + context->handleError(InvalidOperation() + << "EGL image internal format is not supported as a texture."); + return false; + } + + return true; +} + +bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, + GLenum target, + egl::Image *image) +{ + if (!context->getExtensions().eglImage) + { + context->handleError(InvalidOperation()); + return false; + } + + switch (target) + { + case GL_RENDERBUFFER: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); + return false; + } + + ASSERT(context->getCurrentDisplay()); + if (!context->getCurrentDisplay()->isValidImage(image)) + { + context->handleError(InvalidValue() << "EGL image is not valid."); + return false; + } + + const TextureCaps &textureCaps = + context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat); + if (!textureCaps.renderable) + { + context->handleError(InvalidOperation() + << "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->handleError(InvalidOperation()); + 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->handleError(InvalidEnum() << "Program binary format is not valid."); + return false; + } + + if (context->hasActiveTransformFeedback(program)) + { + // ES 3.0.4 section 2.15 page 91 + context->handleError(InvalidOperation() << "Cannot change program binary while program " + "is associated with an active transform " + "feedback object."); + 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()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + if (context->getCaps().programBinaryFormats.empty()) + { + context->handleError(InvalidOperation() << "No program binary formats supported."); + return false; + } + + return true; +} + +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) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + if (static_cast(n) > context->getCaps().maxDrawBuffers) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxDrawBuffer); + return false; + } + + ASSERT(context->getGLState().getDrawFramebuffer()); + GLuint frameBufferId = context->getGLState().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 || + bufs[colorAttachment] > GL_COLOR_ATTACHMENT31)) + { + // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi + // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this + // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects. + // 3.1 is still a bit ambiguous about the error, but future specs are + // expected to clarify that GL_INVALID_ENUM is the correct error. + context->handleError(InvalidEnum() << "Invalid buffer value"); + return false; + } + else if (bufs[colorAttachment] >= maxColorAttachment) + { + context->handleError(InvalidOperation() + << "Buffer value is greater than MAX_DRAW_BUFFERS"); + 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->handleError(InvalidOperation() + << "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->handleError(InvalidOperation() + << "n must be 1 when GL is bound to the default framebuffer"); + return false; + } + + if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) + { + context->handleError( + InvalidOperation() + << "Only NONE or BACK are valid values when drawing to the default framebuffer"); + return false; + } + } + + return true; +} + +bool ValidateGetBufferPointervBase(Context *context, + BufferBinding target, + GLenum pname, + GLsizei *length, + void **params) +{ + if (length) + { + *length = 0; + } + + if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer) + { + context->handleError( + InvalidOperation() + << "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."); + return false; + } + + if (!ValidBufferType(context, target)) + { + context->handleError(InvalidEnum() << "Buffer target not valid"); + return false; + } + + switch (pname) + { + case GL_BUFFER_MAP_POINTER: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a + // target bound to zero generate an INVALID_OPERATION error." + // GLES 3.1 section 6.6 explicitly specifies this error. + if (context->getGLState().getTargetBuffer(target) == nullptr) + { + context->handleError(InvalidOperation() + << "Can not get pointer for reserved buffer name zero."); + return false; + } + + if (length) + { + *length = 1; + } + + return true; +} + +bool ValidateUnmapBufferBase(Context *context, BufferBinding target) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr || !buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Buffer not mapped."); + return false; + } + + return true; +} + +bool ValidateMapBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); return false; } - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (!formatCaps.renderable) + if (offset < 0) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); return false; } - // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be - // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains - // only sized internal formats. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (formatInfo.pixelBytes == 0) + if (length < 0) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeLength); return false; } - if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidOperation() << "Attempted to map buffer object zero."); return false; } - GLuint handle = context->getState().getRenderbufferId(); - if (handle == 0) + // Check for buffer overflow + CheckedNumeric checkedOffset(offset); + auto checkedSize = checkedOffset + length; + + if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast(buffer->getSize())) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() << "Mapped range does not fit into buffer dimensions."); return false; } - return true; -} - -bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height) -{ - ASSERT(samples == 0 || context->getExtensions().framebufferMultisample); + // Check for invalid bits in the mask + GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; - // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal - // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is - // generated. - if (static_cast(samples) > context->getCaps().maxSamples) + if (access & ~(allAccessBits)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() + << "Invalid access bits: 0x" << std::hex << std::uppercase << access); return false; } - // 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. - // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3. - if (context->getClientVersion() >= 3) + if (length == 0) { - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (static_cast(samples) > formatCaps.getMaxSamples()) - { - context->recordError(Error(GL_OUT_OF_MEMORY)); - return false; - } + context->handleError(InvalidOperation() << "Buffer mapping length is zero."); + return false; } - return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height); -} - -bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, - GLenum renderbuffertarget, GLuint renderbuffer) -{ - if (!ValidFramebufferTarget(target)) + if (buffer->isMapped()) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "Buffer is already mapped."); return false; } - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - - ASSERT(framebuffer); - if (framebuffer->id() == 0) + // Check for invalid bit combinations + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments")); + context->handleError(InvalidOperation() + << "Need to map buffer for either reading or writing."); return false; } - if (!ValidateAttachmentTarget(context, attachment)) + GLbitfield writeOnlyBits = + GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + + if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) { + context->handleError(InvalidOperation() + << "Invalid access bits when mapping buffer for reading: 0x" + << std::hex << std::uppercase << access); return false; } - // [OpenGL ES 2.0.25] Section 4.4.3 page 112 - // [OpenGL ES 3.0.2] Section 4.4.2 page 201 - // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of - // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. - if (renderbuffer != 0) + if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) { - if (!context->getRenderbuffer(renderbuffer)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + context->handleError( + InvalidOperation() + << "The explicit flushing bit may only be set if the buffer is mapped for writing."); + return false; } - return true; + return ValidateMapBufferBase(context, target); } -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 ValidateFlushMappedBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) { - switch (filter) + if (offset < 0) { - case GL_NEAREST: - break; - case GL_LINEAR: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); return false; } - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + if (length < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeLength); return false; } - if (mask == 0) + if (!ValidBufferType(context, target)) { - // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no - // buffers are copied. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); 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) + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Attempted to flush buffer object zero."); return false; } - if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) + if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Attempted to flush a buffer not mapped for explicit flushing."); return false; } - const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); - const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + // Check for buffer overflow + CheckedNumeric checkedOffset(offset); + auto checkedSize = checkedOffset + length; - if (!readFramebuffer || !drawFramebuffer) + if (!checkedSize.IsValid() || + checkedSize.ValueOrDie() > static_cast(buffer->getMapLength())) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidValue() + << "Flushed range does not fit into buffer mapping dimensions."); return false; } - if (!readFramebuffer->checkStatus(context->getData())) + return true; +} + +bool ValidateGenOrDelete(Context *context, GLint n) +{ + if (n < 0) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); return false; } + return true; +} - if (!drawFramebuffer->checkStatus(context->getData())) +bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize) +{ + if (!context->getExtensions().robustClientMemory) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidOperation() + << "GL_ANGLE_robust_client_memory is not available."); return false; } - if (drawFramebuffer->getSamples(context->getData()) != 0) + if (bufSize < 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + return true; +} - if (mask & GL_COLOR_BUFFER_BIT) +bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams) +{ + if (bufSize < numParams) { - 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 (size_t drawbufferIdx = 0; - drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) - { - const FramebufferAttachment *attachment = - drawFramebuffer->getDrawBuffer(drawbufferIdx); - if (attachment) - { - GLenum drawInternalFormat = attachment->getInternalFormat(); - const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat); + context->handleError(InvalidOperation() << numParams << " parameters are required but " + << bufSize << " were provided."); + return false; + } - // 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 - // 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); + return true; +} - if (extensions.colorBufferFloat) - { - bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT); - bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT); +bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei *numParams) +{ + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } - 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; - } + int clientVersion = context->getClientMajorVersion(); - if (readComponentType == GL_UNSIGNED_INT && - drawComponentType != GL_UNSIGNED_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + break; - if (readComponentType == GL_INT && drawComponentType != GL_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE: + if (clientVersion < 3 || !context->getExtensions().multiview) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; - if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (clientVersion < 3 && !context->getExtensions().sRGB) + { + context->handleError(InvalidEnum()); + return false; } + break; - if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (clientVersion < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum()); return false; } - } + break; + + default: + context->handleError(InvalidEnum()); + 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++) + // Determine if the attachment is a valid enum + switch (attachment) { - if (mask & masks[i]) - { - const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]); - const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]); + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; - if (readBuffer && drawBuffer) + case GL_DEPTH_STENCIL_ATTACHMENT: + if (clientVersion < 3 && !context->isWebGL1()) { - if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; + } + break; - if (readBuffer->getSamples() > 0 && !sameBounds) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + default: + if ((clientVersion < 3 && !context->getExtensions().drawBuffers) || + attachment < GL_COLOR_ATTACHMENT0_EXT || + (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidAttachment); + return false; } - } + break; } - return true; -} + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname) -{ - switch (pname) + if (framebuffer->id() == 0) { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - case GL_CURRENT_VERTEX_ATTRIB: - return true; - - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: - // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses - // the same constant. - static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, - "ANGLE extension enums not equal to GL enums."); - return true; - - case GL_VERTEX_ATTRIB_ARRAY_INTEGER: - if (context->getClientVersion() < 3) + if (clientVersion < 3) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), DefaultFramebufferTarget); return false; } - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } -} + switch (attachment) + { + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + break; -bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) -{ - switch (pname) + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } + else { - case GL_TEXTURE_WRAP_R: - case GL_TEXTURE_SWIZZLE_R: - case GL_TEXTURE_SWIZZLE_G: - case GL_TEXTURE_SWIZZLE_B: - case GL_TEXTURE_SWIZZLE_A: - case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - case GL_TEXTURE_COMPARE_MODE: - case GL_TEXTURE_COMPARE_FUNC: - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + // Valid attachment query } - break; + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (!framebuffer->hasValidDepthStencil() && !context->isWebGL1()) + { + context->handleError(InvalidOperation()); + return false; + } + break; - default: break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + } } - switch (pname) + const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + if (attachmentObject) { - case GL_TEXTURE_WRAP_S: - case GL_TEXTURE_WRAP_T: - case GL_TEXTURE_WRAP_R: - switch (param) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + ASSERT(attachmentObject->type() == GL_RENDERBUFFER || + attachmentObject->type() == GL_TEXTURE || + attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT); - case GL_TEXTURE_MIN_FILTER: - switch (param) + switch (pname) { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObject->type() != GL_RENDERBUFFER && + attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; - case GL_TEXTURE_MAG_FILTER: - switch (param) - { - case GL_NEAREST: - case GL_LINEAR: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; - case GL_TEXTURE_USAGE_ANGLE: - switch (param) - { - case GL_NONE: - case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidAttachment); + return false; + } + break; - // we assume the parameter passed to this validation method is truncated, not rounded - if (param < 1) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (attachmentObject->type() != GL_TEXTURE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), FramebufferIncompleteAttachment); + return false; + } + break; + + default: + break; } - return true; + } + else + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - // any value is permissible - return true; + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames - case GL_TEXTURE_COMPARE_MODE: - // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 - switch (param) + switch (pname) { - case GL_NONE: - case GL_COMPARE_REF_TO_TEXTURE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + break; - case GL_TEXTURE_COMPARE_FUNC: - // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 - switch (param) - { - case GL_LEQUAL: - case GL_GEQUAL: - case GL_LESS: - case GL_GREATER: - case GL_EQUAL: - case GL_NOTEQUAL: - case GL_ALWAYS: - case GL_NEVER: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + InvalidFramebufferAttachmentParameter); + return false; + } + break; - case GL_TEXTURE_SWIZZLE_R: - case GL_TEXTURE_SWIZZLE_G: - case GL_TEXTURE_SWIZZLE_B: - case GL_TEXTURE_SWIZZLE_A: - switch (param) - { - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_ZERO: - case GL_ONE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; + default: + if (clientVersion < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), + InvalidFramebufferAttachmentParameter); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), + InvalidFramebufferAttachmentParameter); + return false; + } } - break; + } - case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - if (param < 0) + if (numParams) + { + if (pname == GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + // Only when the viewport offsets are queried we can have a varying number of output + // parameters. + const int numViews = attachmentObject ? attachmentObject->getNumViews() : 1; + *numParams = numViews * 2; + } + else + { + // For all other queries we can have only one output parameter. + *numParams = 1; } - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; } + + return true; } -bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) +bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - switch (pname) + if (!ValidateRobustEntryPoint(context, bufSize)) { - case GL_TEXTURE_MIN_FILTER: - case GL_TEXTURE_MAG_FILTER: - case GL_TEXTURE_WRAP_S: - case GL_TEXTURE_WRAP_T: - case GL_TEXTURE_WRAP_R: - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - case GL_TEXTURE_COMPARE_MODE: - case GL_TEXTURE_COMPARE_FUNC: - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); return false; } -} -bool ValidateReadPixels(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLvoid *pixels) -{ - if (width < 0 || height < 0) + if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname, + numParams)) { - 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) + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (context->getState().getReadFramebuffer()->id() != 0 && - framebuffer->getSamples(context->getData()) != 0) + return true; +} + +bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); - if (!readBuffer) + if (!ValidateGetBufferParameterBase(context, target, pname, false, length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - GLenum currentFormat = framebuffer->getImplementationColorReadFormat(); - GLenum currentType = framebuffer->getImplementationColorReadType(); - GLenum currentInternalFormat = readBuffer->getInternalFormat(); - GLuint clientVersion = context->getClientVersion(); - - bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : - ValidES3ReadFormatType(context, currentInternalFormat, format, type); - - if (!(currentFormat == format && currentType == type) && !validReadFormat) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateReadnPixelsEXT(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLsizei bufSize, - GLvoid *pixels) +bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) { - if (bufSize < 0) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number")); return false; } - GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); - const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); + if (!ValidateGetBufferParameterBase(context, target, pname, false, length)) + { + return false; + } - GLsizei outputPitch = - sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), - context->getState().getPackRowLength()); - // sized query sanity check - int requiredSize = outputPitch * height; - if (requiredSize > bufSize) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - return ValidateReadPixels(context, x, y, width, height, format, type, pixels); + return true; } -bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetProgramivBase(ValidationContext *context, + GLuint program, + GLenum pname, + GLsizei *numParams) { - if (n < 0) + // Currently, all GetProgramiv queries return 1 parameter + if (numParams) + { + *numParams = 1; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - context->recordError(Error(GL_INVALID_VALUE, "Query count < 0")); return false; } + switch (pname) + { + case GL_DELETE_STATUS: + case GL_LINK_STATUS: + case GL_VALIDATE_STATUS: + case GL_INFO_LOG_LENGTH: + case GL_ATTACHED_SHADERS: + case GL_ACTIVE_ATTRIBUTES: + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + case GL_ACTIVE_UNIFORMS: + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + break; + + case GL_PROGRAM_BINARY_LENGTH: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary) + { + context->handleError(InvalidEnum() << "Querying GL_PROGRAM_BINARY_LENGTH " + "requires GL_OES_get_program_binary or " + "ES 3.0."); + return false; + } + break; + + case GL_ACTIVE_UNIFORM_BLOCKS: + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + break; + + case GL_PROGRAM_SEPARABLE: + case GL_COMPUTE_WORK_GROUP_SIZE: + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + return true; } -bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetProgramivRobustANGLE(Context *context, + GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateGenQueriesBase(context, n, ids); -} + if (!ValidateGetProgramivBase(context, program, pname, numParams)) + { + return false; + } -bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids) -{ - if (n < 0) + if (!ValidateRobustBufferSize(context, bufSize, *numParams)) { - context->recordError(Error(GL_INVALID_VALUE, "Query count < 0")); return false; } return true; } -bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids) +bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - 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)) + if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - if (id == 0) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0")); return false; } - // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an - // of zero, if the active query object name for is non-zero (for the - // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if - // the active query for either target is non-zero), if is the name of an - // existing query object whose type does not match , or if is the - // active query object name for any query type, the error INVALID_OPERATION is - // generated. - - // Ensure no other queries are active - // NOTE: If other queries than occlusion are supported, we will need to check - // separately that: - // a) The query ID passed is not the current active query for any target/type - // 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. + return true; +} - // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the - // same time - if (context->getState().isQueryActive()) +bool ValidateGetShaderivRobustANGLE(Context *context, + GLuint shader, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Other query is active")); return false; } - Query *queryObject = context->getQuery(id, true, target); - - // check that name was obtained with glGenQueries - if (!queryObject) + if (!ValidateGetShaderivBase(context, shader, pname, length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id")); return false; } - // check for type mismatch - if (queryObject->getType() != target) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target")); return false; } return true; } -bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id) +bool ValidateGetTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateBeginQueryBase(context, target, id); + if (!ValidateGetTexParameterBase(context, target, pname, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; } -bool ValidateEndQueryBase(gl::Context *context, GLenum target) +bool ValidateGetTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!ValidQueryType(context, target)) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - const Query *queryObject = context->getState().getActiveQuery(target); + if (!ValidateGetTexParameterBase(context, target, pname, length)) + { + return false; + } - if (queryObject == nullptr) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query target not active")); return false; } return true; } -bool ValidateEndQueryEXT(gl::Context *context, GLenum target) +bool ValidateTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateEndQueryBase(context, target); + return ValidateTexParameterBase(context, target, pname, bufSize, params); } -bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target) +bool ValidateTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled")); return false; } - if (target != GL_TIMESTAMP_EXT) + return ValidateTexParameterBase(context, target, pname, bufSize, params); +} + +bool ValidateGetSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query target")); return false; } - Query *queryObject = context->getQuery(id, true, target); - if (queryObject == nullptr) + if (!ValidateGetSamplerParameterBase(context, sampler, pname, length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id")); return false; } - if (context->getState().isQueryActive(queryObject)) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query is active")); return false; } return true; } -bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname) +bool ValidateGetSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLint *params) { - if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid query type")); return false; } - switch (pname) + if (!ValidateGetSamplerParameterBase(context, sampler, pname, length)) { - 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 false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; } return true; } -bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params) +bool ValidateSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *params) { - if (!context->getExtensions().occlusionQueryBoolean && - !context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled")); return false; } - return ValidateGetQueryivBase(context, target, pname); + return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params); } -bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname) +bool ValidateSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *params) { - Query *queryObject = context->getQuery(id, false, GL_NONE); - - if (!queryObject) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist")); return false; } - if (context->getState().isQueryActive(queryObject)) + return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params); +} + +bool ValidateGetVertexAttribfvRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION, "Query currently active")); return false; } - switch (pname) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false)) { - case GL_QUERY_RESULT_EXT: - case GL_QUERY_RESULT_AVAILABLE_EXT: - break; + return false; + } - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum")); - return false; + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; } return true; } -bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params) +bool ValidateGetVertexAttribivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - 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) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false)) { - 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) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled")); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); + + return true; } -bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params) +bool ValidateGetVertexAttribPointervRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer) { - if (!context->getExtensions().disjointTimerQuery) + if (!ValidateRobustEntryPoint(context, bufSize)) { - 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) + if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - gl::Program *program = context->getState().getProgram(); - if (!program) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - if (location == -1) + return true; +} + +bool ValidateGetVertexAttribIivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) { - // Silently ignore the uniform command return false; } - if (!program->isValidUniformLocation(location)) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const LinkedUniform &uniform = program->getUniformByLocation(location); - - // attempting to write an array to a non-array uniform is an INVALID_OPERATION - if (!uniform.isArray() && count > 1) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - *uniformOut = &uniform; return true; } -bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) +bool ValidateGetVertexAttribIuivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) { - // Check for ES3 uniform entry points - if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const LinkedUniform *uniform = nullptr; - if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) + if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true)) { return false; } - GLenum targetBoolType = VariableBoolVectorType(uniformType); - bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT); - if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, - GLboolean transpose) +bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) { - // Check for ES3 uniform entry points - int rows = VariableRowCount(matrixType); - int cols = VariableColumnCount(matrixType); - if (rows != cols && context->getClientVersion() < 3) + if (!ValidateRobustEntryPoint(context, bufSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - if (transpose != GL_FALSE && context->getClientVersion() < 3) + if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - const LinkedUniform *uniform = nullptr; - if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetInternalFormativRobustANGLE(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length)) { return false; } - if (uniform->type != matrixType) + if (!ValidateRobustBufferSize(context, bufSize, *length)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } return true; } -bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) +bool ValidateVertexFormatBase(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLboolean pureInteger) { - if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + const Caps &caps = context->getCaps(); + if (attribIndex >= caps.maxVertexAttributes) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } - const Caps &caps = context->getCaps(); - - if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + if (size < 1 || size > 4) { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); - - if (colorAttachment >= caps.maxDrawBuffers) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidVertexAttrSize); + return false; } - switch (pname) + switch (type) { - case GL_TEXTURE_BINDING_2D: - case GL_TEXTURE_BINDING_CUBE_MAP: - case GL_TEXTURE_BINDING_3D: - case GL_TEXTURE_BINDING_2D_ARRAY: - if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + break; - case GL_IMPLEMENTATION_COLOR_READ_TYPE: - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: - { - Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - ASSERT(framebuffer); - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + case GL_INT: + case GL_UNSIGNED_INT: + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); return false; } + break; - const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); - if (!attachment) + case GL_FIXED: + case GL_FLOAT: + if (pureInteger) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); return false; } - } - break; + break; - default: - break; - } + case GL_HALF_FLOAT: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); + return false; + } + if (pureInteger) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); + return false; + } + break; - // pname is valid, but there are no parameters to return - if (numParams == 0) - { - return false; + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() + << "Vertex type not supported before OpenGL ES 3.0."); + return false; + } + if (pureInteger) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTypePureInt); + return false; + } + if (size != 4) + { + context->handleError(InvalidOperation() << "Type is INT_2_10_10_10_REV or " + "UNSIGNED_INT_2_10_10_10_REV and " + "size is not 4."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + return false; } return true; } -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) +// Perform validation from WebGL 2 section 5.10 "Invalid Clears": +// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the +// specified clear value and the type of a buffer that is being cleared generates an +// INVALID_OPERATION error instead of producing undefined results +bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context, + GLint drawbuffer, + const GLenum *validComponentTypes, + size_t validComponentTypeCount) { - if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) + const FramebufferAttachment *attachment = + context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer); + if (attachment) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + GLenum componentType = attachment->getFormat().info->componentType; + const GLenum *end = validComponentTypes + validComponentTypeCount; + if (std::find(validComponentTypes, end, componentType) == end) + { + context->handleError( + InvalidOperation() + << "No defined conversion between clear value and attachment format."); + return false; + } } - if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + return true; +} + +bool ValidateRobustCompressedTexImageBase(ValidationContext *context, + GLsizei imageSize, + GLsizei dataSize) +{ + if (!ValidateRobustEntryPoint(context, dataSize)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (border != 0) + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + if (dataSize < imageSize) + { + context->handleError(InvalidOperation() << "dataSize must be at least " << imageSize); + } } + return true; +} - if (!ValidMipLevel(context, target, level)) +bool ValidateGetBufferParameterBase(ValidationContext *context, + BufferBinding target, + GLenum pname, + bool pointerVersion, + GLsizei *numParams) +{ + if (numParams) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *numParams = 0; } - const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + if (!ValidBufferType(context, target)) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); return false; } - const auto &state = context->getState(); - if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) + const Buffer *buffer = context->getGLState().getTargetBuffer(target); + if (!buffer) { - context->recordError(Error(GL_INVALID_OPERATION)); + // A null buffer means that "0" is bound to the requested buffer target + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); return false; } - const gl::Caps &caps = context->getCaps(); + const Extensions &extensions = context->getExtensions(); - GLuint maxDimension = 0; - switch (target) + switch (pname) { - case GL_TEXTURE_2D: - maxDimension = caps.max2DTextureSize; - break; + case GL_BUFFER_USAGE: + case GL_BUFFER_SIZE: + break; - 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 = caps.maxCubeMapTextureSize; - break; + case GL_BUFFER_ACCESS_OES: + if (!extensions.mapBuffer) + { + context->handleError(InvalidEnum() + << "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."); + return false; + } + break; - case GL_TEXTURE_2D_ARRAY: - maxDimension = caps.max2DTextureSize; - break; + case GL_BUFFER_MAPPED: + static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal."); + if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer && + !extensions.mapBufferRange) + { + context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0, " + "GL_OES_mapbuffer or " + "GL_EXT_map_buffer_range."); + return false; + } + break; - case GL_TEXTURE_3D: - maxDimension = caps.max3DTextureSize; - break; + case GL_BUFFER_MAP_POINTER: + if (!pointerVersion) + { + context->handleError( + InvalidEnum() + << "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."); + return false; + } + break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_BUFFER_ACCESS_FLAGS: + case GL_BUFFER_MAP_OFFSET: + case GL_BUFFER_MAP_LENGTH: + if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange) + { + context->handleError(InvalidEnum() + << "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."); + return false; + } + break; - gl::Texture *texture = - state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (texture->getImmutableFormat() && !isSubImage) + // All buffer parameter queries return one value. + if (numParams) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + *numParams = 1; } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + return true; +} - if (formatInfo.depthBits > 0) +bool ValidateGetRenderbufferParameterivBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *length) +{ + if (length) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + *length = 0; } - if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height)) + if (target != GL_RENDERBUFFER) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - if (isSubImage) + Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); + if (renderbuffer == nullptr) { - if (static_cast(xoffset + width) > texture->getWidth(target, level) || - static_cast(yoffset + height) > texture->getHeight(target, level) || - static_cast(zoffset) >= texture->getDepth(target, level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidOperation(), RenderbufferNotBound); + return false; } - else + + switch (pname) { - if (IsCubeMapTextureTarget(target) && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } + case GL_RENDERBUFFER_WIDTH: + case GL_RENDERBUFFER_HEIGHT: + case GL_RENDERBUFFER_INTERNAL_FORMAT: + case GL_RENDERBUFFER_RED_SIZE: + case GL_RENDERBUFFER_GREEN_SIZE: + case GL_RENDERBUFFER_BLUE_SIZE: + case GL_RENDERBUFFER_ALPHA_SIZE: + case GL_RENDERBUFFER_DEPTH_SIZE: + case GL_RENDERBUFFER_STENCIL_SIZE: + break; - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + case GL_RENDERBUFFER_SAMPLES_ANGLE: + if (!context->getExtensions().framebufferMultisample) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - int maxLevelDimension = (maxDimension >> level); - if (static_cast(width) > maxLevelDimension || static_cast(height) > maxLevelDimension) - { - context->recordError(Error(GL_INVALID_VALUE)); + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } } - *textureFormatOut = texture->getInternalFormat(target, level); + if (length) + { + *length = 1; + } return true; } -static bool ValidateDrawBase(ValidationContext *context, - GLenum mode, - GLsizei count, - GLsizei primcount) +bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length) { - switch (mode) + if (length) { - case GL_POINTS: - case GL_LINES: - case GL_LINE_LOOP: - case GL_LINE_STRIP: - case GL_TRIANGLES: - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; + *length = 0; } - if (count < 0) + if (GetValidShader(context, shader) == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - const State &state = context->getState(); - - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ARRAY_BUFFER)) + switch (pname) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + case GL_SHADER_TYPE: + case GL_DELETE_STATUS: + case GL_COMPILE_STATUS: + case GL_INFO_LOG_LENGTH: + case GL_SHADER_SOURCE_LENGTH: + break; + + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + if (!context->getExtensions().translatedShaderSource) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (context->getLimitations().noSeparateStencilRefsAndMasks) + if (length) { - 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; - } + *length = 1; } + return true; +} - const gl::Framebuffer *fbo = state.getDrawFramebuffer(); - if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) +bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length) +{ + if (length) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; + *length = 0; } - gl::Program *program = state.getProgram(); - if (!program) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - if (!program->validateSamplers(NULL, context->getCaps())) + if (context->getTargetTexture(target) == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + // Should only be possible for external textures + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TextureNotBound); return false; } - // Uniform buffer validation - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + switch (pname) { - const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); - GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); - const OffsetBindingPointer &uniformBuffer = - state.getIndexedUniformBuffer(blockBinding); + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + break; - 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; - } + case GL_TEXTURE_USAGE_ANGLE: + if (!context->getExtensions().textureUsage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - size_t uniformBufferSize = uniformBuffer.getSize(); - if (uniformBufferSize == 0) - { - // Bind the whole buffer. - uniformBufferSize = static_cast(uniformBuffer->getSize()); - } + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; - 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.")); + case GL_TEXTURE_IMMUTABLE_FORMAT: + if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ExtensionNotEnabled); + return false; + } + break; + + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_IMMUTABLE_LEVELS: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + if (context->getClientMajorVersion() < 3) + { + context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0."); + return false; + } + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!context->getExtensions().textureSRGBDecode) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } } - // No-op if zero count - return (count > 0); + if (length) + { + *length = 1; + } + return true; } -bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +bool ValidateGetVertexAttribBase(Context *context, + GLuint index, + GLenum pname, + GLsizei *length, + bool pointer, + bool pureIntegerEntryPoint) { - if (first < 0) + if (length) + { + *length = 0; + } + + if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3) + { + context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0."); + return false; + } + + if (index >= context->getCaps().maxVertexAttributes) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } - const State &state = context->getState(); - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - 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 - // is active), (3.0.2, section 2.14, pg 86) - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + if (pointer) + { + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + } + else + { + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + case GL_CURRENT_VERTEX_ATTRIB: + break; + + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + static_assert( + GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, + "ANGLE extension enums not equal to GL enums."); + if (context->getClientMajorVersion() < 3 && + !context->getExtensions().instancedArrays) + { + context->handleError(InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_DIVISOR " + "requires OpenGL ES 3.0 or " + "GL_ANGLE_instanced_arrays."); + return false; + } + break; + + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + if (context->getClientMajorVersion() < 3) + { + context->handleError( + InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."); + return false; + } + break; + + case GL_VERTEX_ATTRIB_BINDING: + case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "Vertex Attrib Bindings require OpenGL ES 3.1."); + return false; + } + break; - if (!ValidateDrawBase(context, mode, count, primcount)) - { - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } } - if (!ValidateDrawAttribs(context, primcount, count)) + if (length) { - return false; + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + *length = 4; + } + else + { + *length = 1; + } } return true; } -bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +bool ValidateReadPixelsBase(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels) { - if (primcount < 0) + if (length != nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *length = 0; } - - if (!ValidateDrawArrays(context, mode, first, count, primcount)) + if (rows != nullptr) { - return false; + *rows = 0; + } + if (columns != nullptr) + { + *columns = 0; } - // No-op if zero primitive count - return (primcount > 0); -} - -static bool ValidateDrawInstancedANGLE(Context *context) -{ - // Verify there is at least one active attribute with a divisor of zero - const gl::State& state = context->getState(); - - gl::Program *program = state.getProgram(); - - const VertexArray *vao = state.getVertexArray(); - for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + if (width < 0 || height < 0) { - const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); - if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0) - { - return true; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; } - context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute" - "has a divisor of zero.")); - return false; -} + Framebuffer *readFramebuffer = context->getGLState().getReadFramebuffer(); -bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) -{ - if (!ValidateDrawInstancedANGLE(context)) + if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { + context->handleError(InvalidFramebufferOperation()); return false; } - return ValidateDrawArraysInstanced(context, mode, first, count, primcount); -} - -bool ValidateDrawElements(ValidationContext *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut) -{ - switch (type) + if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation()); return false; } - const State &state = context->getState(); + const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + ASSERT(framebuffer); - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused()) + if (framebuffer->getReadBufferState() == GL_NONE) { - // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced - // while transform feedback is active, (3.0.2, section 2.14, pg 86) - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ReadBufferNone); return false; } - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) + const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); + // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment + // In OpenGL ES it is undefined what happens when an operation tries to read from a missing + // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the + // situation is an application error that would lead to a crash in ANGLE. + if (readBuffer == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MissingReadAttachment); return false; } - const gl::VertexArray *vao = state.getVertexArray(); - gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); - if (!indices && !elementArrayBuffer) + // ANGLE_multiview, Revision 1: + // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the + // current read framebuffer is not NONE. + if (readBuffer->getMultiviewLayout() != GL_NONE) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidFramebufferOperation() + << "Attempting to read from a multi-view framebuffer."); return false; } - if (elementArrayBuffer) + if (context->getExtensions().webglCompatibility) { - const gl::Type &typeInfo = gl::GetTypeInfo(type); - - GLint64 offset = reinterpret_cast(indices); - GLint64 byteCount = static_cast(typeInfo.bytes) * static_cast(count)+offset; - - // check for integer overflows - if (static_cast(count) > (std::numeric_limits::max() / typeInfo.bytes) || - byteCount > static_cast(std::numeric_limits::max())) + // The ES 2.0 spec states that the format must be "among those defined in table 3.4, + // excluding formats LUMINANCE and LUMINANCE_ALPHA.". This requires validating the format + // and type before validating the combination of format and type. However, the + // dEQP-GLES3.functional.negative_api.buffer.read_pixels passes GL_LUMINANCE as a format and + // verifies that GL_INVALID_OPERATION is generated. + // TODO(geofflang): Update this check to be done in all/no cases once this is resolved in + // dEQP/WebGL. + if (!ValidReadPixelsFormatEnum(context, format)) { - context->recordError(Error(GL_OUT_OF_MEMORY)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFormat); return false; } - // Check for reading past the end of the bound buffer object - if (byteCount > elementArrayBuffer->getSize()) + if (!ValidReadPixelsTypeEnum(context, type)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); return false; } } - else if (!indices) - { - // Catch this programming error here - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - if (!ValidateDrawBase(context, mode, count, primcount)) - { - return false; - } + GLenum currentFormat = framebuffer->getImplementationColorReadFormat(context); + GLenum currentType = framebuffer->getImplementationColorReadType(context); + GLenum currentComponentType = readBuffer->getFormat().info->componentType; - // 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); - Error error = - elementArrayBuffer->getIndexRange(type, static_cast(offset), count, - state.isPrimitiveRestartEnabled(), indexRangeOut); - if (error.isError()) - { - context->recordError(error); - return false; - } - } - else - { - *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled()); - } + bool validFormatTypeCombination = + ValidReadPixelsFormatType(context, currentComponentType, format, type); - // 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) + if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination) { - context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); return false; } - if (!ValidateDrawAttribs(context, primcount, static_cast(indexRangeOut->end))) + // Check for pixel pack buffer related API errors + gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelPack); + if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped()) { + // ...the buffer object's data store is currently mapped. + context->handleError(InvalidOperation() << "Pixel pack buffer is mapped."); return false; } - // No op if there are no real indices in the index data (all are primitive restart). - return (indexRangeOut->vertexIndexCount > 0); -} + // .. the data would be packed to the buffer object such that the memory writes required + // would exceed the data store size. + const InternalFormat &formatInfo = GetInternalFormatInfo(format, type); + const gl::Extents size(width, height, 1); + const auto &pack = context->getGLState().getPackState(); -bool ValidateDrawElementsInstanced(Context *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut) -{ - if (primcount < 0) + auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false); + if (endByteOrErr.isError()) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(endByteOrErr.getError()); return false; } - if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) + size_t endByte = endByteOrErr.getResult(); + if (bufSize >= 0) { - return false; + if (pixelPackBuffer == nullptr && static_cast(bufSize) < endByte) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } } - // No-op zero primitive count - return (primcount > 0); -} - -bool ValidateDrawElementsInstancedANGLE(Context *context, - GLenum mode, - GLsizei count, - GLenum type, - const GLvoid *indices, - GLsizei primcount, - IndexRange *indexRangeOut) -{ - if (!ValidateDrawInstancedANGLE(context)) + if (pixelPackBuffer != nullptr) { - return false; - } - - return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut); -} + CheckedNumeric checkedEndByte(endByte); + CheckedNumeric checkedOffset(reinterpret_cast(pixels)); + checkedEndByte += checkedOffset; -bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level) -{ - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + if (checkedEndByte.ValueOrDie() > static_cast(pixelPackBuffer->getSize())) + { + // Overflow past the end of the buffer + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ParamOverflow); + return false; + } } - if (!ValidateAttachmentTarget(context, attachment)) + if (pixelPackBuffer == nullptr && length != nullptr) { - return false; + if (endByte > static_cast(std::numeric_limits::max())) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + *length = static_cast(endByte); } - if (texture != 0) - { - gl::Texture *tex = context->getTexture(texture); + auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) { + angle::CheckedNumeric clippedExtent(length); + if (start < 0) + { + // "subtract" the area that is less than 0 + clippedExtent += start; + } - if (tex == NULL) + const int readExtent = start + length; + if (readExtent > bufferSize) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + // Subtract the region to the right of the read buffer + clippedExtent -= (readExtent - bufferSize); } - if (level < 0) + if (!clippedExtent.IsValid()) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + return 0; } - } - const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); + return std::max(clippedExtent.ValueOrDie(), 0); + }; - if (framebuffer->id() == 0) + if (columns != nullptr) { - context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments")); - return false; + *columns = getClippedExtent(x, width, readBuffer->getSize().width); + } + + if (rows != nullptr) + { + *rows = getClippedExtent(y, height, readBuffer->getSize().height); } return true; } -bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) +template +bool ValidateTexParameterBase(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const ParamType *params) { - // 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) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + if (context->getTargetTexture(target) == nullptr) { + // Should only be possible for external textures + ANGLE_VALIDATION_ERR(context, InvalidEnum(), TextureNotBound); return false; } - if (texture != 0) + const GLsizei minBufSize = 1; + if (bufSize >= 0 && bufSize < minBufSize) { - gl::Texture *tex = context->getTexture(texture); - ASSERT(tex); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); + return false; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + if (target == GL_TEXTURE_EXTERNAL_OES && + !context->getExtensions().eglImageExternalEssl3) + { + context->handleError(InvalidEnum() << "ES3 texture parameters are not " + "available without " + "GL_OES_EGL_image_external_essl3."); + return false; + } + break; - const gl::Caps &caps = context->getCaps(); + default: + break; + } - switch (textarget) + if (target == GL_TEXTURE_2D_MULTISAMPLE) + { + switch (pname) { - case GL_TEXTURE_2D: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + context->handleError(InvalidEnum() + << "Invalid parameter for 2D multisampled textures."); + return false; + } + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: { - if (level > gl::log2(caps.max2DTextureSize)) + bool restrictedWrapModes = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureWrapModeValue(context, params, restrictedWrapModes)) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (tex->getTarget() != GL_TEXTURE_2D) - { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } break; - 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: + case GL_TEXTURE_MIN_FILTER: { - if (level > gl::log2(caps.maxCubeMapTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + bool restrictedMinFilter = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureMinFilterValue(context, params, restrictedMinFilter)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level)); - if (internalFormatInfo.compressed) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - return true; -} - -bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) -{ - if (program == 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return false; - } - - if (!programObject || !programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!programObject->isValidUniformLocation(location)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_TEXTURE_MAG_FILTER: + if (!ValidateTextureMagFilterValue(context, params)) + { + return false; + } + break; - return true; -} + case GL_TEXTURE_USAGE_ANGLE: + if (!context->getExtensions().textureUsage) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } -bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params) -{ - return ValidateGetUniformBase(context, program, location); -} + switch (ConvertToGLenum(params[0])) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + break; -bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params) -{ - return ValidateGetUniformBase(context, program, location); -} + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; -static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize) -{ - if (!ValidateGetUniformBase(context, program, location)) - { - return false; - } + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_anisotropic is not enabled."); + return false; + } - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); + // we assume the parameter passed to this validation method is truncated, not rounded + if (params[0] < 1) + { + context->handleError(InvalidValue() << "Max anisotropy must be at least 1."); + return false; + } + break; - // sized queries -- ensure the provided buffer is large enough - const LinkedUniform &uniform = programObject->getUniformByLocation(location); - size_t requiredBytes = VariableExternalSize(uniform.type); - if (static_cast(bufSize) < requiredBytes) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + break; - return true; -} + case GL_TEXTURE_COMPARE_MODE: + if (!ValidateTextureCompareModeValue(context, params)) + { + return false; + } + break; -bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} + case GL_TEXTURE_COMPARE_FUNC: + if (!ValidateTextureCompareFuncValue(context, params)) + { + return false; + } + break; -bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + switch (ConvertToGLenum(params[0])) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ZERO: + case GL_ONE: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; -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; - } + case GL_TEXTURE_BASE_LEVEL: + if (ConvertToGLint(params[0]) < 0) + { + context->handleError(InvalidValue() << "Base level must be at least 0."); + return false; + } + if (target == GL_TEXTURE_EXTERNAL_OES && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for external textures."); + return false; + } + if (target == GL_TEXTURE_2D_MULTISAMPLE && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for multisampled textures."); + return false; + } + if (target == GL_TEXTURE_RECTANGLE_ANGLE && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for rectangle textures."); + return false; + } + break; - for (GLsizei i = 0; i < numAttachments; ++i) - { - if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) - { - if (defaultFramebuffer) + case GL_TEXTURE_MAX_LEVEL: + if (ConvertToGLint(params[0]) < 0) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); return false; } + break; - if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + case GL_DEPTH_STENCIL_TEXTURE_MODE: + if (context->getClientVersion() < Version(3, 1)) { - context->recordError(Error(GL_INVALID_OPERATION, - "Requested color attachment is greater than the maximum supported color attachments")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumRequiresGLES31); return false; } - } - else - { - switch (attachments[i]) + switch (ConvertToGLenum(params[0])) { - 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")); + case GL_DEPTH_COMPONENT: + case GL_STENCIL_INDEX: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment")); + } + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!ValidateTextureSRGBDecodeValue(context, params)) + { return false; } - } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + 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; - } +template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *); +template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *); - if (marker == nullptr) +bool ValidateVertexAttribIndex(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); return false; } return true; } -bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker) +bool ValidateGetActiveUniformBlockivBase(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei *length) { - // Note that debug marker calls must not set error state + if (length) + { + *length = 0; + } - if (length < 0) + if (context->getClientMajorVersion() < 3) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - if (length > 0 && marker == nullptr) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { return false; } - return true; -} - -bool ValidateEGLImageTargetTexture2DOES(Context *context, - egl::Display *display, - GLenum target, - egl::Image *image) -{ - if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal) + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() + << "uniformBlockIndex exceeds active uniform block count."); return false; } - switch (target) + switch (pname) { - case GL_TEXTURE_2D: + case GL_UNIFORM_BLOCK_BINDING: + case GL_UNIFORM_BLOCK_DATA_SIZE: + case GL_UNIFORM_BLOCK_NAME_LENGTH: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: break; default: - context->recordError(Error(GL_INVALID_ENUM, "invalid texture target.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - if (!display->isValidImage(image)) + if (length) { - context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid.")); - return false; + if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) + { + const InterfaceBlock &uniformBlock = + programObject->getUniformBlockByIndex(uniformBlockIndex); + *length = static_cast(uniformBlock.memberIndexes.size()); + } + else + { + *length = 1; + } } - if (image->getSamples() > 0) + return true; +} + +template +bool ValidateSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + ParamType *params) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, - "cannot create a 2D texture from a multisampled EGL image.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat()); - if (!textureCaps.texturable) + if (!context->isSampler(sampler)) { - context->recordError(Error(GL_INVALID_OPERATION, - "EGL image internal format is not supported as a texture.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidSampler); return false; } - return true; -} - -bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, - egl::Display *display, - GLenum target, - egl::Image *image) -{ - if (!context->getExtensions().eglImage) + const GLsizei minBufSize = 1; + if (bufSize >= 0 && bufSize < minBufSize) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InsufficientBufferSize); return false; } - switch (target) + switch (pname) { - case GL_RENDERBUFFER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + if (!ValidateTextureWrapModeValue(context, params, false)) + { + return false; + } break; - default: - context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target.")); - return false; - } + case GL_TEXTURE_MIN_FILTER: + if (!ValidateTextureMinFilterValue(context, params, false)) + { + return false; + } + break; - if (!display->isValidImage(image)) - { - context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid.")); - return false; - } + case GL_TEXTURE_MAG_FILTER: + if (!ValidateTextureMagFilterValue(context, params)) + { + return false; + } + break; - 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; - } + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + break; - return true; -} + case GL_TEXTURE_COMPARE_MODE: + if (!ValidateTextureCompareModeValue(context, params)) + { + return false; + } + break; -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; - } + case GL_TEXTURE_COMPARE_FUNC: + if (!ValidateTextureCompareFuncValue(context, params)) + { + return false; + } + break; - return true; -} + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!ValidateTextureSRGBDecodeValue(context, params)) + { + return false; + } + break; -bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n) -{ - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } return true; } -bool ValidateGenVertexArraysBase(Context *context, GLsizei n) +template bool ValidateSamplerParameterBase(Context *, GLuint, GLenum, GLsizei, GLfloat *); +template bool ValidateSamplerParameterBase(Context *, GLuint, GLenum, GLsizei, GLint *); + +bool ValidateGetSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei *length) { - if (n < 0) + if (length) { - context->recordError(Error(GL_INVALID_VALUE)); - return false; + *length = 0; } - return true; -} - -bool ValidateProgramBinaryBase(Context *context, - GLuint program, - GLenum binaryFormat, - const void *binary, - GLint length) -{ - Program *programObject = GetValidProgram(context, program); - if (programObject == nullptr) + if (context->getClientMajorVersion() < 3) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - const std::vector &programBinaryFormats = context->getCaps().programBinaryFormats; - if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == - programBinaryFormats.end()) + if (!context->isSampler(sampler)) { - context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidSampler); 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) + switch (pname) { - return false; + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + break; + + case GL_TEXTURE_SRGB_DECODE_EXT: + if (!context->getExtensions().textureSRGBDecode) + { + context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; } - if (!programObject->isLinked()) + if (length) { - context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked.")); - return false; + *length = 1; } - return true; } -bool ValidateCopyTexImage2D(ValidationContext *context, - GLenum target, - GLint level, - GLenum internalformat, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLint border) +bool ValidateGetInternalFormativBase(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams) { - if (context->getClientVersion() < 3) + if (numParams) { - return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0, - 0, x, y, width, height, border); + *numParams = 0; } - 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)) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); 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) + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) { - context->recordError( - Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS")); + context->handleError(InvalidEnum() << "Internal format is not renderable."); 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++) + switch (target) { - const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; + case GL_RENDERBUFFER: + break; - 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")); + case GL_TEXTURE_2D_MULTISAMPLE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidOperation() + << "Texture target requires at least OpenGL ES 3.1."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTarget); 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 (bufSize < 0) { - if (n != 1) - { - context->recordError(Error(GL_INVALID_OPERATION, - "n must be 1 when GL is bound to the default framebuffer")); - return false; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InsufficientBufferSize); + 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")); + GLsizei maxWriteParams = 0; + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + maxWriteParams = 1; + break; + + case GL_SAMPLES: + maxWriteParams = static_cast(formatCaps.sampleCounts.size()); + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); 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) + if (numParams) { - return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, - yoffset, x, y, width, height, 0); + // glGetInternalFormativ will not overflow bufSize + *numParams = std::min(bufSize, maxWriteParams); } - return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset, - yoffset, 0, x, y, width, height, 0); + return true; } } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES.h b/src/3rdparty/angle/src/libANGLE/validationES.h index 5d8486a6ab..e29432b8c3 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES.h +++ b/src/3rdparty/angle/src/libANGLE/validationES.h @@ -10,9 +10,11 @@ #define LIBANGLE_VALIDATION_ES_H_ #include "common/mathutil.h" +#include "libANGLE/PackedGLEnums.h" #include #include +#include namespace egl { @@ -23,21 +25,24 @@ class Image; namespace gl { class Context; +struct Format; +struct LinkedUniform; class Program; class Shader; class ValidationContext; -bool ValidCap(const Context *context, GLenum cap); bool ValidTextureTarget(const ValidationContext *context, GLenum target); bool ValidTexture2DTarget(const ValidationContext *context, GLenum target); bool ValidTexture3DTarget(const ValidationContext *context, GLenum target); +bool ValidTextureExternalTarget(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 ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target); +bool ValidFramebufferTarget(const ValidationContext *context, GLenum target); +bool ValidBufferType(const ValidationContext *context, BufferBinding target); +bool ValidBufferParameter(const ValidationContext *context, GLenum pname, GLsizei *numParams); bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level); -bool ValidImageSizeParameters(const Context *context, +bool ValidImageSizeParameters(ValidationContext *context, GLenum target, GLint level, GLsizei width, @@ -46,30 +51,60 @@ bool ValidImageSizeParameters(const Context *context, bool isSubImage); bool ValidCompressedImageSize(const ValidationContext *context, GLenum internalFormat, + GLint level, GLsizei width, GLsizei height); +bool ValidCompressedSubImageSize(const ValidationContext *context, + GLenum internalFormat, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + size_t textureWidth, + size_t textureHeight); +bool ValidImageDataSize(ValidationContext *context, + GLenum textureTarget, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels, + GLsizei imageSize); + bool ValidQueryType(const Context *context, GLenum queryType); +bool ValidateWebGLVertexAttribPointer(ValidationContext *context, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr, + bool pureInteger); + // 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); +Program *GetValidProgram(ValidationContext *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); +Shader *GetValidShader(ValidationContext *context, GLuint id); bool ValidateAttachmentTarget(Context *context, GLenum attachment); -bool ValidateRenderbufferStorageParametersBase(Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); -bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); - -bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment, - GLenum renderbuffertarget, GLuint renderbuffer); - -bool ValidateBlitFramebufferParameters(Context *context, +bool ValidateRenderbufferStorageParametersBase(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); +bool ValidateFramebufferRenderbufferParameters(Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); + +bool ValidateBlitFramebufferParameters(ValidationContext *context, GLint srcX0, GLint srcY0, GLint srcX1, @@ -81,20 +116,30 @@ bool ValidateBlitFramebufferParameters(Context *context, GLbitfield mask, GLenum filter); -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); - -bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); - -bool ValidateSamplerObjectParameter(Context *context, GLenum pname); - -bool ValidateReadPixels(Context *context, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLvoid *pixels); +bool ValidateReadPixelsBase(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels); +bool ValidateReadPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels); bool ValidateReadnPixelsEXT(Context *context, GLint x, GLint y, @@ -103,30 +148,97 @@ bool ValidateReadnPixelsEXT(Context *context, 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); + void *pixels); +bool ValidateReadnPixelsRobustANGLE(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data); + +bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, GLuint *ids); bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids); +bool ValidateIsQueryEXT(gl::Context *context, GLuint id); 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 ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams); bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params); -bool ValidateGetQueryObjectValueBase(Context *context, GLenum target, GLenum pname); +bool ValidateGetQueryivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +bool ValidateGetQueryObjectValueBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *numParams); bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params); +bool ValidateGetQueryObjectivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params); +bool ValidateGetQueryObjectuivRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params); +bool ValidateGetQueryObjecti64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + 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, +bool ValidateGetQueryObjectui64vRobustANGLE(Context *context, + GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params); + +bool ValidateUniformCommonBase(ValidationContext *context, + gl::Program *program, + GLint location, + GLsizei count, + const LinkedUniform **uniformOut); +bool ValidateUniform1ivValue(ValidationContext *context, + GLenum uniformType, + GLsizei count, + const GLint *value); +bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType); +bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType); +bool ValidateUniform(ValidationContext *context, GLenum uniformType, GLint location, GLsizei count); +bool ValidateUniformMatrix(ValidationContext *context, + GLenum matrixType, + GLint location, + GLsizei count, GLboolean transpose); -bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); +bool ValidateStateQuery(ValidationContext *context, + GLenum pname, + GLenum *nativeType, + unsigned int *numParams); + +bool ValidateRobustStateQuery(ValidationContext *context, + GLenum pname, + GLsizei bufSize, + GLenum *nativeType, + unsigned int *numParams); bool ValidateCopyTexImageParametersBase(ValidationContext *context, GLenum target, @@ -141,69 +253,99 @@ bool ValidateCopyTexImageParametersBase(ValidationContext *context, 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(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); + Format *textureFormatOut); + +bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count); +bool ValidateDrawArraysCommon(ValidationContext *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); +bool ValidateDrawArraysInstancedBase(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); +bool ValidateDrawArraysInstancedANGLE(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); + +bool ValidateDrawElementsBase(ValidationContext *context, GLenum type); +bool ValidateDrawElementsCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount); + +bool ValidateDrawElementsInstancedCommon(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount); 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); + const void *indices, + GLsizei primcount); -bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); -bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params); -bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params); -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 ValidateFramebufferTextureBase(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level); -bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments, bool defaultFramebuffer); +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); +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 ValidateGetUniformfvRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetUniformivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params); +bool ValidateGetUniformuivRobustANGLE(Context *context, + GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *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, @@ -217,28 +359,243 @@ bool ValidateGetProgramBinaryBase(Context *context, 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; + +bool ValidateGetBufferPointervBase(Context *context, + BufferBinding target, + GLenum pname, + GLsizei *length, + void **params); +bool ValidateUnmapBufferBase(Context *context, BufferBinding target); +bool ValidateMapBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateFlushMappedBufferRangeBase(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateGenOrDelete(Context *context, GLint n); + +bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize); +bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams); + +bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei *numParams); +bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + +bool ValidateGetBufferParameterBase(ValidationContext *context, + BufferBinding target, + GLenum pname, + bool pointerVersion, + GLsizei *numParams); +bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params); + +bool ValidateGetProgramivBase(ValidationContext *context, + GLuint program, + GLenum pname, + GLsizei *numParams); +bool ValidateGetProgramivRobustANGLE(Context *context, + GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + +bool ValidateGetRenderbufferParameterivBase(Context *context, + GLenum target, + GLenum pname, + GLsizei *length); +bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length); +bool ValidateGetShaderivRobustANGLE(Context *context, + GLuint shader, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length); +bool ValidateGetTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +template +bool ValidateTexParameterBase(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const ParamType *params); +bool ValidateTexParameterfvRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params); +bool ValidateTexParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params); + +bool ValidateGetSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLfloat *params); +bool ValidateGetSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLuint bufSize, + GLsizei *length, + GLint *params); + +bool ValidateSamplerParameterfvRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *params); +bool ValidateSamplerParameterivRobustANGLE(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *params); + +bool ValidateGetVertexAttribBase(Context *context, + GLuint index, + GLenum pname, + GLsizei *length, + bool pointer, + bool pureIntegerEntryPoint); +bool ValidateGetVertexAttribfvRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); + +bool ValidateGetVertexAttribivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetVertexAttribPointervRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer); + +bool ValidateGetVertexAttribIivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetVertexAttribIuivRobustANGLE(Context *context, + GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); + +bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetInternalFormativRobustANGLE(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateVertexFormatBase(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLboolean pureInteger); + +bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context, + GLint drawbuffer, + const GLenum *validComponentTypes, + size_t validComponentTypeCount); + +bool ValidateRobustCompressedTexImageBase(ValidationContext *context, + GLsizei imageSize, + GLsizei dataSize); + +bool ValidateVertexAttribIndex(ValidationContext *context, GLuint index); + +bool ValidateGetActiveUniformBlockivBase(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei *length); + +bool ValidateGetSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei *length); + +template +bool ValidateSamplerParameterBase(Context *context, + GLuint sampler, + GLenum pname, + GLsizei bufSize, + ParamType *params); + +bool ValidateGetInternalFormativBase(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *numParams); + } // namespace gl -#endif // LIBANGLE_VALIDATION_ES_H_ +#endif // LIBANGLE_VALIDATION_ES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp index 2e5b955e99..5e505aa607 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES2.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp @@ -7,16 +7,24 @@ // validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters #include "libANGLE/validationES2.h" -#include "libANGLE/validationES.h" + +#include + +#include "common/mathutil.h" +#include "common/string_utils.h" +#include "common/utilities.h" #include "libANGLE/Context.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/VertexArray.h" #include "libANGLE/formatutils.h" -#include "libANGLE/FramebufferAttachment.h" - -#include "common/mathutil.h" -#include "common/utilities.h" +#include "libANGLE/validationES.h" +#include "libANGLE/validationES3.h" namespace gl { @@ -45,9 +53,9 @@ bool IsPartialBlit(gl::Context *context, return true; } - if (context->getState().isScissorTestEnabled()) + if (context->getGLState().isScissorTestEnabled()) { - const Rectangle &scissor = context->getState().getScissor(); + const Rectangle &scissor = context->getGLState().getScissor(); return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width || scissor.height < writeSize.height; } @@ -55,1702 +63,6289 @@ bool IsPartialBlit(gl::Context *context, return false; } -} // anonymous namespace +template +bool ValidatePathInstances(gl::Context *context, + GLsizei numPaths, + const void *paths, + GLuint pathBase) +{ + const auto *array = static_cast(paths); + + for (GLsizei i = 0; i < numPaths; ++i) + { + const GLuint pathName = array[i] + pathBase; + if (context->hasPath(pathName) && !context->hasPathData(pathName)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + } + return true; +} -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 ValidateInstancedPathParameters(gl::Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum transformType, + const GLfloat *transformValues) { - if (!ValidTexture2DDestinationTarget(context, target)) + if (!context->getExtensions().pathRendering) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); return false; } - if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + if (paths == nullptr) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() << "No path name array."); return false; } - if (level < 0 || xoffset < 0 || - std::numeric_limits::max() - xoffset < width || - std::numeric_limits::max() - yoffset < height) + if (numPaths < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue() << "Invalid (negative) numPaths."); return false; } - if (!isSubImage && !isCompressed && internalformat != format) + if (!angle::IsValueInRangeForNumericType(numPaths)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); return false; } - const gl::Caps &caps = context->getCaps(); + std::uint32_t pathNameTypeSize = 0; + std::uint32_t componentCount = 0; - if (target == GL_TEXTURE_2D) + switch (pathNameType) { - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); + case GL_UNSIGNED_BYTE: + pathNameTypeSize = sizeof(GLubyte); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_BYTE: + pathNameTypeSize = sizeof(GLbyte); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_UNSIGNED_SHORT: + pathNameTypeSize = sizeof(GLushort); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_SHORT: + pathNameTypeSize = sizeof(GLshort); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_UNSIGNED_INT: + pathNameTypeSize = sizeof(GLuint); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + case GL_INT: + pathNameTypeSize = sizeof(GLint); + if (!ValidatePathInstances(context, numPaths, paths, pathBase)) + return false; + break; + + default: + context->handleError(InvalidEnum() << "Invalid path name type."); return false; - } } - else if (IsCubeMapTextureTarget(target)) + + switch (transformType) { - if (!isSubImage && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); + case GL_NONE: + componentCount = 0; + break; + case GL_TRANSLATE_X_CHROMIUM: + case GL_TRANSLATE_Y_CHROMIUM: + componentCount = 1; + break; + case GL_TRANSLATE_2D_CHROMIUM: + componentCount = 2; + break; + case GL_TRANSLATE_3D_CHROMIUM: + componentCount = 3; + break; + case GL_AFFINE_2D_CHROMIUM: + case GL_TRANSPOSE_AFFINE_2D_CHROMIUM: + componentCount = 6; + break; + case GL_AFFINE_3D_CHROMIUM: + case GL_TRANSPOSE_AFFINE_3D_CHROMIUM: + componentCount = 12; + break; + default: + context->handleError(InvalidEnum() << "Invalid transformation."); return false; - } + } + if (componentCount != 0 && transformValues == nullptr) + { + context->handleError(InvalidValue() << "No transform array given."); + return false; + } - if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || - static_cast(height) > (caps.maxCubeMapTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); + angle::CheckedNumeric checkedSize(0); + checkedSize += (numPaths * pathNameTypeSize); + checkedSize += (numPaths * sizeof(GLfloat) * componentCount); + if (!checkedSize.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + return true; +} + +bool IsValidCopyTextureSourceInternalFormatEnum(GLenum internalFormat) +{ + // Table 1.1 from the CHROMIUM_copy_texture spec + switch (GetUnsizedFormat(internalFormat)) + { + case GL_RED: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGB: + case GL_RGBA: + case GL_RGB8: + case GL_RGBA8: + case GL_BGRA_EXT: + case GL_BGRA8_EXT: + return true; + + default: return false; - } } - else +} + +bool IsValidCopySubTextureSourceInternalFormat(GLenum internalFormat) +{ + return IsValidCopyTextureSourceInternalFormatEnum(internalFormat); +} + +bool IsValidCopyTextureDestinationInternalFormatEnum(GLint internalFormat) +{ + // Table 1.0 from the CHROMIUM_copy_texture spec + switch (internalFormat) + { + case GL_RGB: + case GL_RGBA: + case GL_RGB8: + case GL_RGBA8: + case GL_BGRA_EXT: + case GL_BGRA8_EXT: + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + case GL_R8: + case GL_R8UI: + case GL_RG8: + case GL_RG8UI: + case GL_SRGB8: + case GL_RGB565: + case GL_RGB8UI: + case GL_RGB10_A2: + case GL_SRGB8_ALPHA8: + case GL_RGB5_A1: + case GL_RGBA4: + case GL_RGBA8UI: + case GL_RGB9_E5: + case GL_R16F: + case GL_R32F: + case GL_RG16F: + case GL_RG32F: + case GL_RGB16F: + case GL_RGB32F: + case GL_RGBA16F: + case GL_RGBA32F: + case GL_R11F_G11F_B10F: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_ALPHA: + return true; + + default: + return false; + } +} + +bool IsValidCopySubTextureDestionationInternalFormat(GLenum internalFormat) +{ + return IsValidCopyTextureDestinationInternalFormatEnum(internalFormat); +} + +bool IsValidCopyTextureDestinationFormatType(Context *context, GLint internalFormat, GLenum type) +{ + if (!IsValidCopyTextureDestinationInternalFormatEnum(internalFormat)) { - context->recordError(Error(GL_INVALID_ENUM)); return false; } - gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - if (!texture) + if (!ValidES3FormatCombination(GetUnsizedFormat(internalFormat), type, internalFormat)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Invalid combination of type and internalFormat."); return false; } - if (isSubImage) + const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type); + if (!internalFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - if (format != GL_NONE) - { - if (gl::GetSizedInternalFormat(format, type) != texture->getInternalFormat(target, level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } + return false; + } - if (static_cast(xoffset + width) > texture->getWidth(target, level) || - static_cast(yoffset + height) > texture->getHeight(target, level)) - { - context->recordError(Error(GL_INVALID_VALUE)); + return true; +} + +bool IsValidCopyTextureDestinationTargetEnum(Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + 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: + return true; + + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + default: return false; - } + } +} + +bool IsValidCopyTextureDestinationTarget(Context *context, GLenum textureType, GLenum target) +{ + if (IsCubeMapTextureTarget(target)) + { + return textureType == GL_TEXTURE_CUBE_MAP; } else { - if (texture->getImmutableFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); + return textureType == target; + } +} + +bool IsValidCopyTextureSourceTarget(Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + + // TODO(geofflang): accept GL_TEXTURE_EXTERNAL_OES if the texture_external extension is + // supported + + default: return false; - } } +} - // Verify zero border - if (border != 0) +bool IsValidCopyTextureSourceLevel(Context *context, GLenum target, GLint level) +{ + if (!ValidMipLevel(context, target, level)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (isCompressed) + if (level > 0 && context->getClientVersion() < ES_3_0) { - GLenum actualInternalFormat = - isSubImage ? texture->getInternalFormat(target, level) : internalformat; - switch (actualInternalFormat) + return false; + } + + return true; +} + +bool IsValidCopyTextureDestinationLevel(Context *context, + GLenum target, + GLint level, + GLsizei width, + GLsizei height) +{ + if (!ValidMipLevel(context, target, level)) + { + return false; + } + + const Caps &caps = context->getCaps(); + if (target == GL_TEXTURE_2D) + { + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_ENUM)); - 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, "internalformat is not a supported compressed internal format")); - return false; + return false; } - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } - else + else if (IsCubeMapTextureTarget(target)) { - // validate by itself (used as secondary key below) - switch (type) + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - case GL_UNSIGNED_INT_24_8_OES: - case GL_HALF_FLOAT_OES: - case GL_FLOAT: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); return false; } + } - // validate + combinations - // - invalid -> sets INVALID_ENUM - // - invalid + combination -> sets INVALID_OPERATION - switch (format) - { - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED: - case GL_RG: - if (!context->getExtensions().textureRG) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGB: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_SRGB_EXT: - case GL_SRGB_ALPHA_EXT: - if (!context->getExtensions().sRGB) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - break; - case GL_DEPTH_COMPONENT: - switch (type) - { - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_DEPTH_STENCIL_OES: - switch (type) - { - case GL_UNSIGNED_INT_24_8_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + return true; +} + +bool IsValidStencilFunc(GLenum func) +{ + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + return true; + + default: return false; - } + } +} - switch (format) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); +bool IsValidStencilFace(GLenum face) +{ + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + return true; + + default: + return false; + } +} + +bool IsValidStencilOp(GLenum op) +{ + switch (op) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + return true; + + default: + return false; + } +} + +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) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + { + context->handleError(InvalidValue() << "Invalid texture dimensions."); + return false; + } + + Format textureFormat = Format::Invalid(); + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, 0, x, y, width, height, border, + &textureFormat)) + { + return false; + } + + const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer(); + GLenum colorbufferFormat = + framebuffer->getReadColorbuffer()->getFormat().info->sizedInternalFormat; + const auto &formatInfo = *textureFormat.info; + + // [OpenGL ES 2.0.24] table 3.9 + if (isSubImage) + { + switch (formatInfo.format) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_R32F && + colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGBA32F && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + 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_OES: + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + + if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + } + else + { + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + else + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidOperation() + << "ETC lossy decode formats can't be copied to."); + return false; + } + else + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH_STENCIL_OES: + case GL_DEPTH24_STENCIL8_OES: + if (context->getExtensions().depthTextures) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + default: + context->handleError(InvalidEnum()); + return false; + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidCap(const Context *context, GLenum cap, bool queryOnly) +{ + switch (cap) + { + // EXT_multisample_compatibility + case GL_MULTISAMPLE_EXT: + case GL_SAMPLE_ALPHA_TO_ONE_EXT: + return context->getExtensions().multisampleCompatibility; + + case GL_CULL_FACE: + case GL_POLYGON_OFFSET_FILL: + case GL_SAMPLE_ALPHA_TO_COVERAGE: + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + return true; + + case GL_PRIMITIVE_RESTART_FIXED_INDEX: + case GL_RASTERIZER_DISCARD: + return (context->getClientMajorVersion() >= 3); + + case GL_DEBUG_OUTPUT_SYNCHRONOUS: + case GL_DEBUG_OUTPUT: + return context->getExtensions().debug; + + case GL_BIND_GENERATES_RESOURCE_CHROMIUM: + return queryOnly && context->getExtensions().bindGeneratesResource; + + case GL_CLIENT_ARRAYS_ANGLE: + return queryOnly && context->getExtensions().clientArrays; + + case GL_FRAMEBUFFER_SRGB_EXT: + return context->getExtensions().sRGBWriteControl; + + case GL_SAMPLE_MASK: + return context->getClientVersion() >= Version(3, 1); + + case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: + return queryOnly && context->getExtensions().robustResourceInitialization; + + default: + return false; + } +} + +// Return true if a character belongs to the ASCII subset as defined in GLSL ES 1.0 spec section +// 3.1. +bool IsValidESSLCharacter(unsigned char c) +{ + // Printing characters are valid except " $ ` @ \ ' DEL. + if (c >= 32 && c <= 126 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && + c != '\'') + { + return true; + } + + // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid. + if (c >= 9 && c <= 13) + { + return true; + } + + return false; +} + +bool IsValidESSLString(const char *str, size_t len) +{ + for (size_t i = 0; i < len; i++) + { + if (!IsValidESSLCharacter(str[i])) + { + return false; + } + } + + return true; +} + +bool IsValidESSLShaderSourceString(const char *str, size_t len, bool lineContinuationAllowed) +{ + enum class ParseState + { + // Have not seen an ASCII non-whitespace character yet on + // this line. Possible that we might see a preprocessor + // directive. + BEGINING_OF_LINE, + + // Have seen at least one ASCII non-whitespace character + // on this line. + MIDDLE_OF_LINE, + + // Handling a preprocessor directive. Passes through all + // characters up to the end of the line. Disables comment + // processing. + IN_PREPROCESSOR_DIRECTIVE, + + // Handling a single-line comment. The comment text is + // replaced with a single space. + IN_SINGLE_LINE_COMMENT, + + // Handling a multi-line comment. Newlines are passed + // through to preserve line numbers. + IN_MULTI_LINE_COMMENT + }; + + ParseState state = ParseState::BEGINING_OF_LINE; + size_t pos = 0; + + while (pos < len) + { + char c = str[pos]; + char next = pos + 1 < len ? str[pos + 1] : 0; + + // Check for newlines + if (c == '\n' || c == '\r') + { + if (state != ParseState::IN_MULTI_LINE_COMMENT) + { + state = ParseState::BEGINING_OF_LINE; + } + + pos++; + continue; + } + + switch (state) + { + case ParseState::BEGINING_OF_LINE: + if (c == ' ') + { + // Maintain the BEGINING_OF_LINE state until a non-space is seen + pos++; + } + else if (c == '#') + { + state = ParseState::IN_PREPROCESSOR_DIRECTIVE; + pos++; + } + else + { + // Don't advance, re-process this character with the MIDDLE_OF_LINE state + state = ParseState::MIDDLE_OF_LINE; + } + break; + + case ParseState::MIDDLE_OF_LINE: + if (c == '/' && next == '/') + { + state = ParseState::IN_SINGLE_LINE_COMMENT; + pos++; + } + else if (c == '/' && next == '*') + { + state = ParseState::IN_MULTI_LINE_COMMENT; + pos++; + } + else if (lineContinuationAllowed && c == '\\' && (next == '\n' || next == '\r')) + { + // Skip line continuation characters + } + else if (!IsValidESSLCharacter(c)) + { + return false; + } + pos++; + break; + + case ParseState::IN_PREPROCESSOR_DIRECTIVE: + // Line-continuation characters may not be permitted. + // Otherwise, just pass it through. Do not parse comments in this state. + if (!lineContinuationAllowed && c == '\\') + { + return false; + } + pos++; + break; + + case ParseState::IN_SINGLE_LINE_COMMENT: + // Line-continuation characters are processed before comment processing. + // Advance string if a new line character is immediately behind + // line-continuation character. + if (c == '\\' && (next == '\n' || next == '\r')) + { + pos++; + } + pos++; + break; + + case ParseState::IN_MULTI_LINE_COMMENT: + if (c == '*' && next == '/') + { + state = ParseState::MIDDLE_OF_LINE; + pos++; + } + pos++; + break; + } + } + + return true; +} + +bool ValidateWebGLNamePrefix(ValidationContext *context, const GLchar *name) +{ + ASSERT(context->isWebGL()); + + // WebGL 1.0 [Section 6.16] GLSL Constructs + // Identifiers starting with "webgl_" and "_webgl_" are reserved for use by WebGL. + if (strncmp(name, "webgl_", 6) == 0 || strncmp(name, "_webgl_", 7) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), WebglBindAttribLocationReservedPrefix); + return false; + } + + return true; +} + +bool ValidateWebGLNameLength(ValidationContext *context, size_t length) +{ + ASSERT(context->isWebGL()); + + if (context->isWebGL1() && length > 256) + { + // WebGL 1.0 [Section 6.21] Maxmimum Uniform and Attribute Location Lengths + // WebGL imposes a limit of 256 characters on the lengths of uniform and attribute + // locations. + ANGLE_VALIDATION_ERR(context, InvalidValue(), WebglNameLengthLimitExceeded); + + return false; + } + else if (length > 1024) + { + // WebGL 2.0 [Section 4.3.2] WebGL 2.0 imposes a limit of 1024 characters on the lengths of + // uniform and attribute locations. + ANGLE_VALIDATION_ERR(context, InvalidValue(), Webgl2NameLengthLimitExceeded); + return false; + } + + return true; +} + +} // 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, + GLsizei imageSize, + const void *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) + { + context->handleError(InvalidValue()); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (xoffset < 0 || std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ResourceMaxTextureSize); + return false; + } + + // From GL_CHROMIUM_color_buffer_float_rgb[a]: + // GL_RGB[A] / GL_RGB[A]32F becomes an allowable format / internalformat parameter pair for + // TexImage2D. The restriction in section 3.7.1 of the OpenGL ES 2.0 spec that the + // internalformat parameter and format parameter of TexImage2D must match is lifted for this + // case. + bool nonEqualFormatsAllowed = + (internalformat == GL_RGB32F && context->getExtensions().colorBufferFloatRGB) || + (internalformat == GL_RGBA32F && context->getExtensions().colorBufferFloatRGBA); + + if (!isSubImage && !isCompressed && internalformat != format && !nonEqualFormatsAllowed) + { + context->handleError(InvalidOperation()); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + if (target == GL_TEXTURE_2D) + { + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + } + else if (IsCubeMapTextureTarget(target)) + { + if (!isSubImage && width != height) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CubemapFacesEqualDimensions); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + } + else + { + context->handleError(InvalidEnum()); + return false; + } + + gl::Texture *texture = + context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + if (isSubImage) + { + const InternalFormat &textureInternalFormat = *texture->getFormat(target, level).info; + if (textureInternalFormat.internalFormat == GL_NONE) + { + context->handleError(InvalidOperation() << "Texture level does not exist."); + return false; + } + + if (format != GL_NONE) + { + if (GetInternalFormatInfo(format, type).sizedInternalFormat != + textureInternalFormat.sizedInternalFormat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TypeMismatch); + return false; + } + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level)) + { + context->handleError(InvalidValue()); + return false; + } + + if (width > 0 && height > 0 && pixels == nullptr && + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), PixelDataNull); + return false; + } + } + else + { + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation()); + return false; + } + } + + // Verify zero border + if (border != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidBorder); + return false; + } + + if (isCompressed) + { + GLenum actualInternalFormat = + isSubImage ? texture->getFormat(target, level).info->sizedInternalFormat + : internalformat; + switch (actualInternalFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + if (!context->getExtensions().textureCompressionS3TCsRGB) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + if (isSubImage) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidInternalFormat); + return false; + } + + if (isSubImage) + { + if (!ValidCompressedSubImageSize(context, actualInternalFormat, xoffset, yoffset, width, + height, texture->getWidth(target, level), + texture->getHeight(target, level))) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } + + if (format != actualInternalFormat) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidFormat); + return false; + } + } + else + { + if (!ValidCompressedImageSize(context, actualInternalFormat, level, width, height)) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } + } + } + else + { + // validate by itself (used as secondary key below) + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8_OES: + case GL_HALF_FLOAT_OES: + case GL_FLOAT: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + return false; + } + + // validate + combinations + // - invalid -> sets INVALID_ENUM + // - invalid + combination -> sets INVALID_OPERATION + switch (format) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_RED: + case GL_RG: + if (!context->getExtensions().textureRG) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + if (!context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_BGRA_EXT: + if (!context->getExtensions().textureFormatBGRA8888) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + if (!context->getExtensions().sRGB) + { + context->handleError(InvalidEnum()); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are + // handled below + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidOperation()); + return false; + } + else + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidOperation() + << "ETC lossy decode formats can't work with this type."); + return false; + } + else + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->getExtensions().depthTextures) + { + context->handleError(InvalidValue()); + return false; + } + if (target != GL_TEXTURE_2D) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTargetAndFormat); + return false; + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), PixelDataNotNull); + return false; + } + if (level != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), LevelNotZero); + return false; + } + break; + default: + break; + } + + if (!isSubImage) + { + switch (internalformat) + { + case GL_RGBA32F: + if (!context->getExtensions().colorBufferFloatRGBA) + { + context->handleError(InvalidValue() + << "Sized GL_RGBA32F internal format requires " + "GL_CHROMIUM_color_buffer_float_rgba"); + return false; + } + if (type != GL_FLOAT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + if (format != GL_RGBA) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + + case GL_RGB32F: + if (!context->getExtensions().colorBufferFloatRGB) + { + context->handleError(InvalidValue() + << "Sized GL_RGB32F internal format requires " + "GL_CHROMIUM_color_buffer_float_rgb"); + return false; + } + if (type != GL_FLOAT) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + if (format != GL_RGB) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + break; + + default: + break; + } + } + + if (type == GL_FLOAT) + { + if (!context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->getExtensions().textureHalfFloat) + { + context->handleError(InvalidEnum()); + return false; + } + } + } + + GLenum sizeCheckFormat = isSubImage ? format : internalformat; + if (!ValidImageDataSize(context, target, width, height, 1, sizeCheckFormat, type, pixels, + imageSize)) + { + return false; + } + + return true; +} + +bool ValidateES2TexStorageParameters(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP && + target != GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum()); + return false; + } + + if (width < 1 || height < 1 || levels < 1) + { + context->handleError(InvalidValue()); + return false; + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + context->handleError(InvalidValue()); + return false; + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + context->handleError(InvalidOperation()); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); + if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + { + context->handleError(InvalidEnum()); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + break; + case GL_TEXTURE_RECTANGLE_ANGLE: + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); + return false; + } + if (formatInfo.compressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP: + if (static_cast(width) > caps.maxCubeMapTextureSize || + static_cast(height) > caps.maxCubeMapTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if (levels != 1 && !context->getExtensions().textureNPOT) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + context->handleError(InvalidOperation()); + return false; + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + context->handleError(InvalidEnum() + << "ANGLE_lossy_etc_decode extension is not supported."); + return false; + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->getExtensions().textureHalfFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_R8_EXT: + case GL_RG8_EXT: + if (!context->getExtensions().textureRG) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_R16F_EXT: + case GL_RG16F_EXT: + if (!context->getExtensions().textureRG || !context->getExtensions().textureHalfFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_R32F_EXT: + case GL_RG32F_EXT: + if (!context->getExtensions().textureRG || !context->getExtensions().textureFloat) + { + context->handleError(InvalidEnum()); + return false; + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->getExtensions().depthTextures) + { + context->handleError(InvalidEnum()); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->handleError(InvalidOperation()); + return false; + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + context->handleError(InvalidOperation()); + return false; + } + break; + default: + break; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->handleError(InvalidOperation()); + return false; + } + + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateDiscardFramebufferEXT(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments) +{ + if (!context->getExtensions().discardFramebuffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + bool defaultFramebuffer = false; + + switch (target) + { + case GL_FRAMEBUFFER: + defaultFramebuffer = + (context->getGLState().getTargetFramebuffer(GL_FRAMEBUFFER)->id() == 0); + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, + defaultFramebuffer); +} + +bool ValidateBindVertexArrayOES(Context *context, GLuint array) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateBindVertexArrayBase(context, array); +} + +bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n, const GLuint *arrays) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenVertexArraysOES(Context *context, GLsizei n, GLuint *arrays) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateIsVertexArrayOES(Context *context, GLuint array) +{ + if (!context->getExtensions().vertexArrayObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + return true; +} + +bool ValidateProgramBinaryOES(Context *context, + GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) +{ + if (!context->getExtensions().getProgramBinary) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidDebugSource(source, false) && source != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + if (!ValidDebugType(type) && type != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugType); + return false; + } + + if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSeverity); + return false; + } + + if (count > 0) + { + if (source == GL_DONT_CARE || type == GL_DONT_CARE) + { + context->handleError( + InvalidOperation() + << "If count is greater than zero, source and severity cannot be GL_DONT_CARE."); + return false; + } + + if (severity != GL_DONT_CARE) + { + context->handleError( + InvalidOperation() + << "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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!context->getGLState().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)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + if (!ValidDebugType(type)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugType); + return false; + } + + if (!ValidDebugSource(source, true)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + size_t messageLength = (length < 0) ? strlen(buf) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->handleError(InvalidValue() + << "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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + 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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0 && messageLog != nullptr) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return true; +} + +bool ValidatePushDebugGroupKHR(Context *context, + GLenum source, + GLuint id, + GLsizei length, + const GLchar *message) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidDebugSource(source, true)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidDebugSource); + return false; + } + + size_t messageLength = (length < 0) ? strlen(message) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->handleError(InvalidValue() + << "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH."); + return false; + } + + size_t currentStackSize = context->getGLState().getDebug().getGroupStackDepth(); + if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth) + { + context + ->handleError(StackOverflow() + << "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups."); + return false; + } + + return true; +} + +bool ValidatePopDebugGroupKHR(Context *context) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + size_t currentStackSize = context->getGLState().getDebug().getGroupStackDepth(); + if (currentStackSize <= 1) + { + context->handleError(StackUnderflow() << "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->handleError(InvalidValue() << "name is not a valid buffer."); + return false; + } + return true; + + case GL_SHADER: + if (context->getShader(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid shader."); + return false; + } + return true; + + case GL_PROGRAM: + if (context->getProgram(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid program."); + return false; + } + return true; + + case GL_VERTEX_ARRAY: + if (context->getVertexArray(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid vertex array."); + return false; + } + return true; + + case GL_QUERY: + if (context->getQuery(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid query."); + return false; + } + return true; + + case GL_TRANSFORM_FEEDBACK: + if (context->getTransformFeedback(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid transform feedback."); + return false; + } + return true; + + case GL_SAMPLER: + if (context->getSampler(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid sampler."); + return false; + } + return true; + + case GL_TEXTURE: + if (context->getTexture(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid texture."); + return false; + } + return true; + + case GL_RENDERBUFFER: + if (context->getRenderbuffer(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid renderbuffer."); + return false; + } + return true; + + case GL_FRAMEBUFFER: + if (context->getFramebuffer(name) == nullptr) + { + context->handleError(InvalidValue() << "name is not a valid framebuffer."); + return false; + } + return true; + + default: + context->handleError(InvalidEnum() << "Invalid identifier."); + return false; + } +} + +static bool ValidateLabelLength(Context *context, GLsizei length, const GLchar *label) +{ + size_t labelLength = 0; + + if (length < 0) + { + if (label != nullptr) + { + labelLength = strlen(label); + } + } + else + { + labelLength = static_cast(length); + } + + if (labelLength > context->getExtensions().maxLabelLength) + { + context->handleError(InvalidValue() << "Label length is larger than GL_MAX_LABEL_LENGTH."); + return false; + } + + return true; +} + +bool ValidateObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei length, + const GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + if (!ValidateLabelLength(context, length, label)) + { + return false; + } + + return true; +} + +bool ValidateGetObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + return true; +} + +static bool ValidateObjectPtrName(Context *context, const void *ptr) +{ + if (context->getSync(reinterpret_cast(const_cast(ptr))) == nullptr) + { + context->handleError(InvalidValue() << "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) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + if (!ValidateLabelLength(context, length, label)) + { + return false; + } + + return true; +} + +bool ValidateGetObjectPtrLabelKHR(Context *context, + const void *ptr, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + return true; +} + +bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) +{ + if (!context->getExtensions().debug) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return false; + } + + // TODO: represent this in Context::getQueryParameterInfo. + switch (pname) + { + case GL_DEBUG_CALLBACK_FUNCTION: + case GL_DEBUG_CALLBACK_USER_PARAM: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + 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->handleError(InvalidOperation() << "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->handleError(InvalidOperation() << "Scaling and flipping in " + "BlitFramebufferANGLE not supported by this " + "implementation."); + return false; + } + + if (filter == GL_LINEAR) + { + context->handleError(InvalidEnum() << "Linear blit not supported in this extension"); + return false; + } + + Framebuffer *readFramebuffer = context->getGLState().getReadFramebuffer(); + Framebuffer *drawFramebuffer = context->getGLState().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->handleError(InvalidOperation()); + 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->handleError(InvalidOperation()); + return false; + } + + // Return an error if the destination formats do not match + if (!Format::EquivalentForBlit(attachment->getFormat(), + readColorAttachment->getFormat())) + { + context->handleError(InvalidOperation()); + return false; + } + } + } + + if (readFramebuffer->getSamples(context) != 0 && + IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0, + srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + context->handleError(InvalidOperation()); + 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 + context->handleError(InvalidOperation() << "Only whole-buffer depth and " + "stencil blits are supported by " + "this extension."); + return false; + } + + if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0) + { + context->handleError(InvalidOperation()); + return false; + } + } + } + } + + return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, + dstX1, dstY1, mask, filter); +} + +bool ValidateClear(ValidationContext *context, GLbitfield mask) +{ + Framebuffer *fbo = context->getGLState().getDrawFramebuffer(); + if (fbo->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) + { + context->handleError(InvalidFramebufferOperation()); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidClearMask); + return false; + } + + if (context->getExtensions().webglCompatibility && (mask & GL_COLOR_BUFFER_BIT) != 0) + { + constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED, + GL_SIGNED_NORMALIZED}; + + for (GLuint drawBufferIdx = 0; drawBufferIdx < fbo->getDrawbufferStateCount(); + drawBufferIdx++) + { + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawBufferIdx, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } + } + + return true; +} + +bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs) +{ + if (!context->getExtensions().drawBuffers) + { + context->handleError(InvalidOperation() << "Extension not supported."); + return false; + } + + return ValidateDrawBuffersBase(context, n, bufs); +} + +bool ValidateTexImage2D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, -1, pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, 1, border, format, type, -1, + pixels); +} + +bool ValidateTexImage2DRobust(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, bufSize, + pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, 1, border, format, type, bufSize, + pixels); +} + +bool ValidateTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) +{ + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, width, height, 0, format, type, -1, pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, 0, width, height, 1, 0, format, type, -1, + pixels); +} + +bool ValidateTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (context->getClientMajorVersion() < 3) + { + return ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, width, height, 0, format, type, bufSize, + pixels); + } + + ASSERT(context->getClientMajorVersion() >= 3); + return ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, 0, width, height, 1, 0, format, type, bufSize, + pixels); +} + +bool ValidateCompressedTexImage2D(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + if (!ValidateES2TexImageParameters(context, target, level, internalformat, true, false, 0, + 0, width, height, border, GL_NONE, GL_NONE, -1, data)) + { + return false; + } + } + else + { + ASSERT(context->getClientMajorVersion() >= 3); + if (!ValidateES3TexImage2DParameters(context, target, level, internalformat, true, false, 0, + 0, 0, width, height, 1, border, GL_NONE, GL_NONE, -1, + data)) + { + return false; + } + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalformat); + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, 1)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), CompressedTextureDimensionsMustMatchData); + return false; + } + + if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); + return false; + } + + return true; +} + +bool ValidateCompressedTexImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexImage2D(context, target, level, internalformat, width, height, + border, imageSize, data); +} +bool ValidateCompressedTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexSubImage2D(context, target, level, xoffset, yoffset, width, height, + format, imageSize, data); +} + +bool ValidateCompressedTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + if (!ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, width, height, 0, format, GL_NONE, -1, data)) + { + return false; + } + } + else + { + ASSERT(context->getClientMajorVersion() >= 3); + if (!ValidateES3TexImage2DParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, 0, width, height, 1, 0, format, GL_NONE, -1, + data)) + { + return false; + } + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(format); + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, 1)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateGetBufferPointervOES(Context *context, + BufferBinding target, + GLenum pname, + void **params) +{ + return ValidateGetBufferPointervBase(context, target, pname, nullptr, params); +} + +bool ValidateMapBufferOES(Context *context, BufferBinding target, GLenum access) +{ + if (!context->getExtensions().mapBuffer) + { + context->handleError(InvalidOperation() << "Map buffer extension not available."); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (buffer == nullptr) + { + context->handleError(InvalidOperation() << "Attempted to map buffer object zero."); + return false; + } + + if (access != GL_WRITE_ONLY_OES) + { + context->handleError(InvalidEnum() << "Non-write buffer mapping not supported."); + return false; + } + + if (buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Buffer is already mapped."); + return false; + } + + return ValidateMapBufferBase(context, target); +} + +bool ValidateUnmapBufferOES(Context *context, BufferBinding target) +{ + if (!context->getExtensions().mapBuffer) + { + context->handleError(InvalidOperation() << "Map buffer extension not available."); + return false; + } + + return ValidateUnmapBufferBase(context, target); +} + +bool ValidateMapBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (!context->getExtensions().mapBufferRange) + { + context->handleError(InvalidOperation() << "Map buffer range extension not available."); + return false; + } + + return ValidateMapBufferRangeBase(context, target, offset, length, access); +} + +bool ValidateMapBufferBase(Context *context, BufferBinding target) +{ + Buffer *buffer = context->getGLState().getTargetBuffer(target); + ASSERT(buffer != nullptr); + + // Check if this buffer is currently being used as a transform feedback output buffer + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + if (transformFeedback != nullptr && transformFeedback->isActive()) + { + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const auto &transformFeedbackBuffer = transformFeedback->getIndexedBuffer(i); + if (transformFeedbackBuffer.get() == buffer) + { + context->handleError(InvalidOperation() + << "Buffer is currently bound for transform feedback."); + return false; + } + } + } + + return true; +} + +bool ValidateFlushMappedBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) +{ + if (!context->getExtensions().mapBufferRange) + { + context->handleError(InvalidOperation() << "Map buffer range extension not available."); + return false; + } + + return ValidateFlushMappedBufferRangeBase(context, target, offset, length); +} + +bool ValidateBindTexture(Context *context, GLenum target, GLuint texture) +{ + Texture *textureObject = context->getTexture(texture); + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TypeMismatch); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isTextureGenerated(texture)) + { + context->handleError(InvalidOperation() << "Texture was not generated"); + return false; + } + + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + break; + + case GL_TEXTURE_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "Context does not support GL_ANGLE_texture_rectangle"); + return false; + } + break; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES3Required); + return false; + } + break; + + case GL_TEXTURE_2D_MULTISAMPLE: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + case GL_TEXTURE_EXTERNAL_OES: + if (!context->getExtensions().eglImageExternal && + !context->getExtensions().eglStreamConsumerExternal) + { + context->handleError(InvalidEnum() << "External texture extension not enabled"); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + return true; +} + +bool ValidateBindUniformLocationCHROMIUM(Context *context, + GLuint program, + GLint location, + const GLchar *name) +{ + if (!context->getExtensions().bindUniformLocation) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_bind_uniform_location is not available."); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (location < 0) + { + context->handleError(InvalidValue() << "Location cannot be less than 0."); + return false; + } + + const Caps &caps = context->getCaps(); + if (static_cast(location) >= + (caps.maxVertexUniformVectors + caps.maxFragmentUniformVectors) * 4) + { + context->handleError(InvalidValue() << "Location must be less than " + "(MAX_VERTEX_UNIFORM_VECTORS + " + "MAX_FRAGMENT_UNIFORM_VECTORS) * 4"); + return false; + } + + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; + } + + if (strncmp(name, "gl_", 3) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NameBeginsWithGL); + return false; + } + + return true; +} + +bool ValidateCoverageModulationCHROMIUM(Context *context, GLenum components) +{ + if (!context->getExtensions().framebufferMixedSamples) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_framebuffer_mixed_samples is not available."); + return false; + } + switch (components) + { + case GL_RGB: + case GL_RGBA: + case GL_ALPHA: + case GL_NONE: + break; + default: + context->handleError( + InvalidEnum() + << "GLenum components is not one of GL_RGB, GL_RGBA, GL_ALPHA or GL_NONE."); + return false; + } + + return true; +} + +// CHROMIUM_path_rendering + +bool ValidateMatrix(Context *context, GLenum matrixMode, const GLfloat *matrix) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (matrixMode != GL_PATH_MODELVIEW_CHROMIUM && matrixMode != GL_PATH_PROJECTION_CHROMIUM) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidMatrixMode); + return false; + } + if (matrix == nullptr) + { + context->handleError(InvalidOperation() << "Invalid matrix."); + return false; + } + return true; +} + +bool ValidateMatrixMode(Context *context, GLenum matrixMode) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (matrixMode != GL_PATH_MODELVIEW_CHROMIUM && matrixMode != GL_PATH_PROJECTION_CHROMIUM) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidMatrixMode); + return false; + } + return true; +} + +bool ValidateGenPaths(Context *context, GLsizei range) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + // range = 0 is undefined in NV_path_rendering. + // we add stricter semantic check here and require a non zero positive range. + if (range <= 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRange); + return false; + } + + if (!angle::IsValueInRangeForNumericType(range)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + return true; +} + +bool ValidateDeletePaths(Context *context, GLuint path, GLsizei range) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + // range = 0 is undefined in NV_path_rendering. + // we add stricter semantic check here and require a non zero positive range. + if (range <= 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidRange); + return false; + } + + angle::CheckedNumeric checkedRange(path); + checkedRange += range; + + if (!angle::IsValueInRangeForNumericType(range) || !checkedRange.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + return true; +} + +bool ValidatePathCommands(Context *context, + GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + if (numCommands < 0) + { + context->handleError(InvalidValue() << "Invalid number of commands."); + return false; + } + else if (numCommands > 0) + { + if (!commands) + { + context->handleError(InvalidValue() << "No commands array given."); + return false; + } + } + + if (numCoords < 0) + { + context->handleError(InvalidValue() << "Invalid number of coordinates."); + return false; + } + else if (numCoords > 0) + { + if (!coords) + { + context->handleError(InvalidValue() << "No coordinate array given."); + return false; + } + } + + std::uint32_t coordTypeSize = 0; + switch (coordType) + { + case GL_BYTE: + coordTypeSize = sizeof(GLbyte); + break; + + case GL_UNSIGNED_BYTE: + coordTypeSize = sizeof(GLubyte); + break; + + case GL_SHORT: + coordTypeSize = sizeof(GLshort); + break; + + case GL_UNSIGNED_SHORT: + coordTypeSize = sizeof(GLushort); + break; + + case GL_FLOAT: + coordTypeSize = sizeof(GLfloat); + break; + + default: + context->handleError(InvalidEnum() << "Invalid coordinate type."); + return false; + } + + angle::CheckedNumeric checkedSize(numCommands); + checkedSize += (coordTypeSize * numCoords); + if (!checkedSize.IsValid()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), IntegerOverflow); + return false; + } + + // early return skips command data validation when it doesn't exist. + if (!commands) + return true; + + GLsizei expectedNumCoords = 0; + for (GLsizei i = 0; i < numCommands; ++i) + { + switch (commands[i]) + { + case GL_CLOSE_PATH_CHROMIUM: // no coordinates. + break; + case GL_MOVE_TO_CHROMIUM: + case GL_LINE_TO_CHROMIUM: + expectedNumCoords += 2; + break; + case GL_QUADRATIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 4; + break; + case GL_CUBIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 6; + break; + case GL_CONIC_CURVE_TO_CHROMIUM: + expectedNumCoords += 5; + break; + default: + context->handleError(InvalidEnum() << "Invalid command."); + return false; + } + } + if (expectedNumCoords != numCoords) + { + context->handleError(InvalidValue() << "Invalid number of coordinates."); + return false; + } + + return true; +} + +bool ValidateSetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat value) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (pname) + { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + if (value < 0.0f) + { + context->handleError(InvalidValue() << "Invalid stroke width."); + return false; + } + break; + case GL_PATH_END_CAPS_CHROMIUM: + switch (static_cast(value)) + { + case GL_FLAT_CHROMIUM: + case GL_SQUARE_CHROMIUM: + case GL_ROUND_CHROMIUM: + break; + default: + context->handleError(InvalidEnum() << "Invalid end caps."); + return false; + } + break; + case GL_PATH_JOIN_STYLE_CHROMIUM: + switch (static_cast(value)) + { + case GL_MITER_REVERT_CHROMIUM: + case GL_BEVEL_CHROMIUM: + case GL_ROUND_CHROMIUM: + break; + default: + context->handleError(InvalidEnum() << "Invalid join style."); + return false; + } + case GL_PATH_MITER_LIMIT_CHROMIUM: + if (value < 0.0f) + { + context->handleError(InvalidValue() << "Invalid miter limit."); + return false; + } + break; + + case GL_PATH_STROKE_BOUND_CHROMIUM: + // no errors, only clamping. + break; + + default: + context->handleError(InvalidEnum() << "Invalid path parameter."); + return false; + } + return true; +} + +bool ValidateGetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat *value) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + if (!context->hasPath(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + if (!value) + { + context->handleError(InvalidValue() << "No value array."); + return false; + } + + switch (pname) + { + case GL_PATH_STROKE_WIDTH_CHROMIUM: + case GL_PATH_END_CAPS_CHROMIUM: + case GL_PATH_JOIN_STYLE_CHROMIUM: + case GL_PATH_MITER_LIMIT_CHROMIUM: + case GL_PATH_STROKE_BOUND_CHROMIUM: + break; + + default: + context->handleError(InvalidEnum() << "Invalid path parameter."); + return false; + } + + return true; +} + +bool ValidatePathStencilFunc(Context *context, GLenum func, GLint ref, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); + return false; + } + + return true; +} + +// Note that the spec specifies that for the path drawing commands +// if the path object is not an existing path object the command +// does nothing and no error is generated. +// However if the path object exists but has not been specified any +// commands then an error is generated. + +bool ValidateStencilFillPath(Context *context, GLuint path, GLenum fillMode, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + + return true; +} + +bool ValidateStencilStrokePath(Context *context, GLuint path, GLint reference, GLuint mask) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + context->handleError(InvalidOperation() << "No such path or path has no data."); + return false; + } + + return true; +} + +bool ValidateCoverPath(Context *context, GLuint path, GLenum coverMode) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + if (context->hasPath(path) && !context->hasPathData(path)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoSuchPath); + return false; + } + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + return true; +} + +bool ValidateStencilThenCoverFillPath(Context *context, + GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + return ValidateStencilFillPath(context, path, fillMode, mask) && + ValidateCoverPath(context, path, coverMode); +} + +bool ValidateStencilThenCoverStrokePath(Context *context, + GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + return ValidateStencilStrokePath(context, path, reference, mask) && + ValidateCoverPath(context, path, coverMode); +} + +bool ValidateIsPath(Context *context) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + return true; +} + +bool ValidateCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateStencilFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + return true; +} + +bool ValidateStencilStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + // no more validation here. + + return true; +} + +bool ValidateStencilThenCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + switch (fillMode) + { + case GL_COUNT_UP_CHROMIUM: + case GL_COUNT_DOWN_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFillMode); + return false; + } + if (!isPow2(mask + 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidStencilBitMask); + return false; + } + + return true; +} + +bool ValidateStencilThenCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase, + transformType, transformValues)) + return false; + + switch (coverMode) + { + case GL_CONVEX_HULL_CHROMIUM: + case GL_BOUNDING_BOX_CHROMIUM: + case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCoverMode); + return false; + } + + return true; +} + +bool ValidateBindFragmentInputLocation(Context *context, + GLuint program, + GLint location, + const GLchar *name) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + const GLint MaxLocation = context->getCaps().maxVaryingVectors * 4; + if (location >= MaxLocation) + { + context->handleError(InvalidValue() << "Location exceeds max varying."); + return false; + } + + const auto *programObject = context->getProgram(program); + if (!programObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + if (!name) + { + context->handleError(InvalidValue() << "No name given."); + return false; + } + + if (angle::BeginsWith(name, "gl_")) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NameBeginsWithGL); + return false; + } + + return true; +} + +bool ValidateProgramPathFragmentInputGen(Context *context, + GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + if (!context->getExtensions().pathRendering) + { + context->handleError(InvalidOperation() << "GL_CHROMIUM_path_rendering is not available."); + return false; + } + + const auto *programObject = context->getProgram(program); + if (!programObject || programObject->isFlaggedForDeletion()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramDoesNotExist); + return false; + } + + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + switch (genMode) + { + case GL_NONE: + if (components != 0) + { + context->handleError(InvalidValue() << "Invalid components."); return false; } break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->getExtensions().textureCompressionDXT3) + + case GL_OBJECT_LINEAR_CHROMIUM: + case GL_EYE_LINEAR_CHROMIUM: + case GL_CONSTANT_CHROMIUM: + if (components < 1 || components > 4) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidValue() << "Invalid components."); return false; } - else + if (!coeffs) + { + context->handleError(InvalidValue() << "No coefficients array given."); + return false; + } + break; + + default: + context->handleError(InvalidEnum() << "Invalid gen mode."); + return false; + } + + // If the location is -1 then the command is silently ignored + // and no further validation is needed. + if (location == -1) + return true; + + const auto &binding = programObject->getFragmentInputBindingInfo(context, location); + + if (!binding.valid) + { + context->handleError(InvalidOperation() << "No such binding."); + return false; + } + + if (binding.type != GL_NONE) + { + GLint expectedComponents = 0; + switch (binding.type) + { + case GL_FLOAT: + expectedComponents = 1; + break; + case GL_FLOAT_VEC2: + expectedComponents = 2; + break; + case GL_FLOAT_VEC3: + expectedComponents = 3; + break; + case GL_FLOAT_VEC4: + expectedComponents = 4; + break; + default: + context->handleError( + InvalidOperation() + << "Fragment input type is not a floating point scalar or vector."); + return false; + } + if (expectedComponents != components && genMode != GL_NONE) + { + context->handleError(InvalidOperation() << "Unexpected number of components"); + return false; + } + } + return true; +} + +bool ValidateCopyTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + if (!context->getExtensions().copyTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_texture extension not available."); + return false; + } + + const Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureSourceTarget(context, source->getTarget())) + { + context->handleError(InvalidValue() << "Source texture a valid texture type."); + return false; + } + + GLenum sourceTarget = source->getTarget(); + ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP); + + if (!IsValidCopyTextureSourceLevel(context, source->getTarget(), sourceLevel)) + { + context->handleError(InvalidValue() << "Source texture level is not valid."); + return false; + } + + GLsizei sourceWidth = static_cast(source->getWidth(sourceTarget, sourceLevel)); + GLsizei sourceHeight = static_cast(source->getHeight(sourceTarget, sourceLevel)); + if (sourceWidth == 0 || sourceHeight == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + + const InternalFormat &sourceFormat = *source->getFormat(sourceTarget, sourceLevel).info; + if (!IsValidCopyTextureSourceInternalFormatEnum(sourceFormat.internalFormat)) + { + context->handleError(InvalidOperation() << "Source texture internal format is invalid."); + return false; + } + + if (!IsValidCopyTextureDestinationTargetEnum(context, destTarget)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + const Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget(), destTarget)) + { + context->handleError(InvalidValue() << "Destination texture a valid texture type."); + return false; + } + + if (!IsValidCopyTextureDestinationLevel(context, destTarget, destLevel, sourceWidth, + sourceHeight)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (!IsValidCopyTextureDestinationFormatType(context, internalFormat, destType)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), MismatchedTypeAndFormat); + return false; + } + + if (IsCubeMapTextureTarget(destTarget) && sourceWidth != sourceHeight) + { + context->handleError( + InvalidValue() << "Destination width and height must be equal for cube map textures."); + return false; + } + + if (dest->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "Destination texture is immutable."); + return false; + } + + return true; +} + +bool ValidateCopySubTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + if (!context->getExtensions().copyTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_texture extension not available."); + return false; + } + + const Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureSourceTarget(context, source->getTarget())) + { + context->handleError(InvalidValue() << "Source texture a valid texture type."); + return false; + } + + GLenum sourceTarget = source->getTarget(); + ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP); + + if (!IsValidCopyTextureSourceLevel(context, source->getTarget(), sourceLevel)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + if (source->getWidth(sourceTarget, sourceLevel) == 0 || + source->getHeight(sourceTarget, sourceLevel) == 0) + { + context->handleError(InvalidValue() + << "The source level of the source texture must be defined."); + return false; + } + + if (x < 0 || y < 0) + { + context->handleError(InvalidValue() << "x and y cannot be negative."); + return false; + } + + if (width < 0 || height < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (static_cast(x + width) > source->getWidth(sourceTarget, sourceLevel) || + static_cast(y + height) > source->getHeight(sourceTarget, sourceLevel)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), SourceTextureTooSmall); + return false; + } + + const Format &sourceFormat = source->getFormat(sourceTarget, sourceLevel); + if (!IsValidCopySubTextureSourceInternalFormat(sourceFormat.info->internalFormat)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + + if (!IsValidCopyTextureDestinationTargetEnum(context, destTarget)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + const Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget(), destTarget)) + { + context->handleError(InvalidValue() << "Destination texture a valid texture type."); + return false; + } + + if (!IsValidCopyTextureDestinationLevel(context, destTarget, destLevel, width, height)) + { + context->handleError(InvalidValue() << "Destination texture level is not valid."); + return false; + } + + if (dest->getWidth(destTarget, destLevel) == 0 || dest->getHeight(destTarget, destLevel) == 0) + { + context + ->handleError(InvalidOperation() + << "The destination level of the destination texture must be defined."); + return false; + } + + const InternalFormat &destFormat = *dest->getFormat(destTarget, destLevel).info; + if (!IsValidCopySubTextureDestionationInternalFormat(destFormat.internalFormat)) + { + context->handleError(InvalidOperation() + << "Destination internal format and type combination is not valid."); + return false; + } + + if (xoffset < 0 || yoffset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (static_cast(xoffset + width) > dest->getWidth(destTarget, destLevel) || + static_cast(yoffset + height) > dest->getHeight(destTarget, destLevel)) + { + context->handleError(InvalidValue() << "Destination texture not large enough to copy to."); + return false; + } + + return true; +} + +bool ValidateCompressedCopyTextureCHROMIUM(Context *context, GLuint sourceId, GLuint destId) +{ + if (!context->getExtensions().copyCompressedTexture) + { + context->handleError(InvalidOperation() + << "GL_CHROMIUM_copy_compressed_texture extension not available."); + return false; + } + + const gl::Texture *source = context->getTexture(sourceId); + if (source == nullptr) + { + context->handleError(InvalidValue() << "Source texture is not a valid texture object."); + return false; + } + + if (source->getTarget() != GL_TEXTURE_2D) + { + context->handleError(InvalidValue() << "Source texture must be of type GL_TEXTURE_2D."); + return false; + } + + if (source->getWidth(GL_TEXTURE_2D, 0) == 0 || source->getHeight(GL_TEXTURE_2D, 0) == 0) + { + context->handleError(InvalidValue() << "Source texture must level 0 defined."); + return false; + } + + const gl::Format &sourceFormat = source->getFormat(GL_TEXTURE_2D, 0); + if (!sourceFormat.info->compressed) + { + context->handleError(InvalidOperation() + << "Source texture must have a compressed internal format."); + return false; + } + + const gl::Texture *dest = context->getTexture(destId); + if (dest == nullptr) + { + context->handleError(InvalidValue() + << "Destination texture is not a valid texture object."); + return false; + } + + if (dest->getTarget() != GL_TEXTURE_2D) + { + context->handleError(InvalidValue() + << "Destination texture must be of type GL_TEXTURE_2D."); + return false; + } + + if (dest->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "Destination cannot be immutable."); + return false; + } + + return true; +} + +bool ValidateCreateShader(Context *context, GLenum type) +{ + switch (type) + { + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + + case GL_COMPUTE_SHADER: + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), ES31Required); + return false; + } + break; + + case GL_GEOMETRY_SHADER_EXT: + if (!context->getExtensions().geometryShader) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + + return true; +} + +bool ValidateBufferData(ValidationContext *context, + BufferBinding target, + GLsizeiptr size, + const void *data, + BufferUsage usage) +{ + if (size < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + switch (usage) + { + case BufferUsage::StreamDraw: + case BufferUsage::StaticDraw: + case BufferUsage::DynamicDraw: + break; + + case BufferUsage::StreamRead: + case BufferUsage::StaticRead: + case BufferUsage::DynamicRead: + case BufferUsage::StreamCopy: + case BufferUsage::StaticCopy: + case BufferUsage::DynamicCopy: + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferUsage); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferUsage); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + return true; +} + +bool ValidateBufferSubData(ValidationContext *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data) +{ + if (size < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + if (offset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(target); + + if (!buffer) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), BufferNotBound); + return false; + } + + if (buffer->isMapped()) + { + context->handleError(InvalidOperation()); + return false; + } + + // Check for possible overflow of size + offset + angle::CheckedNumeric checkedSize(size); + checkedSize += offset; + if (!checkedSize.IsValid()) + { + context->handleError(OutOfMemory()); + return false; + } + + if (size + offset > buffer->getSize()) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InsufficientBufferSize); + return false; + } + + return true; +} + +bool ValidateRequestExtensionANGLE(Context *context, const GLchar *name) +{ + if (!context->getExtensions().requestExtension) + { + context->handleError(InvalidOperation() << "GL_ANGLE_request_extension is not available."); + return false; + } + + if (!context->isExtensionRequestable(name)) + { + context->handleError(InvalidOperation() << "Extension " << name << " is not requestable."); + return false; + } + + return true; +} + +bool ValidateActiveTexture(ValidationContext *context, GLenum texture) +{ + if (texture < GL_TEXTURE0 || + texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1) + { + context->handleError(InvalidEnum()); + return false; + } + + return true; +} + +bool ValidateAttachShader(ValidationContext *context, GLuint program, GLuint shader) +{ + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + switch (shaderObject->getType()) + { + case GL_VERTEX_SHADER: + { + if (programObject->getAttachedVertexShader()) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else + } + case GL_FRAGMENT_SHADER: + { + if (programObject->getAttachedFragmentShader()) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); 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) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (target != GL_TEXTURE_2D) + } + case GL_COMPUTE_SHADER: + { + if (programObject->getAttachedComputeShader()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } - // OES_depth_texture supports loading depth data and multiple levels, - // but ANGLE_depth_texture does not - if (pixels != NULL || level != 0) + break; + } + case GL_GEOMETRY_SHADER_EXT: + { + if (programObject->getAttachedGeometryShader()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderAttachmentHasShader); return false; } break; - default: - break; } + default: + UNREACHABLE(); + break; + } - if (type == GL_FLOAT) + return true; +} + +bool ValidateBindAttribLocation(ValidationContext *context, + GLuint program, + GLuint index, + const GLchar *name) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + if (strncmp(name, "gl_", 3) == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NameBeginsWithGL); + return false; + } + + if (context->isWebGL()) + { + const size_t length = strlen(name); + + if (!IsValidESSLString(name, length)) { - if (!context->getExtensions().textureFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters + // for shader-related entry points + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; } - else if (type == GL_HALF_FLOAT_OES) + + if (!ValidateWebGLNameLength(context, length) || !ValidateWebGLNamePrefix(context, name)) { - if (!context->getExtensions().textureHalfFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } + return false; } } + return GetValidProgram(context, program) != nullptr; +} + +bool ValidateBindBuffer(ValidationContext *context, BufferBinding target, GLuint buffer) +{ + if (!ValidBufferType(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isBufferGenerated(buffer)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } + return true; } -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 ValidateBindFramebuffer(ValidationContext *context, GLenum target, GLuint framebuffer) { - GLenum textureInternalFormat = GL_NONE; + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } - if (!ValidTexture2DDestinationTarget(context, target)) + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isFramebufferGenerated(framebuffer)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); return false; } - if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) + return true; +} + +bool ValidateBindRenderbuffer(ValidationContext *context, GLenum target, GLuint renderbuffer) +{ + if (target != GL_RENDERBUFFER) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); - const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat); - GLenum textureFormat = internalFormatInfo.format; + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isRenderbufferGenerated(renderbuffer)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } - // [OpenGL ES 2.0.24] table 3.9 - if (isSubImage) + return true; +} + +static bool ValidBlendEquationMode(const ValidationContext *context, GLenum mode) +{ + switch (mode) { - switch (textureFormat) - { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED_EXT: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_R32F && - colorbufferFormat != GL_RG32F && - colorbufferFormat != GL_RGB32F && - colorbufferFormat != GL_RGBA32F) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RG_EXT: - if (colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_RG32F && - colorbufferFormat != GL_RGB32F && - colorbufferFormat != GL_RGBA32F) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_RGB32F && - colorbufferFormat != GL_RGBA32F) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_RGBA32F) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - 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_OES: - case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (internalFormatInfo.type == GL_FLOAT && - !context->getExtensions().textureFloat) - { - context->recordError(Error(GL_INVALID_OPERATION)); + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + return true; + + case GL_MIN: + case GL_MAX: + return context->getClientVersion() >= ES_3_0 || context->getExtensions().blendMinMax; + + default: return false; - } } - else +} + +bool ValidateBlendColor(ValidationContext *context, + GLfloat red, + GLfloat green, + GLfloat blue, + GLfloat alpha) +{ + return true; +} + +bool ValidateBlendEquation(ValidationContext *context, GLenum mode) +{ + if (!ValidBlendEquationMode(context, mode)) { - switch (internalformat) + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + return true; +} + +bool ValidateBlendEquationSeparate(ValidationContext *context, GLenum modeRGB, GLenum modeAlpha) +{ + if (!ValidBlendEquationMode(context, modeRGB)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + if (!ValidBlendEquationMode(context, modeAlpha)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendEquation); + return false; + } + + return true; +} + +bool ValidateBlendFunc(ValidationContext *context, GLenum sfactor, GLenum dfactor) +{ + return ValidateBlendFuncSeparate(context, sfactor, dfactor, sfactor, dfactor); +} + +static bool ValidSrcBlendFunc(GLenum srcBlend) +{ + switch (srcBlend) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + return true; + + default: + return false; + } +} + +static bool ValidDstBlendFunc(GLenum dstBlend, GLint contextMajorVersion) +{ + switch (dstBlend) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return true; + + case GL_SRC_ALPHA_SATURATE: + return (contextMajorVersion >= 3); + + default: + return false; + } +} + +bool ValidateBlendFuncSeparate(ValidationContext *context, + GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha) +{ + if (!ValidSrcBlendFunc(srcRGB)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidDstBlendFunc(dstRGB, context->getClientMajorVersion())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidSrcBlendFunc(srcAlpha)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (!ValidDstBlendFunc(dstAlpha, context->getClientMajorVersion())) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBlendFunction); + return false; + } + + if (context->getLimitations().noSimultaneousConstantColorAndAlphaBlendFunc || + context->getExtensions().webglCompatibility) + { + 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); + + if (constantColorUsed && constantAlphaUsed) { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED_EXT: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RG_EXT: - if (colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES && - colorbufferFormat != GL_BGR5_A1_ANGLEX) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->getExtensions().textureCompressionDXT3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->getExtensions().textureCompressionDXT5) + const char *msg; + if (context->getExtensions().webglCompatibility) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + msg = kErrorInvalidConstantColor; } else { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + msg = + "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."; + ERR() << msg; } + context->handleError(InvalidOperation() << msg); + return false; + } + } + + return true; +} + +bool ValidateGetString(Context *context, GLenum name) +{ + switch (name) + { + case GL_VENDOR: + case GL_RENDERER: + case GL_VERSION: + case GL_SHADING_LANGUAGE_VERSION: + case GL_EXTENSIONS: break; - case GL_ETC1_RGB8_OES: - if (context->getExtensions().compressedETC1RGB8Texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + if (!context->getExtensions().requestExtension) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); 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: - case GL_DEPTH_STENCIL_OES: - case GL_DEPTH24_STENCIL8_OES: - if (context->getExtensions().depthTextures) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - default: - context->recordError(Error(GL_INVALID_ENUM)); + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); return false; - } } - // If width or height is zero, it is a no-op. Return false without setting an error. - return (width > 0 && height > 0); + return true; } -bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height) +bool ValidateLineWidth(ValidationContext *context, GLfloat width) { - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + if (width <= 0.0f || isNaN(width)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidWidth); return false; } - if (width < 1 || height < 1 || levels < 1) + return true; +} + +bool ValidateVertexAttribPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr) +{ + if (!ValidateVertexFormatBase(context, index, size, type, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - if (target == GL_TEXTURE_CUBE_MAP && width != height) + if (stride < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStride); return false; } - if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + const Caps &caps = context->getCaps(); + if (context->getClientVersion() >= ES_3_1) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + if (stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + if (index >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + bool nullBufferAllowed = context->getGLState().areClientArraysEnabled() && + context->getGLState().getVertexArray()->id() == 0; + if (!nullBufferAllowed && context->getGLState().getTargetBuffer(BufferBinding::Array) == 0 && + ptr != nullptr) { - context->recordError(Error(GL_INVALID_ENUM)); + context + ->handleError(InvalidOperation() + << "Client data cannot be used with a non-default vertex array object."); return false; } - const gl::Caps &caps = context->getCaps(); - - switch (target) + if (context->getExtensions().webglCompatibility) { - case GL_TEXTURE_2D: - if (static_cast(width) > caps.max2DTextureSize || - static_cast(height) > caps.max2DTextureSize) + // WebGL 1.0 [Section 6.14] Fixed point support + // The WebGL API does not support the GL_FIXED data type. + if (type == GL_FIXED) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidEnum() << "GL_FIXED is not supported in WebGL."); return false; } - break; - case GL_TEXTURE_CUBE_MAP: - if (static_cast(width) > caps.maxCubeMapTextureSize || - static_cast(height) > caps.maxCubeMapTextureSize) + + if (!ValidateWebGLVertexAttribPointer(context, type, normalized, stride, ptr, false)) { - context->recordError(Error(GL_INVALID_VALUE)); return false; } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); + } + + return true; +} + +bool ValidateDepthRangef(ValidationContext *context, GLfloat zNear, GLfloat zFar) +{ + if (context->getExtensions().webglCompatibility && zNear > zFar) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidDepthRange); return false; } - if (levels != 1 && !context->getExtensions().textureNPOT) + return true; +} + +bool ValidateRenderbufferStorage(ValidationContext *context, + GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + return ValidateRenderbufferStorageParametersBase(context, target, 0, internalformat, width, + height); +} + +bool ValidateRenderbufferStorageMultisampleANGLE(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (!context->getExtensions().framebufferMultisample) { - if (!gl::isPow2(width) || !gl::isPow2(height)) + context->handleError(InvalidOperation() + << "GL_ANGLE_framebuffer_multisample not available"); + return false; + } + + // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal + // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_OPERATION is + // generated. + if (static_cast(samples) > context->getCaps().maxSamples) + { + context->handleError(InvalidValue()); + return false; + } + + // 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. + // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3. + if (context->getClientMajorVersion() >= 3) + { + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(OutOfMemory()); return false; } } - switch (internalformat) + return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, + width, height); +} + +bool ValidateCheckFramebufferStatus(ValidationContext *context, GLenum target) +{ + if (!ValidFramebufferTarget(context, target)) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + return true; +} + +bool ValidateClearColor(ValidationContext *context, + GLfloat red, + GLfloat green, + GLfloat blue, + GLfloat alpha) +{ + return true; +} + +bool ValidateClearDepthf(ValidationContext *context, GLfloat depth) +{ + return true; +} + +bool ValidateClearStencil(ValidationContext *context, GLint s) +{ + return true; +} + +bool ValidateColorMask(ValidationContext *context, + GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha) +{ + return true; +} + +bool ValidateCompileShader(ValidationContext *context, GLuint shader) +{ + return true; +} + +bool ValidateCreateProgram(ValidationContext *context) +{ + return true; +} + +bool ValidateCullFace(ValidationContext *context, CullFaceMode mode) +{ + switch (mode) + { + case CullFaceMode::Front: + case CullFaceMode::Back: + case CullFaceMode::FrontAndBack: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidCullMode); return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->getExtensions().textureCompressionDXT3) + } + + return true; +} + +bool ValidateDeleteProgram(ValidationContext *context, GLuint program) +{ + if (program == 0) + { + return false; + } + + if (!context->getProgram(program)) + { + if (context->getShader(program)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); return false; } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->getExtensions().textureCompressionDXT5) + else { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); return false; } - break; - case GL_ETC1_RGB8_OES: - if (!context->getExtensions().compressedETC1RGB8Texture) + } + + return true; +} + +bool ValidateDeleteShader(ValidationContext *context, GLuint shader) +{ + if (shader == 0) + { + return false; + } + + if (!context->getShader(shader)) + { + if (context->getProgram(shader)) { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidShaderName); 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: - case GL_LUMINANCE32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - if (!context->getExtensions().textureFloat) + else { - context->recordError(Error(GL_INVALID_ENUM)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), ExpectedShaderName); return false; } - break; - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - if (!context->getExtensions().textureHalfFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); + } + + return true; +} + +bool ValidateDepthFunc(ValidationContext *context, GLenum func) +{ + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; - } - break; - case GL_R8_EXT: - case GL_RG8_EXT: - case GL_R16F_EXT: - case GL_RG16F_EXT: - case GL_R32F_EXT: - case GL_RG32F_EXT: - if (!context->getExtensions().textureRG) + } + + return true; +} + +bool ValidateDepthMask(ValidationContext *context, GLboolean flag) +{ + return true; +} + +bool ValidateDetachShader(ValidationContext *context, GLuint program, GLuint shader) +{ + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + const Shader *attachedShader = nullptr; + + switch (shaderObject->getType()) + { + case GL_VERTEX_SHADER: { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + attachedShader = programObject->getAttachedVertexShader(); + break; } - break; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - if (!context->getExtensions().depthTextures) + case GL_FRAGMENT_SHADER: { - context->recordError(Error(GL_INVALID_ENUM)); - return false; + attachedShader = programObject->getAttachedFragmentShader(); + break; } - if (target != GL_TEXTURE_2D) + case GL_COMPUTE_SHADER: { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + attachedShader = programObject->getAttachedComputeShader(); + break; } - // ANGLE_depth_texture only supports 1-level textures - if (levels != 1) + case GL_GEOMETRY_SHADER_EXT: { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + attachedShader = programObject->getAttachedGeometryShader(); + break; } - break; - default: - break; + default: + UNREACHABLE(); + return false; + } + + if (attachedShader != shaderObject) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ShaderToDetachMustBeAttached); + return false; + } + + return true; +} + +bool ValidateDisableVertexAttribArray(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + return true; +} + +bool ValidateEnableVertexAttribArray(ValidationContext *context, GLuint index) +{ + if (index >= MAX_VERTEX_ATTRIBS) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + return true; +} + +bool ValidateFinish(ValidationContext *context) +{ + return true; +} + +bool ValidateFlush(ValidationContext *context) +{ + return true; +} + +bool ValidateFrontFace(ValidationContext *context, GLenum mode) +{ + switch (mode) + { + case GL_CW: + case GL_CCW: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + return true; +} + +bool ValidateGetActiveAttrib(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getActiveAttributeCount())) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxActiveUniform); + return false; + } + + return true; +} + +bool ValidateGetActiveUniform(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getActiveUniformCount())) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxActiveUniform); + return false; + } + + return true; +} + +bool ValidateGetAttachedShaders(ValidationContext *context, + GLuint program, + GLsizei maxcount, + GLsizei *count, + GLuint *shaders) +{ + if (maxcount < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeMaxCount); + return false; + } + + Program *programObject = GetValidProgram(context, program); + + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetAttribLocation(ValidationContext *context, GLuint program, const GLchar *name) +{ + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; } - gl::Texture *texture = context->getTargetTexture(target); - if (!texture || texture->id() == 0) + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); return false; } - if (texture->getImmutableFormat()) + if (!programObject->isLinked()) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); return false; } return true; } -// check for combinations of format and type that are valid for ReadPixels -bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type) +bool ValidateGetBooleanv(ValidationContext *context, GLenum pname, GLboolean *params) { - switch (format) - { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return false; - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - break; - default: - return false; - } - break; - case GL_RG_EXT: - case GL_RED_EXT: - if (!context->getExtensions().textureRG) - { - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return false; - } - break; + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} - default: - return false; - } +bool ValidateGetError(ValidationContext *context) +{ return true; } -bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments) +bool ValidateGetFloatv(ValidationContext *context, GLenum pname, GLfloat *params) { - if (!context->getExtensions().discardFramebuffer) + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} + +bool ValidateGetIntegerv(ValidationContext *context, GLenum pname, GLint *params) +{ + GLenum nativeType; + unsigned int numParams = 0; + return ValidateStateQuery(context, pname, &nativeType, &numParams); +} + +bool ValidateGetProgramInfoLog(ValidationContext *context, + GLuint program, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) +{ + if (bufsize < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - bool defaultFramebuffer = false; - - switch (target) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - 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); + return true; } -bool ValidateBindVertexArrayOES(Context *context, GLuint array) +bool ValidateGetShaderInfoLog(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) { - if (!context->getExtensions().vertexArrayObject) + if (bufsize < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); return false; } - return ValidateBindVertexArrayBase(context, array); -} - -bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n) -{ - if (!context->getExtensions().vertexArrayObject) + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateDeleteVertexArraysBase(context, n); + return true; } -bool ValidateGenVertexArraysOES(Context *context, GLsizei n) +bool ValidateGetShaderPrecisionFormat(ValidationContext *context, + GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) { - if (!context->getExtensions().vertexArrayObject) + switch (shadertype) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + case GL_COMPUTE_SHADER: + context->handleError(InvalidOperation() + << "compute shader precision not yet implemented."); + return false; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidShaderType); + return false; + } + + switch (precisiontype) + { + case GL_LOW_FLOAT: + case GL_MEDIUM_FLOAT: + case GL_HIGH_FLOAT: + case GL_LOW_INT: + case GL_MEDIUM_INT: + case GL_HIGH_INT: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPrecision); + return false; } - return ValidateGenVertexArraysBase(context, n); + return true; } -bool ValidateIsVertexArrayOES(Context *context) +bool ValidateGetShaderSource(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source) { - if (!context->getExtensions().vertexArrayObject) + if (bufsize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) { - 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) +bool ValidateGetUniformLocation(ValidationContext *context, GLuint program, const GLchar *name) { - if (!context->getExtensions().getProgramBinary) + if (strstr(name, "gl_") == name) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length); -} + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility && !IsValidESSLString(name, strlen(name))) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidNameCharacters); + return false; + } -bool ValidateGetProgramBinaryOES(Context *context, - GLuint program, - GLsizei bufSize, - GLsizei *length, - GLenum *binaryFormat, - void *binary) -{ - if (!context->getExtensions().getProgramBinary) + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); return false; } - return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + return true; } -static bool ValidDebugSource(GLenum source, bool mustBeThirdPartyOrApplication) +bool ValidateHint(ValidationContext *context, GLenum target, GLenum mode) { - switch (source) + switch (mode) { - 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_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; - case GL_DEBUG_SOURCE_THIRD_PARTY: - case GL_DEBUG_SOURCE_APPLICATION: - return true; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + return false; + } + + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + break; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: + if (context->getClientVersion() < ES_3_0 && + !context->getExtensions().standardDerivatives) + { + context->handleError(InvalidEnum() << "hint requires OES_standard_derivatives."); + return false; + } + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } + + return true; } -static bool ValidDebugType(GLenum type) +bool ValidateIsBuffer(ValidationContext *context, GLuint buffer) { - switch (type) + return true; +} + +bool ValidateIsFramebuffer(ValidationContext *context, GLuint framebuffer) +{ + return true; +} + +bool ValidateIsProgram(ValidationContext *context, GLuint program) +{ + return true; +} + +bool ValidateIsRenderbuffer(ValidationContext *context, GLuint renderbuffer) +{ + return true; +} + +bool ValidateIsShader(ValidationContext *context, GLuint shader) +{ + return true; +} + +bool ValidateIsTexture(ValidationContext *context, GLuint texture) +{ + return true; +} + +bool ValidatePixelStorei(ValidationContext *context, GLenum pname, GLint param) +{ + if (context->getClientMajorVersion() < 3) { - 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; + switch (pname) + { + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + context->handleError(InvalidEnum()); + return false; + + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + if (!context->getExtensions().unpackSubimage) + { + context->handleError(InvalidEnum()); + return false; + } + break; + + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + if (!context->getExtensions().packSubimage) + { + context->handleError(InvalidEnum()); + return false; + } + break; + } + } + + if (param < 0) + { + context->handleError(InvalidValue() << "Cannot use negative values in PixelStorei"); + return false; + } + + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidUnpackAlignment); + return false; + } + break; + + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidUnpackAlignment); + return false; + } + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + if (!context->getExtensions().packReverseRowOrder) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); + } + break; + + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } + + return true; } -static bool ValidDebugSeverity(GLenum severity) +bool ValidatePolygonOffset(ValidationContext *context, GLfloat factor, GLfloat units) { - switch (severity) + return true; +} + +bool ValidateReleaseShaderCompiler(ValidationContext *context) +{ + return true; +} + +bool ValidateSampleCoverage(ValidationContext *context, GLfloat value, GLboolean invert) +{ + return true; +} + +bool ValidateScissor(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (width < 0 || height < 0) { - case GL_DEBUG_SEVERITY_HIGH: - case GL_DEBUG_SEVERITY_MEDIUM: - case GL_DEBUG_SEVERITY_LOW: - case GL_DEBUG_SEVERITY_NOTIFICATION: - return true; + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } - default: - return false; + return true; +} + +bool ValidateShaderBinary(ValidationContext *context, + GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) +{ + const std::vector &shaderBinaryFormats = context->getCaps().shaderBinaryFormats; + if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == + shaderBinaryFormats.end()) + { + context->handleError(InvalidEnum() << "Invalid shader binary format."); + return false; } + + return true; } -bool ValidateDebugMessageControlKHR(Context *context, - GLenum source, - GLenum type, - GLenum severity, - GLsizei count, - const GLuint *ids, - GLboolean enabled) +bool ValidateShaderSource(ValidationContext *context, + GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) { - if (!context->getExtensions().debug) + if (count < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); return false; } - if (!ValidDebugSource(source, false) && source != GL_DONT_CARE) + // The WebGL spec (section 6.20) disallows strings containing invalid ESSL characters for + // shader-related entry points + if (context->getExtensions().webglCompatibility) + { + for (GLsizei i = 0; i < count; i++) + { + size_t len = + (length && length[i] >= 0) ? static_cast(length[i]) : strlen(string[i]); + + // Backslash as line-continuation is allowed in WebGL 2.0. + if (!IsValidESSLShaderSourceString(string[i], len, + context->getClientVersion() >= ES_3_0)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), ShaderSourceInvalidCharacters); + return false; + } + } + } + + Shader *shaderObject = GetValidShader(context, shader); + if (!shaderObject) + { + return false; + } + + return true; +} + +bool ValidateStencilFunc(ValidationContext *context, GLenum func, GLint ref, GLuint mask) +{ + if (!IsValidStencilFunc(func)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugType(type) && type != GL_DONT_CARE) + return true; +} + +bool ValidateStencilFuncSeparate(ValidationContext *context, + GLenum face, + GLenum func, + GLint ref, + GLuint mask) +{ + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE) + if (!IsValidStencilFunc(func)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); 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 ValidateStencilMask(ValidationContext *context, GLuint mask) +{ return true; } -bool ValidateDebugMessageInsertKHR(Context *context, - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *buf) +bool ValidateStencilMaskSeparate(ValidationContext *context, GLenum face, GLuint mask) { - if (!context->getExtensions().debug) + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!context->getState().getDebug().isOutputEnabled()) + return true; +} + +bool ValidateStencilOp(ValidationContext *context, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (!IsValidStencilOp(fail)) { - // If the DEBUG_OUTPUT state is disabled calls to DebugMessageInsert are discarded and do - // not generate an error. + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSeverity(severity)) + if (!IsValidStencilOp(zfail)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugType(type)) + if (!IsValidStencilOp(zpass)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - if (!ValidDebugSource(source, true)) + return true; +} + +bool ValidateStencilOpSeparate(ValidationContext *context, + GLenum face, + GLenum fail, + GLenum zfail, + GLenum zpass) +{ + if (!IsValidStencilFace(face)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidStencil); return false; } - size_t messageLength = (length < 0) ? strlen(buf) : length; - if (messageLength > context->getExtensions().maxDebugMessageLength) + return ValidateStencilOp(context, fail, zfail, zpass); +} + +bool ValidateUniform1f(ValidationContext *context, GLint location, GLfloat x) +{ + return ValidateUniform(context, GL_FLOAT, location, 1); +} + +bool ValidateUniform1fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT, location, count); +} + +bool ValidateUniform1i(ValidationContext *context, GLint location, GLint x) +{ + return ValidateUniform1iv(context, location, 1, &x); +} + +bool ValidateUniform2f(ValidationContext *context, GLint location, GLfloat x, GLfloat y) +{ + return ValidateUniform(context, GL_FLOAT_VEC2, location, 1); +} + +bool ValidateUniform2fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC2, location, count); +} + +bool ValidateUniform2i(ValidationContext *context, GLint location, GLint x, GLint y) +{ + return ValidateUniform(context, GL_INT_VEC2, location, 1); +} + +bool ValidateUniform2iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC2, location, count); +} + +bool ValidateUniform3f(ValidationContext *context, GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + return ValidateUniform(context, GL_FLOAT_VEC3, location, 1); +} + +bool ValidateUniform3fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC3, location, count); +} + +bool ValidateUniform3i(ValidationContext *context, GLint location, GLint x, GLint y, GLint z) +{ + return ValidateUniform(context, GL_INT_VEC3, location, 1); +} + +bool ValidateUniform3iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC3, location, count); +} + +bool ValidateUniform4f(ValidationContext *context, + GLint location, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) +{ + return ValidateUniform(context, GL_FLOAT_VEC4, location, 1); +} + +bool ValidateUniform4fv(ValidationContext *context, GLint location, GLsizei count, const GLfloat *v) +{ + return ValidateUniform(context, GL_FLOAT_VEC4, location, count); +} + +bool ValidateUniform4i(ValidationContext *context, + GLint location, + GLint x, + GLint y, + GLint z, + GLint w) +{ + return ValidateUniform(context, GL_INT_VEC4, location, 1); +} + +bool ValidateUniform4iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v) +{ + return ValidateUniform(context, GL_INT_VEC4, location, count); +} + +bool ValidateUniformMatrix2fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose); +} + +bool ValidateUniformMatrix3fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose); +} + +bool ValidateUniformMatrix4fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose); +} + +bool ValidateValidateProgram(ValidationContext *context, GLuint program) +{ + Program *programObject = GetValidProgram(context, program); + + if (!programObject) { - 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) +bool ValidateVertexAttrib1f(ValidationContext *context, GLuint index, GLfloat x) { - if (!context->getExtensions().debug) + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib1fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib2f(ValidationContext *context, GLuint index, GLfloat x, GLfloat y) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib2fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib3f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib3fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib4f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values) +{ + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (width < 0 || height < 0) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidValue(), ViewportNegativeSize); return false; } return true; } -bool ValidateGetDebugMessageLogKHR(Context *context, - GLuint count, - GLsizei bufSize, - GLenum *sources, - GLenum *types, - GLuint *ids, - GLenum *severities, - GLsizei *lengths, - GLchar *messageLog) +bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateDrawArraysCommon(context, mode, first, count, 1); +} - if (bufSize < 0 && messageLog != nullptr) +bool ValidateDrawElements(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices) +{ + return ValidateDrawElementsCommon(context, mode, count, type, indices, 1); +} + +bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) +{ + return ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname, + nullptr); +} + +bool ValidateGetProgramiv(ValidationContext *context, GLuint program, GLenum pname, GLint *params) +{ + return ValidateGetProgramivBase(context, program, pname, nullptr); +} + +bool ValidateCopyTexImage2D(ValidationContext *context, + GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError( - Error(GL_INVALID_VALUE, "bufSize must be positive if messageLog is not null.")); - return false; + return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0, + 0, x, y, width, height, border); } - return true; + ASSERT(context->getClientMajorVersion() == 3); + return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0, + 0, x, y, width, height, border); } -bool ValidatePushDebugGroupKHR(Context *context, - GLenum source, - GLuint id, - GLsizei length, - const GLchar *message) +bool ValidateCopyTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { - if (!context->getExtensions().debug) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; + return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, + yoffset, x, y, width, height, 0); } - if (!ValidDebugSource(source, true)) + return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset, + yoffset, 0, x, y, width, height, 0); +} + +bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateDisable(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, false)) { - context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - size_t messageLength = (length < 0) ? strlen(message) : length; - if (messageLength > context->getExtensions().maxDebugMessageLength) + return true; +} + +bool ValidateEnable(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, false)) { - context->recordError( - Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); - if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth) + if (context->getLimitations().noSampleAlphaToCoverageSupport && + cap == GL_SAMPLE_ALPHA_TO_COVERAGE) { - context->recordError( - Error(GL_STACK_OVERFLOW, - "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups.")); + const char *errorMessage = "Current renderer doesn't support alpha-to-coverage"; + context->handleError(InvalidOperation() << errorMessage); + + // We also output an error message to the debugger window if tracing is active, so that + // developers can see the error message. + ERR() << errorMessage; return false; } return true; } -bool ValidatePopDebugGroupKHR(Context *context) +bool ValidateFramebufferRenderbuffer(Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) { - if (!context->getExtensions().debug) + if (!ValidFramebufferTarget(context, target)) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); return false; } - size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); - if (currentStackSize <= 1) + if (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0) { - context->recordError(Error(GL_STACK_UNDERFLOW, "Cannot pop the default debug group.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidRenderbufferTarget); return false; } - return true; + return ValidateFramebufferRenderbufferParameters(context, target, attachment, + renderbuffertarget, renderbuffer); } -static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier, GLuint name) +bool ValidateFramebufferTexture2D(Context *context, + GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level) { - switch (identifier) + // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap + // extension + if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap && + level != 0) { - 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; + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidFramebufferTextureLevel); + return false; + } - case GL_PROGRAM: - if (context->getProgram(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid program.")); - return false; - } - return true; + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } - 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; + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); - case GL_QUERY: - if (context->getQuery(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid query.")); - return false; - } - return true; + const gl::Caps &caps = context->getCaps(); - case GL_TRANSFORM_FEEDBACK: - if (context->getTransformFeedback(name) == nullptr) + switch (textarget) + { + case GL_TEXTURE_2D: { - context->recordError( - Error(GL_INVALID_VALUE, "name is not a valid transform feedback.")); - return false; + if (level > gl::log2(caps.max2DTextureSize)) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidTextureTarget); + return false; + } } - return true; + break; - case GL_SAMPLER: - if (context->getSampler(name) == nullptr) + case GL_TEXTURE_RECTANGLE_ANGLE: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sampler.")); - return false; + if (level != 0) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_TEXTURE: - if (context->getTexture(name) == nullptr) + 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: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid texture.")); - return false; + if (level > gl::log2(caps.maxCubeMapTextureSize)) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_RENDERBUFFER: - if (context->getRenderbuffer(name) == nullptr) + case GL_TEXTURE_2D_MULTISAMPLE: { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid renderbuffer.")); - return false; + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (level != 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), LevelNotZero); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D_MULTISAMPLE) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } } - return true; + break; - case GL_FRAMEBUFFER: - if (context->getFramebuffer(name) == nullptr) - { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid framebuffer.")); + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; - } - return true; + } - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid identifier.")); + const Format &format = tex->getFormat(textarget, level); + if (format.info->compressed) + { + context->handleError(InvalidOperation()); return false; + } } return true; } -bool ValidateObjectLabelKHR(Context *context, - GLenum identifier, - GLuint name, - GLsizei length, - const GLchar *label) +bool ValidateGenBuffers(Context *context, GLint n, GLuint *) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGenOrDelete(context, n); +} - if (!ValidateObjectIdentifierAndName(context, identifier, name)) +bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenTextures(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenerateMipmap(Context *context, GLenum target) +{ + if (!ValidTextureTarget(context, target)) { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); return false; } - size_t labelLength = (length < 0) ? strlen(label) : length; - if (labelLength > context->getExtensions().maxLabelLength) + Texture *texture = context->getTargetTexture(target); + + if (texture == nullptr) { - context->recordError( - Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotBound); return false; } - return true; -} + const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel(); -bool ValidateGetObjectLabelKHR(Context *context, - GLenum identifier, - GLuint name, - GLsizei bufSize, - GLsizei *length, - GLchar *label) -{ - if (!context->getExtensions().debug) + // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so + // that out-of-range base level has a non-color-renderable / non-texture-filterable format. + if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + context->handleError(InvalidOperation()); return false; } - if (bufSize < 0) + GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; + const auto &format = *(texture->getFormat(baseTarget, effectiveBaseLevel).info); + if (format.sizedInternalFormat == GL_NONE || format.compressed || format.depthBits > 0 || + format.stencilBits > 0) { - context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - if (!ValidateObjectIdentifierAndName(context, identifier, name)) + // GenerateMipmap accepts formats that are unsized or both color renderable and filterable. + bool formatUnsized = !format.sized; + bool formatColorRenderableAndFilterable = + format.filterSupport(context->getClientVersion(), context->getExtensions()) && + format.renderSupport(context->getClientVersion(), context->getExtensions()); + if (!formatUnsized && !formatColorRenderableAndFilterable) { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); 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) + // GL_EXT_sRGB adds an unsized SRGB (no alpha) format which has explicitly disabled mipmap + // generation + if (format.colorEncoding == GL_SRGB && format.format == GL_RGB) { - context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sync.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - return true; -} - -bool ValidateObjectPtrLabelKHR(Context *context, - const void *ptr, - GLsizei length, - const GLchar *label) -{ - if (!context->getExtensions().debug) + // ES3 and WebGL grant mipmap generation for sRGBA (with alpha) textures but GL_EXT_sRGB does + // not. + bool supportsSRGBMipmapGeneration = + context->getClientVersion() >= ES_3_0 || context->getExtensions().webglCompatibility; + if (!supportsSRGBMipmapGeneration && format.colorEncoding == GL_SRGB) { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), GenerateMipmapNotAllowed); return false; } - if (!ValidateObjectPtrName(context, ptr)) + // Non-power of 2 ES2 check + if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNPOT && + (!isPow2(static_cast(texture->getWidth(baseTarget, 0))) || + !isPow2(static_cast(texture->getHeight(baseTarget, 0))))) { + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ANGLE || + target == GL_TEXTURE_CUBE_MAP); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotPow2); return false; } - size_t labelLength = (length < 0) ? strlen(label) : length; - if (labelLength > context->getExtensions().maxLabelLength) + // Cube completeness check + if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete()) { - context->recordError( - Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), CubemapIncomplete); return false; } return true; } -bool ValidateGetObjectPtrLabelKHR(Context *context, - const void *ptr, - GLsizei bufSize, - GLsizei *length, - GLchar *label) +bool ValidateGetBufferParameteriv(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint *params) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGetBufferParameterBase(context, target, pname, false, nullptr); +} - if (bufSize < 0) - { - context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); - return false; - } +bool ValidateGetRenderbufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params) +{ + return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr); +} - if (!ValidateObjectPtrName(context, ptr)) - { - return false; - } +bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params) +{ + return ValidateGetShaderivBase(context, shader, pname, nullptr); +} - // Can no-op if bufSize is zero. - return bufSize > 0; +bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params) +{ + return ValidateGetTexParameterBase(context, target, pname, nullptr); } -bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) +bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params) { - if (!context->getExtensions().debug) - { - context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); - return false; - } + return ValidateGetTexParameterBase(context, target, pname, nullptr); +} - // TODO: represent this in Context::getQueryParameterInfo. - switch (pname) - { - case GL_DEBUG_CALLBACK_FUNCTION: - case GL_DEBUG_CALLBACK_USER_PARAM: - break; +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params) +{ + return ValidateGetUniformBase(context, program, location); +} - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname.")); - return false; - } +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params) +{ + return ValidateGetUniformBase(context, program, location); +} - return true; +bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false); } -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 ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params) { - if (!context->getExtensions().framebufferBlit) + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false); +} + +bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, true, false); +} + +bool ValidateIsEnabled(Context *context, GLenum cap) +{ + if (!ValidCap(context, cap, true)) { - context->recordError(Error(GL_INVALID_OPERATION, "Blit extension not available.")); + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumNotSupported); return false; } - if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + return true; +} + +bool ValidateLinkProgram(Context *context, GLuint program) +{ + if (context->hasActiveTransformFeedback(program)) { - // 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.")); + // ES 3.0.4 section 2.15 page 91 + context->handleError(InvalidOperation() << "Cannot link program while program is " + "associated with an active transform " + "feedback object."); return false; } - if (filter == GL_LINEAR) + Program *programObject = GetValidProgram(context, program); + if (!programObject) { - 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(); + return true; +} - if (mask & GL_COLOR_BUFFER_BIT) - { - const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer(); - const FramebufferAttachment *drawColorAttachment = drawFramebuffer->getFirstColorbuffer(); +bool ValidateReadPixels(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels) +{ + return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, nullptr, + nullptr, pixels); +} - 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; - } +bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param) +{ + return ValidateTexParameterBase(context, target, pname, -1, ¶m); +} - 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; - } +bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params) +{ + return ValidateTexParameterBase(context, target, pname, -1, params); +} - // Return an error if the destination formats do not match - if (attachment->getInternalFormat() != readColorAttachment->getInternalFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } +bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param) +{ + return ValidateTexParameterBase(context, target, pname, -1, ¶m); +} - int readSamples = readFramebuffer->getSamples(context->getData()); +bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params) +{ + return ValidateTexParameterBase(context, target, pname, -1, params); +} - if (readSamples != 0 && - IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0, - srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) +bool ValidateUseProgram(Context *context, GLuint program) +{ + if (program != 0) + { + Program *programObject = context->getProgram(program); + if (!programObject) + { + // ES 3.1.0 section 7.3 page 72 + if (context->getShader(program)) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExpectedProgramName); 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) + else { - 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; - } + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidProgramName); + return false; } } + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + 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) + if (context->getGLState().isTransformFeedbackActiveUnpaused()) { - context->recordError(Error(GL_INVALID_VALUE)); + // ES 3.0.4 section 2.15 page 91 + context + ->handleError(InvalidOperation() + << "Cannot change active program while transform feedback is unpaused."); 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 1b2cf13f60..5dc09176a1 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES2.h +++ b/src/3rdparty/angle/src/libANGLE/validationES2.h @@ -9,6 +9,8 @@ #ifndef LIBANGLE_VALIDATION_ES2_H_ #define LIBANGLE_VALIDATION_ES2_H_ +#include "libANGLE/PackedGLEnums.h" + #include #include @@ -17,37 +19,24 @@ 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(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, - GLsizei width, GLsizei height); - -bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type); - -bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, +bool ValidateES2TexStorageParameters(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height); + +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 ValidateDeleteVertexArraysOES(Context *context, GLsizei n, const GLuint *arrays); +bool ValidateGenVertexArraysOES(Context *context, GLsizei n, GLuint *arrays); +bool ValidateIsVertexArrayOES(Context *context, GLuint array); bool ValidateProgramBinaryOES(Context *context, GLuint program, @@ -128,7 +117,571 @@ bool ValidateBlitFramebufferANGLE(Context *context, GLenum filter); bool ValidateClear(ValidationContext *context, GLbitfield mask); +bool ValidateTexImage2D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexImage2DRobust(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateCompressedTexImage2D(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data); +bool ValidateCompressedTexSubImage2DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data); + +bool ValidateBindTexture(Context *context, GLenum target, GLuint texture); + +bool ValidateGetBufferPointervOES(Context *context, + BufferBinding target, + GLenum pname, + void **params); +bool ValidateMapBufferOES(Context *context, BufferBinding target, GLenum access); +bool ValidateUnmapBufferOES(Context *context, BufferBinding target); +bool ValidateMapBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateMapBufferBase(Context *context, BufferBinding target); +bool ValidateFlushMappedBufferRangeEXT(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateBindUniformLocationCHROMIUM(Context *context, + GLuint program, + GLint location, + const GLchar *name); + +bool ValidateCoverageModulationCHROMIUM(Context *context, GLenum components); + +// CHROMIUM_path_rendering +bool ValidateMatrix(Context *context, GLenum matrixMode, const GLfloat *matrix); +bool ValidateMatrixMode(Context *context, GLenum matrixMode); +bool ValidateGenPaths(Context *context, GLsizei range); +bool ValidateDeletePaths(Context *context, GLuint first, GLsizei range); +bool ValidatePathCommands(Context *context, + GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); +bool ValidateSetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat value); +bool ValidateGetPathParameter(Context *context, GLuint path, GLenum pname, GLfloat *value); +bool ValidatePathStencilFunc(Context *context, GLenum func, GLint ref, GLuint mask); +bool ValidateStencilFillPath(Context *context, GLuint path, GLenum fillMode, GLuint mask); +bool ValidateStencilStrokePath(Context *context, GLuint path, GLint reference, GLuint mask); +bool ValidateCoverPath(Context *context, GLuint path, GLenum coverMode); +bool ValidateStencilThenCoverFillPath(Context *context, + GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); +bool ValidateStencilThenCoverStrokePath(Context *context, + GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode); +bool ValidateIsPath(Context *context); +bool ValidateCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBAse, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilThenCoverFillPathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateStencilThenCoverStrokePathInstanced(Context *context, + GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +bool ValidateBindFragmentInputLocation(Context *context, + GLuint program, + GLint location, + const GLchar *name); +bool ValidateProgramPathFragmentInputGen(Context *context, + GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + +bool ValidateCopyTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +bool ValidateCopySubTextureCHROMIUM(Context *context, + GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); +bool ValidateCompressedCopyTextureCHROMIUM(Context *context, GLuint sourceId, GLuint destId); + +bool ValidateCreateShader(Context *context, GLenum type); +bool ValidateBufferData(ValidationContext *context, + BufferBinding target, + GLsizeiptr size, + const void *data, + BufferUsage usage); +bool ValidateBufferSubData(ValidationContext *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr size, + const void *data); + +bool ValidateRequestExtensionANGLE(Context *context, const GLchar *name); + +bool ValidateActiveTexture(ValidationContext *context, GLenum texture); +bool ValidateAttachShader(ValidationContext *context, GLuint program, GLuint shader); +bool ValidateBindAttribLocation(ValidationContext *context, + GLuint program, + GLuint index, + const GLchar *name); +bool ValidateBindBuffer(ValidationContext *context, BufferBinding target, GLuint buffer); +bool ValidateBindFramebuffer(ValidationContext *context, GLenum target, GLuint framebuffer); +bool ValidateBindRenderbuffer(ValidationContext *context, GLenum target, GLuint renderbuffer); +bool ValidateBlendColor(ValidationContext *context, + GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); +bool ValidateBlendEquation(ValidationContext *context, GLenum mode); +bool ValidateBlendEquationSeparate(ValidationContext *context, GLenum modeRGB, GLenum modeAlpha); +bool ValidateBlendFunc(ValidationContext *context, GLenum sfactor, GLenum dfactor); +bool ValidateBlendFuncSeparate(ValidationContext *context, + GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha); + +bool ValidateGetString(Context *context, GLenum name); +bool ValidateLineWidth(ValidationContext *context, GLfloat width); +bool ValidateVertexAttribPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr); + +bool ValidateDepthRangef(ValidationContext *context, GLclampf zNear, GLclampf zFar); +bool ValidateRenderbufferStorage(ValidationContext *context, + GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height); +bool ValidateRenderbufferStorageMultisampleANGLE(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + +bool ValidateCheckFramebufferStatus(ValidationContext *context, GLenum target); +bool ValidateClearColor(ValidationContext *context, + GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); +bool ValidateClearDepthf(ValidationContext *context, GLclampf depth); +bool ValidateClearStencil(ValidationContext *context, GLint s); +bool ValidateColorMask(ValidationContext *context, + GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha); +bool ValidateCompileShader(ValidationContext *context, GLuint shader); +bool ValidateCreateProgram(ValidationContext *context); +bool ValidateCullFace(ValidationContext *context, CullFaceMode mode); +bool ValidateDeleteProgram(ValidationContext *context, GLuint program); +bool ValidateDeleteShader(ValidationContext *context, GLuint shader); +bool ValidateDepthFunc(ValidationContext *context, GLenum func); +bool ValidateDepthMask(ValidationContext *context, GLboolean flag); +bool ValidateDetachShader(ValidationContext *context, GLuint program, GLuint shader); +bool ValidateDisableVertexAttribArray(ValidationContext *context, GLuint index); +bool ValidateEnableVertexAttribArray(ValidationContext *context, GLuint index); +bool ValidateFinish(ValidationContext *context); +bool ValidateFlush(ValidationContext *context); +bool ValidateFrontFace(ValidationContext *context, GLenum mode); +bool ValidateGetActiveAttrib(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +bool ValidateGetActiveUniform(ValidationContext *context, + GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +bool ValidateGetAttachedShaders(ValidationContext *context, + GLuint program, + GLsizei maxcount, + GLsizei *count, + GLuint *shaders); +bool ValidateGetAttribLocation(ValidationContext *context, GLuint program, const GLchar *name); +bool ValidateGetBooleanv(ValidationContext *context, GLenum pname, GLboolean *params); +bool ValidateGetError(ValidationContext *context); +bool ValidateGetFloatv(ValidationContext *context, GLenum pname, GLfloat *params); +bool ValidateGetIntegerv(ValidationContext *context, GLenum pname, GLint *params); +bool ValidateGetProgramInfoLog(ValidationContext *context, + GLuint program, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog); +bool ValidateGetShaderInfoLog(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog); +bool ValidateGetShaderPrecisionFormat(ValidationContext *context, + GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision); +bool ValidateGetShaderSource(ValidationContext *context, + GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source); +bool ValidateGetUniformLocation(ValidationContext *context, GLuint program, const GLchar *name); +bool ValidateHint(ValidationContext *context, GLenum target, GLenum mode); +bool ValidateIsBuffer(ValidationContext *context, GLuint buffer); +bool ValidateIsFramebuffer(ValidationContext *context, GLuint framebuffer); +bool ValidateIsProgram(ValidationContext *context, GLuint program); +bool ValidateIsRenderbuffer(ValidationContext *context, GLuint renderbuffer); +bool ValidateIsShader(ValidationContext *context, GLuint shader); +bool ValidateIsTexture(ValidationContext *context, GLuint texture); +bool ValidatePixelStorei(ValidationContext *context, GLenum pname, GLint param); +bool ValidatePolygonOffset(ValidationContext *context, GLfloat factor, GLfloat units); +bool ValidateReleaseShaderCompiler(ValidationContext *context); +bool ValidateSampleCoverage(ValidationContext *context, GLclampf value, GLboolean invert); +bool ValidateScissor(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height); +bool ValidateShaderBinary(ValidationContext *context, + GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length); +bool ValidateShaderSource(ValidationContext *context, + GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length); +bool ValidateStencilFunc(ValidationContext *context, GLenum func, GLint ref, GLuint mask); +bool ValidateStencilFuncSeparate(ValidationContext *context, + GLenum face, + GLenum func, + GLint ref, + GLuint mask); +bool ValidateStencilMask(ValidationContext *context, GLuint mask); +bool ValidateStencilMaskSeparate(ValidationContext *context, GLenum face, GLuint mask); +bool ValidateStencilOp(ValidationContext *context, GLenum fail, GLenum zfail, GLenum zpass); +bool ValidateStencilOpSeparate(ValidationContext *context, + GLenum face, + GLenum fail, + GLenum zfail, + GLenum zpass); +bool ValidateUniform1f(ValidationContext *context, GLint location, GLfloat x); +bool ValidateUniform1fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform1i(ValidationContext *context, GLint location, GLint x); +bool ValidateUniform2f(ValidationContext *context, GLint location, GLfloat x, GLfloat y); +bool ValidateUniform2fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform2i(ValidationContext *context, GLint location, GLint x, GLint y); +bool ValidateUniform2iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniform3f(ValidationContext *context, GLint location, GLfloat x, GLfloat y, GLfloat z); +bool ValidateUniform3fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform3i(ValidationContext *context, GLint location, GLint x, GLint y, GLint z); +bool ValidateUniform3iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniform4f(ValidationContext *context, + GLint location, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w); +bool ValidateUniform4fv(ValidationContext *context, + GLint location, + GLsizei count, + const GLfloat *v); +bool ValidateUniform4i(ValidationContext *context, + GLint location, + GLint x, + GLint y, + GLint z, + GLint w); +bool ValidateUniform4iv(ValidationContext *context, GLint location, GLsizei count, const GLint *v); +bool ValidateUniformMatrix2fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4fv(ValidationContext *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateValidateProgram(ValidationContext *context, GLuint program); +bool ValidateVertexAttrib1f(ValidationContext *context, GLuint index, GLfloat x); +bool ValidateVertexAttrib1fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib2f(ValidationContext *context, GLuint index, GLfloat x, GLfloat y); +bool ValidateVertexAttrib2fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib3f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z); +bool ValidateVertexAttrib3fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateVertexAttrib4f(ValidationContext *context, + GLuint index, + GLfloat x, + GLfloat y, + GLfloat z, + GLfloat w); +bool ValidateVertexAttrib4fv(ValidationContext *context, GLuint index, const GLfloat *values); +bool ValidateViewport(ValidationContext *context, GLint x, GLint y, GLsizei width, GLsizei height); +bool ValidateDrawElements(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices); + +bool ValidateDrawArrays(ValidationContext *context, GLenum mode, GLint first, GLsizei count); + +bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context, + GLenum target, + GLenum attachment, + GLenum pname, + GLint *params); +bool ValidateGetProgramiv(ValidationContext *context, GLuint program, GLenum pname, GLint *params); + +bool ValidateCopyTexImage2D(ValidationContext *context, + GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border); + +bool ValidateCopyTexSubImage2D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height); + +bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *buffers); +bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *framebuffers); +bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *renderbuffers); +bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *textures); +bool ValidateDisable(Context *context, GLenum cap); +bool ValidateEnable(Context *context, GLenum cap); +bool ValidateFramebufferRenderbuffer(Context *context, + GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +bool ValidateFramebufferTexture2D(Context *context, + GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level); +bool ValidateGenBuffers(Context *context, GLint n, GLuint *buffers); +bool ValidateGenerateMipmap(Context *context, GLenum target); +bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *framebuffers); +bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *renderbuffers); +bool ValidateGenTextures(Context *context, GLint n, GLuint *textures); +bool ValidateGetBufferParameteriv(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint *params); +bool ValidateGetRenderbufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params); +bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params); +bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params); +bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params); +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params); +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params); +bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params); +bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params); +bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer); +bool ValidateIsEnabled(Context *context, GLenum cap); +bool ValidateLinkProgram(Context *context, GLuint program); +bool ValidateReadPixels(Context *context, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels); +bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param); +bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params); +bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param); +bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params); +bool ValidateUniform1iv(ValidationContext *context, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateUseProgram(Context *context, GLuint program); } // namespace gl -#endif // LIBANGLE_VALIDATION_ES2_H_ +#endif // LIBANGLE_VALIDATION_ES2_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.cpp b/src/3rdparty/angle/src/libANGLE/validationES3.cpp index 2db64ec4cc..1aadfc876e 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES3.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES3.cpp @@ -7,255 +7,190 @@ // validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters #include "libANGLE/validationES3.h" -#include "libANGLE/validationES.h" + +#include "anglebase/numerics/safe_conversions.h" +#include "common/mathutil.h" +#include "common/utilities.h" #include "libANGLE/Context.h" -#include "libANGLE/Texture.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" #include "libANGLE/formatutils.h" -#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/validationES.h" -#include "common/mathutil.h" -#include "common/utilities.h" +using namespace angle; namespace gl { -struct ES3FormatCombination +namespace { - GLenum internalFormat; - GLenum format; - GLenum type; -}; +bool ValidateFramebufferTextureMultiviewBaseANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews) +{ + if (!context->getExtensions().multiview) + { + context->handleError(InvalidOperation() << "ANGLE_multiview is not available."); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + if (texture != 0 && numViews < 1) + { + context->handleError(InvalidValue() << "numViews cannot be less than 1."); + return false; + } + + const Extensions &extensions = context->getExtensions(); + if (static_cast(numViews) > extensions.maxViews) + { + context->handleError(InvalidValue() + << "numViews cannot be greater than GL_MAX_VIEWS_ANGLE."); + return false; + } + + return true; +} -bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b) -{ - return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0; -} - -typedef std::set ES3FormatCombinationSet; - -static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type) -{ - ES3FormatCombination info; - info.internalFormat = internalFormat; - info.format = format; - info.type = type; - set->insert(info); -} - -ES3FormatCombinationSet BuildES3FormatSet() -{ - ES3FormatCombinationSet set; - - // Format combinations from ES 3.0.1 spec, table 3.2 - - // | Internal format | Format | Type | - // | | | | - InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); - InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT ); - - // Unsized formats - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); - InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE ); - 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 ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 ); - InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); - - // From GL_EXT_sRGB - InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); - 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 ); - - // From GL_OES_texture_half_float - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES ); - - // From GL_EXT_texture_format_BGRA8888 - InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - - // From GL_EXT_texture_storage - // | Internal format | Format | Type | - // | | | | - InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); - - // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888 - InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT); - InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT); - InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - - // From GL_ANGLE_depth_texture - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES ); - - return set; -} - -static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) +bool ValidateFramebufferTextureMultiviewLevelAndFormat(Context *context, + Texture *texture, + GLint level) { - // 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())) + GLenum texTarget = texture->getTarget(); + if (!ValidMipLevel(context, texTarget, level)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidMipLevel); + return false; + } + + const auto &format = texture->getFormat(texTarget, level); + if (format.info->compressed) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), CompressedTexturesNotAttachable); + return false; + } + return true; +} + +bool ValidateUniformES3(Context *context, GLenum uniformType, GLint location, GLint count) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUniform(context, uniformType, location, count); +} + +bool ValidateUniformMatrixES3(Context *context, + GLenum valueType, + GLint location, + GLsizei count, + GLboolean transpose) +{ + // Check for ES3 uniform entry points + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUniformMatrix(context, valueType, location, count, transpose); +} + +bool ValidateGenOrDeleteES3(Context *context, GLint n) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenOrDeleteCountES3(Context *context, GLint count) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + return true; +} + +} // anonymous namespace + +static bool ValidateTexImageFormatCombination(gl::Context *context, + GLenum target, + GLenum internalFormat, + GLenum format, + GLenum type) +{ // The type and format are valid if any supported internal format has that type and format - bool formatSupported = false; - bool typeSupported = false; + if (!ValidES3Format(format)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFormat); + return false; + } - static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet(); - for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++) + if (!ValidES3Type(type)) { - if (i->format == format || i->type == type) - { - const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat); - bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions()); - if (supported && i->type == type) - { - typeSupported = true; - } - if (supported && i->format == format) - { - formatSupported = true; - } + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidType); + return false; + } - // Early-out if both type and format are supported now - if (typeSupported && formatSupported) - { - break; - } - } + // 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. + if (!ValidES3InternalFormat(internalFormat)) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidInternalFormat); + return false; } - if (!typeSupported || !formatSupported) + // From the ES 3.0 spec section 3.8.3: + // Textures with a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL are supported by + // texture image specification commands only if target is TEXTURE_2D, TEXTURE_2D_ARRAY, or + // TEXTURE_CUBE_MAP.Using these formats in conjunction with any other target will result in an + // INVALID_OPERATION error. + if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidOperation() << "Format cannot be GL_DEPTH_COMPONENT or " + "GL_DEPTH_STENCIL if target is " + "GL_TEXTURE_3D"); return false; } // Check if this is a valid format combination to load texture data - ES3FormatCombination searchFormat; - searchFormat.internalFormat = internalFormat; - searchFormat.format = format; - searchFormat.type = type; + if (!ValidES3FormatCombination(format, type, internalFormat)) + { + context->handleError(InvalidOperation() + << "Invalid combination of format, type and internalFormat."); + return false; + } - if (es3FormatSet.find(searchFormat) == es3FormatSet.end()) + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Unsupported internal format."); return false; } @@ -277,19 +212,20 @@ bool ValidateES3TexImageParametersBase(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei imageSize, + const void *pixels) { // Validate image size if (!ValidImageSizeParameters(context, target, level, width, height, depth, isSubImage)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } // Verify zero border if (border != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -298,7 +234,7 @@ bool ValidateES3TexImageParametersBase(Context *context, std::numeric_limits::max() - yoffset < height || std::numeric_limits::max() - zoffset < depth) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -306,112 +242,158 @@ bool ValidateES3TexImageParametersBase(Context *context, switch (target) { - case GL_TEXTURE_2D: - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; + case GL_TEXTURE_2D: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + break; - 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: - if (!isSubImage && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } + case GL_TEXTURE_RECTANGLE_ANGLE: + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; - if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; + 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: + if (!isSubImage && width != height) + { + context->handleError(InvalidValue()); + return false; + } - case GL_TEXTURE_3D: - if (static_cast(width) > (caps.max3DTextureSize >> level) || - static_cast(height) > (caps.max3DTextureSize >> level) || - static_cast(depth) > (caps.max3DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + break; - case GL_TEXTURE_2D_ARRAY: - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level) || - static_cast(depth) > caps.maxArrayTextureLayers) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; + case GL_TEXTURE_3D: + if (static_cast(width) > (caps.max3DTextureSize >> level) || + static_cast(height) > (caps.max3DTextureSize >> level) || + static_cast(depth) > (caps.max3DTextureSize >> level)) + { + context->handleError(InvalidValue()); + return false; + } + break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; + case GL_TEXTURE_2D_ARRAY: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level) || + static_cast(depth) > caps.maxArrayTextureLayers) + { + context->handleError(InvalidValue()); + return false; + } + break; + + default: + context->handleError(InvalidEnum()); + return false; } - gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + gl::Texture *texture = + context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); if (!texture) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } if (texture->getImmutableFormat() && !isSubImage) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } // Validate texture formats - GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat); + GLenum actualInternalFormat = + isSubImage ? texture->getFormat(target, level).info->internalFormat : internalformat; + if (isSubImage && actualInternalFormat == GL_NONE) + { + context->handleError(InvalidOperation() << "Texture level does not exist."); + return false; + } + + const gl::InternalFormat &actualFormatInfo = isSubImage + ? *texture->getFormat(target, level).info + : GetInternalFormatInfo(internalformat, type); if (isCompressed) { if (!actualFormatInfo.compressed) { - context->recordError(Error( - GL_INVALID_ENUM, "internalformat is not a supported compressed internal format.")); + context->handleError( + InvalidEnum() << "internalformat is not a supported compressed internal format."); return false; } - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + if (isSubImage) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + if (!ValidCompressedSubImageSize( + context, actualFormatInfo.internalFormat, xoffset, yoffset, width, height, + texture->getWidth(target, level), texture->getHeight(target, level))) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } + + if (format != actualInternalFormat) + { + context->handleError(InvalidOperation() + << "Format must match the internal format of the texture."); + return false; + } + + if (actualInternalFormat == GL_ETC1_RGB8_OES) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), InvalidInternalFormat); + return false; + } + } + else + { + if (!ValidCompressedImageSize(context, actualInternalFormat, level, width, height)) + { + context->handleError(InvalidOperation() << "Invalid compressed format dimension."); + return false; + } } if (!actualFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } if (target == GL_TEXTURE_3D) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } else { - if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type)) - { - return false; - } - - if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) + if (!ValidateTexImageFormatCombination(context, target, actualInternalFormat, format, type)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } } @@ -421,18 +403,13 @@ bool ValidateES3TexImageParametersBase(Context *context, { if (isCompressed != actualFormatInfo.compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (width == 0 || height == 0 || depth == 0) - { + context->handleError(InvalidOperation()); return false; } if (xoffset < 0 || yoffset < 0 || zoffset < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -440,7 +417,7 @@ bool ValidateES3TexImageParametersBase(Context *context, std::numeric_limits::max() - yoffset < height || std::numeric_limits::max() - zoffset < depth) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -448,54 +425,42 @@ bool ValidateES3TexImageParametersBase(Context *context, static_cast(yoffset + height) > texture->getHeight(target, level) || static_cast(zoffset + depth) > texture->getDepth(target, level)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } - } - - // Check for pixel unpack buffer related API errors - gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER); - if (pixelUnpackBuffer != NULL) - { - // ...the data would be unpacked from the buffer object such that the memory reads required - // would exceed the data store size. - size_t widthSize = static_cast(width); - size_t heightSize = static_cast(height); - size_t depthSize = static_cast(depth); - GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type); - size_t pixelBytes = static_cast(gl::GetInternalFormatInfo(sizedFormat).pixelBytes); - - if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) || - !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) || - !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes)) + if (width > 0 && height > 0 && depth > 0 && pixels == nullptr && + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr) { - // Overflow past the end of the buffer - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidValue(), PixelDataNull); return false; } + } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); - size_t copyBytes = formatInfo.computeBlockSize(type, width, height); - size_t offset = reinterpret_cast(pixels); - - if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || - ((offset + copyBytes) > static_cast(pixelUnpackBuffer->getSize()))) - { - // Overflow past the end of the buffer - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } + GLenum sizeCheckFormat = isSubImage ? format : internalformat; + if (!ValidImageDataSize(context, target, width, height, depth, sizeCheckFormat, type, pixels, + imageSize)) + { + return false; + } - // ...data is not evenly divisible into the number of bytes needed to store in memory a datum + // Check for pixel unpack buffer related API errors + gl::Buffer *pixelUnpackBuffer = + context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack); + if (pixelUnpackBuffer != nullptr) + { + // ...data is not evenly divisible into the number of bytes needed to store in memory a + // datum // indicated by type. if (!isCompressed) { + size_t offset = reinterpret_cast(pixels); size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); if ((offset % dataBytesPerPixel) != 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() + << "Reads would overflow the pixel unpack buffer."); return false; } } @@ -503,7 +468,7 @@ bool ValidateES3TexImageParametersBase(Context *context, // ...the buffer object's data store is currently mapped. if (pixelUnpackBuffer->isMapped()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Pixel unpack buffer is mapped."); return false; } } @@ -526,17 +491,18 @@ bool ValidateES3TexImage2DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei imageSize, + const void *pixels) { if (!ValidTexture2DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed, isSubImage, xoffset, yoffset, zoffset, width, height, - depth, border, format, type, pixels); + depth, border, format, type, imageSize, pixels); } bool ValidateES3TexImage3DParameters(Context *context, @@ -554,301 +520,260 @@ bool ValidateES3TexImage3DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) + GLsizei bufSize, + const void *pixels) { if (!ValidTexture3DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } return ValidateES3TexImageParametersBase(context, target, level, internalformat, isCompressed, isSubImage, xoffset, yoffset, zoffset, width, height, - depth, border, format, type, pixels); + depth, border, format, type, bufSize, pixels); } struct EffectiveInternalFormatInfo { - GLenum mEffectiveFormat; - GLenum mDestFormat; - GLuint mMinRedBits; - GLuint mMaxRedBits; - GLuint mMinGreenBits; - GLuint mMaxGreenBits; - GLuint mMinBlueBits; - GLuint mMaxBlueBits; - GLuint mMinAlphaBits; - GLuint mMaxAlphaBits; - - EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits, - GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits, - GLuint minAlphaBits, GLuint maxAlphaBits) - : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits), - mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits), - mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits), - mMaxAlphaBits(maxAlphaBits) {}; + GLenum effectiveFormat; + GLenum destFormat; + GLuint minRedBits; + GLuint maxRedBits; + GLuint minGreenBits; + GLuint maxGreenBits; + GLuint minBlueBits; + GLuint maxBlueBits; + GLuint minAlphaBits; + GLuint maxAlphaBits; }; -typedef std::vector EffectiveInternalFormatList; - -static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() +static bool QueryEffectiveFormatList(const InternalFormat &srcFormat, + GLenum targetFormat, + const EffectiveInternalFormatInfo *list, + size_t size, + GLenum *outEffectiveFormat) { - EffectiveInternalFormatList list; - - // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and - // linear source buffer component sizes. - // | Source channel min/max sizes | - // Effective Internal Format | N/A | R | G | B | A | - list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2)); + for (size_t curFormat = 0; curFormat < size; ++curFormat) + { + const EffectiveInternalFormatInfo &formatInfo = list[curFormat]; + if ((formatInfo.destFormat == targetFormat) && + (formatInfo.minRedBits <= srcFormat.redBits && + formatInfo.maxRedBits >= srcFormat.redBits) && + (formatInfo.minGreenBits <= srcFormat.greenBits && + formatInfo.maxGreenBits >= srcFormat.greenBits) && + (formatInfo.minBlueBits <= srcFormat.blueBits && + formatInfo.maxBlueBits >= srcFormat.blueBits) && + (formatInfo.minAlphaBits <= srcFormat.alphaBits && + formatInfo.maxAlphaBits >= srcFormat.alphaBits)) + { + *outEffectiveFormat = formatInfo.effectiveFormat; + return true; + } + } - return list; + *outEffectiveFormat = GL_NONE; + return false; } -static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() +bool GetSizedEffectiveInternalFormatInfo(const InternalFormat &srcFormat, + GLenum *outEffectiveFormat) { - EffectiveInternalFormatList list; - - // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and - // linear source buffer component sizes. - // | Source channel min/max sizes | - // Effective Internal Format | Dest Format | R | G | B | A | - list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8)); + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: + // Effective internal format coresponding to destination internal format and linear source + // buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | N/A | R | G | B | A | + // clang-format off + constexpr EffectiveInternalFormatInfo list[] = { + { GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8 }, + { GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0 }, + { GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0 }, + { GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0 }, + { GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0 }, + { GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4 }, + { GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1 }, + { GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8 }, + { GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2 }, + }; + // clang-format on + + return QueryEffectiveFormatList(srcFormat, GL_NONE, list, ArraySize(list), outEffectiveFormat); +} - return list; +bool GetUnsizedEffectiveInternalFormatInfo(const InternalFormat &srcFormat, + const InternalFormat &destFormat, + GLenum *outEffectiveFormat) +{ + constexpr GLuint umax = UINT_MAX; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: + // Effective internal format coresponding to destination internal format andlinear source buffer + // component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | Dest Format | R | G | B | A | + // clang-format off + constexpr EffectiveInternalFormatInfo list[] = { + { GL_ALPHA8_EXT, GL_ALPHA, 0, umax, 0, umax, 0, umax, 1, 8 }, + { GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, umax, 0, umax, 0, umax }, + { GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, umax, 0, umax, 1, 8 }, + { GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, umax }, + { GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, umax }, + { GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4 }, + { GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1 }, + { GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8 }, + }; + // clang-format on + + return QueryEffectiveFormatList(srcFormat, destFormat.format, list, ArraySize(list), + outEffectiveFormat); } -static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat, +static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, + const InternalFormat &destFormat, GLenum *outEffectiveFormat) { - const EffectiveInternalFormatList *list = NULL; - GLenum targetFormat = GL_NONE; - - if (destFormat.pixelBytes > 0) + if (destFormat.sized) { - static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); - list = &sizedList; + return GetSizedEffectiveInternalFormatInfo(srcFormat, outEffectiveFormat); } else { - static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList(); - list = &unsizedList; - targetFormat = destFormat.format; - } - - for (size_t curFormat = 0; curFormat < list->size(); ++curFormat) - { - const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat); - if ((formatInfo.mDestFormat == targetFormat) && - (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) && - (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) && - (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) && - (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits)) - { - *outEffectiveFormat = formatInfo.mEffectiveFormat; - return true; - } + return GetUnsizedEffectiveInternalFormatInfo(srcFormat, destFormat, outEffectiveFormat); } +} - return false; +static bool EqualOrFirstZero(GLuint first, GLuint second) +{ + return first == 0 || first == second; } -struct CopyConversion +static bool IsValidES3CopyTexImageCombination(const InternalFormat &textureFormatInfo, + const InternalFormat &framebufferFormatInfo, + GLuint readBufferHandle) { - GLenum mTextureFormat; - GLenum mFramebufferFormat; + if (!ValidES3CopyConversion(textureFormatInfo.format, framebufferFormatInfo.format)) + { + return false; + } - CopyConversion(GLenum textureFormat, GLenum framebufferFormat) - : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } + // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats + // must both be signed, unsigned, or fixed point and both source and destinations + // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed + // conversion between fixed and floating point. - bool operator<(const CopyConversion& other) const + if ((textureFormatInfo.colorEncoding == GL_SRGB) != + (framebufferFormatInfo.colorEncoding == GL_SRGB)) { - return memcmp(this, &other, sizeof(CopyConversion)) < 0; + return false; } -}; -typedef std::set CopyConversionSet; - -static CopyConversionSet BuildValidES3CopyTexImageCombinations() -{ - CopyConversionSet set; - - // From ES 3.0.1 spec, table 3.15 - set.insert(CopyConversion(GL_ALPHA, GL_RGBA)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RED)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RG)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RGB)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA)); - set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA)); - set.insert(CopyConversion(GL_RED, GL_RED)); - set.insert(CopyConversion(GL_RED, GL_RG)); - set.insert(CopyConversion(GL_RED, GL_RGB)); - set.insert(CopyConversion(GL_RED, GL_RGBA)); - set.insert(CopyConversion(GL_RG, GL_RG)); - set.insert(CopyConversion(GL_RG, GL_RGB)); - set.insert(CopyConversion(GL_RG, GL_RGBA)); - set.insert(CopyConversion(GL_RGB, GL_RGB)); - set.insert(CopyConversion(GL_RGB, GL_RGBA)); - set.insert(CopyConversion(GL_RGBA, GL_RGBA)); - - // Necessary for ANGLE back-buffers - set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RED, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RG, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT)); - - set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER)); - - return set; -} - -static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle) -{ - const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat); - const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat); - - static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations(); - if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end()) - { - // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats - // must both be signed, unsigned, or fixed point and both source and destinations - // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed - // conversion between fixed and floating point. - - if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)) - { - return false; - } + if (((textureFormatInfo.componentType == GL_INT) != + (framebufferFormatInfo.componentType == GL_INT)) || + ((textureFormatInfo.componentType == GL_UNSIGNED_INT) != + (framebufferFormatInfo.componentType == GL_UNSIGNED_INT))) + { + return false; + } + + if ((textureFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + textureFormatInfo.componentType == GL_SIGNED_NORMALIZED || + textureFormatInfo.componentType == GL_FLOAT) && + !(framebufferFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + framebufferFormatInfo.componentType == GL_SIGNED_NORMALIZED || + framebufferFormatInfo.componentType == GL_FLOAT)) + { + return false; + } - if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) || - ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT))) + // GLES specification 3.0.3, sec 3.8.5, pg 139-140: + // The effective internal format of the source buffer is determined with the following rules + // applied in order: + // * If the source buffer is a texture or renderbuffer that was created with a sized internal + // format then the effective internal format is the source buffer's sized internal format. + // * If the source buffer is a texture that was created with an unsized base internal format, + // then the effective internal format is the source image array's effective internal + // format, as specified by table 3.12, which is determined from the and + // that were used when the source image array was specified by TexImage*. + // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 + // where Destination Internal Format matches internalformat and where the [source channel + // sizes] are consistent with the values of the source buffer's [channel sizes]. Table 3.17 + // is used if the FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the + // FRAMEBUFFER_ATTACHMENT_ENCODING is SRGB. + const InternalFormat *sourceEffectiveFormat = nullptr; + if (readBufferHandle != 0) + { + // Not the default framebuffer, therefore the read buffer must be a user-created texture or + // renderbuffer + if (framebufferFormatInfo.sized) { - return false; + sourceEffectiveFormat = &framebufferFormatInfo; } - - if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || - textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || - textureInternalFormatInfo.componentType == GL_FLOAT) && - !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || - framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || - framebufferInternalFormatInfo.componentType == GL_FLOAT)) + else { - return false; + // Renderbuffers cannot be created with an unsized internal format, so this must be an + // unsized-format texture. We can use the same table we use when creating textures to + // get its effective sized format. + sourceEffectiveFormat = + &GetSizedInternalFormatInfo(framebufferFormatInfo.sizedInternalFormat); } - - // GLES specification 3.0.3, sec 3.8.5, pg 139-140: - // The effective internal format of the source buffer is determined with the following rules applied in order: - // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the - // effective internal format is the source buffer's sized internal format. - // * If the source buffer is a texture that was created with an unsized base internal format, then the - // effective internal format is the source image array's effective internal format, as specified by table - // 3.12, which is determined from the and that were used when the source image array was - // specified by TexImage*. - // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where - // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent - // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the - // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING - // is SRGB. - InternalFormat sourceEffectiveFormat; - if (readBufferHandle != 0) + } + else + { + // The effective internal format must be derived from the source framebuffer's channel + // sizes. This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) + if (framebufferFormatInfo.colorEncoding == GL_LINEAR) { - // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer - if (framebufferInternalFormatInfo.pixelBytes > 0) + GLenum effectiveFormat; + if (GetEffectiveInternalFormat(framebufferFormatInfo, textureFormatInfo, + &effectiveFormat)) { - sourceEffectiveFormat = framebufferInternalFormatInfo; + sourceEffectiveFormat = &GetSizedInternalFormatInfo(effectiveFormat); } else { - // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format - // texture. We can use the same table we use when creating textures to get its effective sized format. - GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type); - sourceEffectiveFormat = GetInternalFormatInfo(sizedInternalFormat); + return false; } } - else + else if (framebufferFormatInfo.colorEncoding == GL_SRGB) { - // The effective internal format must be derived from the source framebuffer's channel sizes. - // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) - if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR) + // SRGB buffers can only be copied to sized format destinations according to table 3.18 + if (textureFormatInfo.sized && + (framebufferFormatInfo.redBits >= 1 && framebufferFormatInfo.redBits <= 8) && + (framebufferFormatInfo.greenBits >= 1 && framebufferFormatInfo.greenBits <= 8) && + (framebufferFormatInfo.blueBits >= 1 && framebufferFormatInfo.blueBits <= 8) && + (framebufferFormatInfo.alphaBits >= 1 && framebufferFormatInfo.alphaBits <= 8)) { - GLenum effectiveFormat; - if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat)) - { - sourceEffectiveFormat = GetInternalFormatInfo(effectiveFormat); - } - else - { - return false; - } - } - else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB) - { - // SRGB buffers can only be copied to sized format destinations according to table 3.18 - if ((textureInternalFormatInfo.pixelBytes > 0) && - (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) && - (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) && - (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) && - (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8)) - { - sourceEffectiveFormat = GetInternalFormatInfo(GL_SRGB8_ALPHA8); - } - else - { - return false; - } + sourceEffectiveFormat = &GetSizedInternalFormatInfo(GL_SRGB8_ALPHA8); } else { - UNREACHABLE(); return false; } } - - if (textureInternalFormatInfo.pixelBytes > 0) + else { - // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized, - // component sizes of the source and destination formats must exactly match - if (textureInternalFormatInfo.redBits != sourceEffectiveFormat.redBits || - textureInternalFormatInfo.greenBits != sourceEffectiveFormat.greenBits || - textureInternalFormatInfo.blueBits != sourceEffectiveFormat.blueBits || - textureInternalFormatInfo.alphaBits != sourceEffectiveFormat.alphaBits) - { - return false; - } + UNREACHABLE(); + return false; } + } - - return true; // A conversion function exists, and no rule in the specification has precluded conversion - // between these formats. + if (textureFormatInfo.sized) + { + // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is + // sized, component sizes of the source and destination formats must exactly match if the + // destination format exists. + if (!EqualOrFirstZero(textureFormatInfo.redBits, sourceEffectiveFormat->redBits) || + !EqualOrFirstZero(textureFormatInfo.greenBits, sourceEffectiveFormat->greenBits) || + !EqualOrFirstZero(textureFormatInfo.blueBits, sourceEffectiveFormat->blueBits) || + !EqualOrFirstZero(textureFormatInfo.alphaBits, sourceEffectiveFormat->alphaBits)) + { + return false; + } } - return false; + return true; // A conversion function exists, and no rule in the specification has precluded + // conversion between these formats. } bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, @@ -865,48 +790,50 @@ bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, GLsizei height, GLint border) { - GLenum textureInternalFormat; + Format textureFormat = Format::Invalid(); if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, zoffset, x, y, width, height, - border, &textureInternalFormat)) + xoffset, yoffset, zoffset, x, y, width, height, border, + &textureFormat)) { return false; } + ASSERT(textureFormat.valid() || !isSubImage); - const auto &state = context->getState(); - const gl::Framebuffer *framebuffer = state.getReadFramebuffer(); - GLuint readFramebufferID = framebuffer->id(); + const auto &state = context->getGLState(); + gl::Framebuffer *framebuffer = state.getReadFramebuffer(); + GLuint readFramebufferID = framebuffer->id(); - if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + context->handleError(InvalidFramebufferOperation()); return false; } - if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0) + if (readFramebufferID != 0 && framebuffer->getSamples(context) != 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } - const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); - GLenum colorbufferInternalFormat = source->getInternalFormat(); + const FramebufferAttachment *source = framebuffer->getReadColorbuffer(); if (isSubImage) { - if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, + if (!IsValidES3CopyTexImageCombination(*textureFormat.info, *source->getFormat().info, readFramebufferID)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } else { - if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, - readFramebufferID)) + // Use format/type from the source FBO. (Might not be perfect for all cases?) + const InternalFormat &framebufferFormat = *source->getFormat().info; + const InternalFormat ©Format = GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE); + if (!IsValidES3CopyTexImageCombination(copyFormat, framebufferFormat, readFramebufferID)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } @@ -931,7 +858,7 @@ bool ValidateES3CopyTexImage2DParameters(ValidationContext *context, { if (!ValidTexture2DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -956,7 +883,7 @@ bool ValidateES3CopyTexImage3DParameters(ValidationContext *context, { if (!ValidTexture3DDestinationTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -975,7 +902,7 @@ bool ValidateES3TexStorageParametersBase(Context *context, { if (width < 1 || height < 1 || depth < 1 || levels < 1) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } @@ -987,7 +914,7 @@ bool ValidateES3TexStorageParametersBase(Context *context, if (levels > gl::log2(maxDim) + 1) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } @@ -995,85 +922,102 @@ bool ValidateES3TexStorageParametersBase(Context *context, switch (target) { - case GL_TEXTURE_2D: + case GL_TEXTURE_2D: { if (static_cast(width) > caps.max2DTextureSize || static_cast(height) > caps.max2DTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); + return false; + } + } + break; + + case GL_TEXTURE_RECTANGLE_ANGLE: + { + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP: { if (width != height) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(width) > caps.maxCubeMapTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_3D: + case GL_TEXTURE_3D: { if (static_cast(width) > caps.max3DTextureSize || static_cast(height) > caps.max3DTextureSize || static_cast(depth) > caps.max3DTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_ARRAY: { if (static_cast(width) > caps.max2DTextureSize || static_cast(height) > caps.max2DTextureSize || static_cast(depth) > caps.maxArrayTextureLayers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - default: - UNREACHABLE(); - return false; + default: + UNREACHABLE(); + return false; } gl::Texture *texture = context->getTargetTexture(target); if (!texture || texture->id() == 0) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } if (texture->getImmutableFormat()) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); + return false; + } + + if (!formatInfo.sized) + { + context->handleError(InvalidEnum()); return false; } - if (formatInfo.pixelBytes == 0) + if (formatInfo.compressed && target == GL_TEXTURE_RECTANGLE_ANGLE) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); return false; } @@ -1090,7 +1034,7 @@ bool ValidateES3TexStorage2DParameters(Context *context, { if (!ValidTexture2DTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1108,7 +1052,7 @@ bool ValidateES3TexStorage3DParameters(Context *context, { if (!ValidTexture3DTarget(context, target)) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1116,33 +1060,11 @@ bool ValidateES3TexStorage3DParameters(Context *context, 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) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1151,9 +1073,9 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) bool ValidateEndQuery(gl::Context *context, GLenum target) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1162,38 +1084,36 @@ bool ValidateEndQuery(gl::Context *context, GLenum target) bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGetQueryivBase(context, target, pname); + return ValidateGetQueryivBase(context, target, pname, nullptr); } bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "GLES version < 3.0")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGetQueryObjectValueBase(context, id, pname); + return ValidateGetQueryObjectValueBase(context, id, pname, nullptr); } -bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) +bool ValidateFramebufferTextureLayer(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint layer) { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (layer < 0) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_VALUE)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1205,52 +1125,58 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att const gl::Caps &caps = context->getCaps(); if (texture != 0) { + if (layer < 0) + { + context->handleError(InvalidValue()); + return false; + } + gl::Texture *tex = context->getTexture(texture); ASSERT(tex); switch (tex->getTarget()) { - case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_ARRAY: { if (level > gl::log2(caps.max2DTextureSize)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(layer) >= caps.maxArrayTextureLayers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - case GL_TEXTURE_3D: + case GL_TEXTURE_3D: { if (level > gl::log2(caps.max3DTextureSize)) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } if (static_cast(layer) >= caps.max3DTextureSize) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } } break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + default: + context->handleError(InvalidOperation()); + return false; } - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level)); - if (internalFormatInfo.compressed) + const auto &format = tex->getFormat(tex->getTarget(), level); + if (format.info->compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return false; } } @@ -1258,161 +1184,114 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att return true; } -bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type) +bool ValidateInvalidateFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments) { - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + bool defaultFramebuffer = false; - switch (format) + switch (target) { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (internalFormat != GL_RGB10_A2) - { - return false; - } - break; - case GL_FLOAT: - if (internalFormatInfo.componentType != GL_FLOAT) - { - return false; - } - break; - default: - return false; - } - break; - case GL_RGBA_INTEGER: - switch (type) - { - case GL_INT: - if (internalFormatInfo.componentType != GL_INT) - { - return false; - } - break; - case GL_UNSIGNED_INT: - if (internalFormatInfo.componentType != GL_UNSIGNED_INT) - { - return false; - } - break; - default: - return false; - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + defaultFramebuffer = context->getGLState().getDrawFramebuffer()->id() == 0; break; - default: - return false; - } - break; - case GL_RG_EXT: - case GL_RED_EXT: - if (!context->getExtensions().textureRG) - { - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: + case GL_READ_FRAMEBUFFER: + defaultFramebuffer = context->getGLState().getReadFramebuffer()->id() == 0; break; default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); return false; - } - break; - default: - return false; } - return true; + + return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, + defaultFramebuffer); } -bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height) +bool ValidateInvalidateSubFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { - if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height)) - { - return false; - } + return ValidateInvalidateFramebuffer(context, target, numAttachments, attachments); +} - //The ES3 spec(section 4.4.2) states that the internal format must be sized and not an integer format if samples is greater than zero. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0) +bool ValidateClearBuffer(ValidationContext *context) +{ + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY. - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (static_cast(samples) > formatCaps.getMaxSamples()) + if (context->getGLState().getDrawFramebuffer()->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidFramebufferOperation()); return false; } return true; } -bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments, - const GLenum *attachments) +bool ValidateDrawRangeElements(Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Operation only supported on ES 3.0 and above")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - bool defaultFramebuffer = false; - - switch (target) + if (end < start) { - case GL_DRAW_FRAMEBUFFER: - case GL_FRAMEBUFFER: - defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0; - break; - case GL_READ_FRAMEBUFFER: - defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0; - break; - default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target")); + context->handleError(InvalidValue() << "end < start"); return false; } - return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); -} - -bool ValidateClearBuffer(ValidationContext *context) -{ - if (context->getClientVersion() < 3) + if (!ValidateDrawElementsCommon(context, mode, count, type, indices, 0)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); - if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + // Use the parameter buffer to retrieve and cache the index range. + const auto ¶ms = context->getParams(); + const auto &indexRangeOpt = params.getIndexRange(); + if (!indexRangeOpt.valid()) { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + // Unexpected error. return false; } + if (indexRangeOpt.value().end > end || indexRangeOpt.value().start < start) + { + // GL spec says that behavior in this case is undefined - generating an error is fine. + context->handleError(InvalidOperation() << "Indices are out of the start, end range."); + return false; + } return true; } -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params) +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint *params) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1421,17 +1300,17 @@ bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLu bool ValidateReadBuffer(Context *context, GLenum src) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - Framebuffer *readFBO = context->getState().getReadFramebuffer(); + const Framebuffer *readFBO = context->getGLState().getReadFramebuffer(); if (readFBO == nullptr) { - context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer.")); + context->handleError(InvalidOperation() << "No active read framebuffer."); return false; } @@ -1440,9 +1319,9 @@ bool ValidateReadBuffer(Context *context, GLenum src) return true; } - if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15)) + if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT31)) { - context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer")); + context->handleError(InvalidEnum() << "Unknown enum for 'src' in ReadBuffer"); return false; } @@ -1450,8 +1329,9 @@ bool ValidateReadBuffer(Context *context, GLenum src) { if (src != GL_BACK) { - const char *errorMsg = "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer."; - context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + context->handleError( + InvalidOperation() + << "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer."); return false; } } @@ -1461,8 +1341,7 @@ bool ValidateReadBuffer(Context *context, GLenum src) if (drawBuffer >= context->getCaps().maxDrawBuffers) { - const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS."; - context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + context->handleError(InvalidOperation() << "'src' is greater than MAX_DRAW_BUFFERS."); return false; } } @@ -1479,34 +1358,57 @@ bool ValidateCompressedTexImage3D(Context *context, GLsizei depth, GLint border, GLsizei imageSize, - const GLvoid *data) + const void *data) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidTextureTarget(context, target)) + { + context->handleError(InvalidEnum()); + return false; + } + + // Validate image size + if (!ValidImageSizeParameters(context, target, level, width, height, depth, false)) + { + context->handleError(InvalidValue()); + return false; + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalformat); + if (!formatInfo.compressed) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidEnum() << "Not a valid compressed texture format"); return false; } - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (imageSize < 0 || - static_cast(imageSize) != - formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, depth)); + if (blockSizeOrErr.isError()) + { + context->handleError(InvalidValue()); + return false; + } + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); 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")); + context->handleError(InvalidEnum() << "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)) + 0, width, height, depth, border, GL_NONE, GL_NONE, -1, + data)) { return false; } @@ -1514,59 +1416,207 @@ bool ValidateCompressedTexImage3D(Context *context, return true; } -bool ValidateBindVertexArray(Context *context, GLuint array) +bool ValidateCompressedTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data) { - if (context->getClientVersion() < 3) + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) { - context->recordError(Error(GL_INVALID_OPERATION)); return false; } - return ValidateBindVertexArrayBase(context, array); + return ValidateCompressedTexImage3D(context, target, level, internalformat, width, height, + depth, border, imageSize, data); } -bool ValidateDeleteVertexArrays(Context *context, GLsizei n) +bool ValidateBindVertexArray(Context *context, GLuint array) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateDeleteVertexArraysBase(context, n); + return ValidateBindVertexArrayBase(context, array); } -bool ValidateGenVertexArrays(Context *context, GLsizei n) +bool ValidateIsVertexArray(Context *context, GLuint array) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } - return ValidateGenVertexArraysBase(context, n); + return true; } -bool ValidateIsVertexArray(Context *context) +static bool ValidateBindBufferCommon(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (buffer != 0 && offset < 0) + { + context->handleError(InvalidValue() << "buffer is non-zero and offset is negative."); + return false; + } + + if (!context->getGLState().isBindGeneratesResourceEnabled() && + !context->isBufferGenerated(buffer)) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation() << "Buffer was not generated."); return false; } + const Caps &caps = context->getCaps(); + switch (target) + { + case BufferBinding::TransformFeedback: + { + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of TRANSFORM_FEEDBACK_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) + { + context->handleError(InvalidValue() << "offset and size must be multiple of 4."); + return false; + } + + TransformFeedback *curTransformFeedback = + context->getGLState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive()) + { + context->handleError(InvalidOperation() + << "target is TRANSFORM_FEEDBACK_BUFFER and transform " + "feedback is currently active."); + return false; + } + break; + } + case BufferBinding::Uniform: + { + if (index >= caps.maxUniformBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of UNIFORM_BUFFER indexed " + "binding points."); + return false; + } + + if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0) + { + context->handleError( + InvalidValue() + << "offset must be multiple of value of UNIFORM_BUFFER_OFFSET_ALIGNMENT."); + return false; + } + break; + } + case BufferBinding::AtomicCounter: + { + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "ATOMIC_COUNTER_BUFFER is not supported before GLES 3.1"); + return false; + } + if (index >= caps.maxAtomicCounterBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of ATOMIC_COUNTER_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && (offset % 4) != 0) + { + context->handleError(InvalidValue() << "offset must be a multiple of 4."); + return false; + } + break; + } + case BufferBinding::ShaderStorage: + { + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "SHADER_STORAGE_BUFFER is not supported in GLES3."); + return false; + } + if (index >= caps.maxShaderStorageBufferBindings) + { + context->handleError(InvalidValue() << "index is greater than or equal to the " + "number of SHADER_STORAGE_BUFFER " + "indexed binding points."); + return false; + } + if (buffer != 0 && (offset % caps.shaderStorageBufferOffsetAlignment) != 0) + { + context->handleError(InvalidValue() << "offset must be multiple of value of " + "SHADER_STORAGE_BUFFER_OFFSET_" + "ALIGNMENT."); + return false; + } + break; + } + default: + context->handleError(InvalidEnum() << "the target is not supported."); + return false; + } + return true; } +bool ValidateBindBufferBase(Context *context, BufferBinding target, GLuint index, GLuint buffer) +{ + return ValidateBindBufferCommon(context, target, index, buffer, 0, 0); +} + +bool ValidateBindBufferRange(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size) +{ + if (buffer != 0 && size <= 0) + { + context->handleError(InvalidValue() + << "buffer is non-zero and size is less than or equal to zero."); + return false; + } + return ValidateBindBufferCommon(context, target, index, buffer, offset, size); +} + bool ValidateProgramBinary(Context *context, GLuint program, GLenum binaryFormat, const void *binary, GLint length) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1580,20 +1630,20 @@ bool ValidateGetProgramBinary(Context *context, GLenum *binaryFormat, void *binary) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); } -bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value) +bool ValidateProgramParameteri(Context *context, GLuint program, GLenum pname, GLint value) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1605,10 +1655,33 @@ bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GL switch (pname) { case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: + if (value != GL_FALSE && value != GL_TRUE) + { + context->handleError(InvalidValue() + << "Invalid value, expected GL_FALSE or GL_TRUE: " << value); + return false; + } + break; + + case GL_PROGRAM_SEPARABLE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError(InvalidEnum() + << "PROGRAM_SEPARABLE is not supported before GLES 3.1"); + return false; + } + + if (value != GL_FALSE && value != GL_TRUE) + { + context->handleError(InvalidValue() + << "Invalid value, expected GL_FALSE or GL_TRUE: " << value); + return false; + } break; default: - context->recordError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname)); + context->handleError(InvalidEnum() + << "Invalid pname: 0x" << std::hex << std::uppercase << pname); return false; } @@ -1627,9 +1700,9 @@ bool ValidateBlitFramebuffer(Context *context, GLbitfield mask, GLenum filter) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1648,21 +1721,30 @@ bool ValidateClearBufferiv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_INT}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; case GL_STENCIL: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1680,13 +1762,22 @@ bool ValidateClearBufferuiv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_UNSIGNED_INT}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1704,21 +1795,31 @@ bool ValidateClearBufferfv(ValidationContext *context, if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } + if (context->getExtensions().webglCompatibility) + { + constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED, + GL_SIGNED_NORMALIZED}; + if (!ValidateWebGLFramebufferAttachmentClearType( + context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes))) + { + return false; + } + } break; case GL_DEPTH: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1736,13 +1837,13 @@ bool ValidateClearBufferfi(ValidationContext *context, case GL_DEPTH_STENCIL: if (drawbuffer != 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return false; } break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return false; } @@ -1751,9 +1852,9 @@ bool ValidateClearBufferfi(ValidationContext *context, bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.")); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1771,9 +1872,9 @@ bool ValidateCopyTexSubImage3D(Context *context, GLsizei width, GLsizei height) { - if (context->getClientVersion() < 3) + if (context->getClientMajorVersion() < 3) { - context->recordError(Error(GL_INVALID_OPERATION)); + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); return false; } @@ -1781,4 +1882,1821 @@ bool ValidateCopyTexSubImage3D(Context *context, yoffset, zoffset, x, y, width, height, 0); } +bool ValidateTexImage3D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, depth, border, format, type, -1, + pixels); +} + +bool ValidateTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, internalformat, false, false, 0, + 0, 0, width, height, depth, border, format, type, + bufSize, pixels); +} + +bool ValidateTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, type, + -1, pixels); +} + +bool ValidateTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, type, + bufSize, pixels); +} + +bool ValidateCompressedTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(format); + if (!formatInfo.compressed) + { + context->handleError(InvalidEnum() << "Not a valid compressed texture format"); + return false; + } + + auto blockSizeOrErr = formatInfo.computeCompressedImageSize(gl::Extents(width, height, depth)); + if (blockSizeOrErr.isError()) + { + context->handleError(blockSizeOrErr.getError()); + return false; + } + if (imageSize < 0 || static_cast(imageSize) != blockSizeOrErr.getResult()) + { + context->handleError(InvalidValue()); + return false; + } + + if (!data) + { + context->handleError(InvalidValue()); + return false; + } + + return ValidateES3TexImage3DParameters(context, target, level, GL_NONE, true, true, xoffset, + yoffset, zoffset, width, height, depth, 0, format, + GL_NONE, -1, data); +} +bool ValidateCompressedTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data) +{ + if (!ValidateRobustCompressedTexImageBase(context, imageSize, dataSize)) + { + return false; + } + + return ValidateCompressedTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, width, + height, depth, format, imageSize, data); +} + +bool ValidateGenQueries(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteQueries(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateGenSamplers(Context *context, GLint count, GLuint *) +{ + return ValidateGenOrDeleteCountES3(context, count); +} + +bool ValidateDeleteSamplers(Context *context, GLint count, const GLuint *) +{ + return ValidateGenOrDeleteCountES3(context, count); +} + +bool ValidateGenTransformFeedbacks(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteTransformFeedbacks(Context *context, GLint n, const GLuint *ids) +{ + if (!ValidateGenOrDeleteES3(context, n)) + { + return false; + } + for (GLint i = 0; i < n; ++i) + { + auto *transformFeedback = context->getTransformFeedback(ids[i]); + if (transformFeedback != nullptr && transformFeedback->isActive()) + { + // ES 3.0.4 section 2.15.1 page 86 + context->handleError(InvalidOperation() + << "Attempt to delete active transform feedback."); + return false; + } + } + return true; +} + +bool ValidateGenVertexArrays(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateDeleteVertexArrays(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES3(context, n); +} + +bool ValidateBeginTransformFeedback(Context *context, GLenum primitiveMode) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + switch (primitiveMode) + { + case GL_TRIANGLES: + case GL_LINES: + case GL_POINTS: + break; + + default: + context->handleError(InvalidEnum() << "Invalid primitive mode."); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + if (transformFeedback->isActive()) + { + context->handleError(InvalidOperation() << "Transform feedback is already active."); + return false; + } + + for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) + { + const auto &buffer = transformFeedback->getIndexedBuffer(i); + if (buffer.get() && buffer->isMapped()) + { + context->handleError(InvalidOperation() << "Transform feedback has a mapped buffer."); + return false; + } + } + + Program *program = context->getGLState().getProgram(); + + if (!program) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound); + return false; + } + + if (program->getTransformFeedbackVaryingCount() == 0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoTransformFeedbackOutputVariables); + return false; + } + + return true; +} + +bool ValidateGetBufferPointerv(Context *context, BufferBinding target, GLenum pname, void **params) +{ + return ValidateGetBufferPointervBase(context, target, pname, nullptr, params); +} + +bool ValidateGetBufferPointervRobustANGLE(Context *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params) +{ + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateGetBufferPointervBase(context, target, pname, length, params)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateUnmapBuffer(Context *context, BufferBinding target) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateUnmapBufferBase(context, target); +} + +bool ValidateMapBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateMapBufferRangeBase(context, target, offset, length, access); +} + +bool ValidateFlushMappedBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateFlushMappedBufferRangeBase(context, target, offset, length); +} + +bool ValidateIndexedStateQuery(ValidationContext *context, + GLenum pname, + GLuint index, + GLsizei *length) +{ + if (length) + { + *length = 0; + } + + GLenum nativeType; + unsigned int numParams; + if (!context->getIndexedQueryParameterInfo(pname, &nativeType, &numParams)) + { + context->handleError(InvalidEnum()); + return false; + } + + const Caps &caps = context->getCaps(); + switch (pname) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= caps.maxUniformBufferBindings) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_MAX_COMPUTE_WORK_GROUP_SIZE: + case GL_MAX_COMPUTE_WORK_GROUP_COUNT: + if (index >= 3u) + { + context->handleError(InvalidValue()); + return false; + } + break; + + case GL_ATOMIC_COUNTER_BUFFER_START: + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Atomic Counter buffers are not supported in this version of GL"); + return false; + } + if (index >= caps.maxAtomicCounterBufferBindings) + { + context->handleError( + InvalidValue() + << "index is outside the valid range for GL_ATOMIC_COUNTER_BUFFER_BINDING"); + return false; + } + break; + + case GL_SHADER_STORAGE_BUFFER_START: + case GL_SHADER_STORAGE_BUFFER_SIZE: + case GL_SHADER_STORAGE_BUFFER_BINDING: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Shader storage buffers are not supported in this version of GL"); + return false; + } + if (index >= caps.maxShaderStorageBufferBindings) + { + context->handleError( + InvalidValue() + << "index is outside the valid range for GL_SHADER_STORAGE_BUFFER_BINDING"); + return false; + } + break; + + case GL_VERTEX_BINDING_BUFFER: + case GL_VERTEX_BINDING_DIVISOR: + case GL_VERTEX_BINDING_OFFSET: + case GL_VERTEX_BINDING_STRIDE: + if (context->getClientVersion() < ES_3_1) + { + context->handleError( + InvalidEnum() + << "Vertex Attrib Bindings are not supported in this version of GL"); + return false; + } + if (index >= caps.maxVertexAttribBindings) + { + context->handleError( + InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + break; + case GL_SAMPLE_MASK_VALUE: + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), EnumRequiresGLES31); + return false; + } + if (index >= caps.maxSampleMaskWords) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidSampleMaskNumber); + return false; + } + break; + default: + context->handleError(InvalidEnum()); + return false; + } + + if (length) + { + *length = 1; + } + + return true; +} + +bool ValidateGetIntegeri_v(ValidationContext *context, GLenum target, GLuint index, GLint *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateIndexedStateQuery(context, target, index, nullptr); +} + +bool ValidateGetIntegeri_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateGetInteger64i_v(ValidationContext *context, GLenum target, GLuint index, GLint64 *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + return ValidateIndexedStateQuery(context, target, index, nullptr); +} + +bool ValidateGetInteger64i_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data) +{ + if (context->getClientVersion() < ES_3_0) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateCopyBufferSubData(ValidationContext *context, + BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidBufferType(context, readTarget) || !ValidBufferType(context, writeTarget)) + { + context->handleError(InvalidEnum() << "Invalid buffer target"); + return false; + } + + Buffer *readBuffer = context->getGLState().getTargetBuffer(readTarget); + Buffer *writeBuffer = context->getGLState().getTargetBuffer(writeTarget); + + if (!readBuffer || !writeBuffer) + { + context->handleError(InvalidOperation() << "No buffer bound to target"); + return false; + } + + // Verify that readBuffer and writeBuffer are not currently mapped + if (readBuffer->isMapped() || writeBuffer->isMapped()) + { + context->handleError(InvalidOperation() + << "Cannot call CopyBufferSubData on a mapped buffer"); + return false; + } + + CheckedNumeric checkedReadOffset(readOffset); + CheckedNumeric checkedWriteOffset(writeOffset); + CheckedNumeric checkedSize(size); + + auto checkedReadSum = checkedReadOffset + checkedSize; + auto checkedWriteSum = checkedWriteOffset + checkedSize; + + if (!checkedReadSum.IsValid() || !checkedWriteSum.IsValid() || + !IsValueInRangeForNumericType(readBuffer->getSize()) || + !IsValueInRangeForNumericType(writeBuffer->getSize())) + { + context->handleError(InvalidValue() << "Integer overflow when validating copy offsets."); + return false; + } + + if (readOffset < 0 || writeOffset < 0 || size < 0) + { + context->handleError(InvalidValue() + << "readOffset, writeOffset and size must all be non-negative"); + return false; + } + + if (checkedReadSum.ValueOrDie() > readBuffer->getSize() || + checkedWriteSum.ValueOrDie() > writeBuffer->getSize()) + { + context->handleError(InvalidValue() << "Buffer offset overflow in CopyBufferSubData"); + return false; + } + + if (readBuffer == writeBuffer) + { + auto checkedOffsetDiff = (checkedReadOffset - checkedWriteOffset).Abs(); + if (!checkedOffsetDiff.IsValid()) + { + // This shold not be possible. + UNREACHABLE(); + context->handleError(InvalidValue() + << "Integer overflow when validating same buffer copy."); + return false; + } + + if (checkedOffsetDiff.ValueOrDie() < size) + { + context->handleError(InvalidValue()); + return false; + } + } + + return true; +} + +bool ValidateGetStringi(Context *context, GLenum name, GLuint index) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + switch (name) + { + case GL_EXTENSIONS: + if (index >= context->getExtensionStringCount()) + { + context->handleError(InvalidValue() + << "index must be less than the number of extension strings."); + return false; + } + break; + + case GL_REQUESTABLE_EXTENSIONS_ANGLE: + if (!context->getExtensions().requestExtension) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); + return false; + } + if (index >= context->getRequestableExtensionStringCount()) + { + context->handleError( + InvalidValue() + << "index must be less than the number of requestable extension strings."); + return false; + } + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidName); + return false; + } + + return true; +} + +bool ValidateRenderbufferStorageMultisample(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, + height)) + { + return false; + } + + // The ES3 spec(section 4.4.2) states that the internal format must be sized and not an integer + // format if samples is greater than zero. + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalformat); + if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && + samples > 0) + { + context->handleError(InvalidOperation()); + return false; + } + + // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY. + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->handleError( + InvalidOperation() + << "Samples must not be greater than maximum supported value for the format."); + return false; + } + + return true; +} + +bool ValidateVertexAttribIPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateVertexFormatBase(context, index, size, type, true)) + { + return false; + } + + if (stride < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeStride); + return false; + } + + const Caps &caps = context->getCaps(); + if (context->getClientVersion() >= ES_3_1) + { + if (stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride cannot be greater than MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 245: + // glVertexAttribBinding is part of the equivalent code of VertexAttribIPointer, so its + // validation should be inherited. + if (index >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "index must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + } + + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getGLState().getVertexArrayId() != 0 && + context->getGLState().getTargetBuffer(BufferBinding::Array) == 0 && pointer != nullptr) + { + context + ->handleError(InvalidOperation() + << "Client data cannot be used with a non-default vertex array object."); + return false; + } + + if (context->getExtensions().webglCompatibility) + { + if (!ValidateWebGLVertexAttribPointer(context, type, false, stride, pointer, true)) + { + return false; + } + } + + return true; +} + +bool ValidateGetSynciv(Context *context, + GLsync sync, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *values) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Sync *syncObject = context->getSync(sync); + if (!syncObject) + { + context->handleError(InvalidValue() << "Invalid sync object."); + return false; + } + + switch (pname) + { + case GL_OBJECT_TYPE: + case GL_SYNC_CONDITION: + case GL_SYNC_FLAGS: + case GL_SYNC_STATUS: + break; + + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + return true; +} + +bool ValidateDrawElementsInstanced(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instanceCount) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateDrawElementsInstancedCommon(context, mode, count, type, indices, instanceCount); +} + +bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + + if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level, + numViews)) + { + return false; + } + + if (texture != 0) + { + if (baseViewIndex < 0) + { + context->handleError(InvalidValue() << "baseViewIndex cannot be less than 0."); + return false; + } + + Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D_ARRAY: + { + const Caps &caps = context->getCaps(); + if (static_cast(baseViewIndex + numViews) > caps.maxArrayTextureLayers) + { + context->handleError(InvalidValue() << "baseViewIndex+numViews cannot be " + "greater than " + "GL_MAX_ARRAY_TEXTURE_LAYERS."); + return false; + } + } + break; + default: + context->handleError(InvalidOperation() + << "Texture's target must be GL_TEXTURE_2D_ARRAY."); + return false; + } + + if (!ValidateFramebufferTextureMultiviewLevelAndFormat(context, tex, level)) + { + return false; + } + } + + return true; +} + +bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level, + numViews)) + { + return false; + } + + if (texture != 0) + { + const GLsizei numViewportOffsetValues = numViews * 2; + for (GLsizei i = 0; i < numViewportOffsetValues; ++i) + { + if (viewportOffsets[i] < 0) + { + context->handleError(InvalidValue() + << "viewportOffsets cannot contain negative values."); + return false; + } + } + + Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D: + break; + default: + context->handleError(InvalidOperation() + << "Texture's target must be GL_TEXTURE_2D."); + return false; + } + + if (!ValidateFramebufferTextureMultiviewLevelAndFormat(context, tex, level)) + { + return false; + } + } + + return true; +} + +bool ValidateUniform1ui(Context *context, GLint location, GLuint v0) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT, location, 1); +} + +bool ValidateUniform2ui(Context *context, GLint location, GLuint v0, GLuint v1) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC2, location, 1); +} + +bool ValidateUniform3ui(Context *context, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC3, location, 1); +} + +bool ValidateUniform4ui(Context *context, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC4, location, 1); +} + +bool ValidateUniform1uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT, location, count); +} + +bool ValidateUniform2uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC2, location, count); +} + +bool ValidateUniform3uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC3, location, count); +} + +bool ValidateUniform4uiv(Context *context, GLint location, GLsizei count, const GLuint *value) +{ + return ValidateUniformES3(context, GL_UNSIGNED_INT_VEC4, location, count); +} + +bool ValidateIsQuery(Context *context, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateUniformMatrix2x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT2x3, location, count, transpose); +} + +bool ValidateUniformMatrix3x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT3x2, location, count, transpose); +} + +bool ValidateUniformMatrix2x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT2x4, location, count, transpose); +} + +bool ValidateUniformMatrix4x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT4x2, location, count, transpose); +} + +bool ValidateUniformMatrix3x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT3x4, location, count, transpose); +} + +bool ValidateUniformMatrix4x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateUniformMatrixES3(context, GL_FLOAT_MAT4x3, location, count, transpose); +} + +bool ValidateEndTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + if (!transformFeedback->isActive()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateTransformFeedbackVaryings(Context *context, + GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (count < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeCount); + return false; + } + + switch (bufferMode) + { + case GL_INTERLEAVED_ATTRIBS: + break; + case GL_SEPARATE_ATTRIBS: + { + const Caps &caps = context->getCaps(); + if (static_cast(count) > caps.maxTransformFeedbackSeparateAttributes) + { + context->handleError(InvalidValue()); + return false; + } + break; + } + default: + context->handleError(InvalidEnum()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetTransformFeedbackVarying(Context *context, + GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (index >= static_cast(programObject->getTransformFeedbackVaryingCount())) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateBindTransformFeedback(Context *context, GLenum target, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK: + { + // 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->getGLState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section + // 2.14.1) + if (!context->isTransformFeedbackGenerated(id)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), TransformFeedbackDoesNotExist); + return false; + } + } + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + return true; +} + +bool ValidateIsTransformFeedback(Context *context, GLuint id) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidatePauseTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + // Current transform feedback must be active and not paused in order to pause (3.0.2 pg 86) + if (!transformFeedback->isActive() || transformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateResumeTransformFeedback(Context *context) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + TransformFeedback *transformFeedback = context->getGLState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != nullptr); + + // Current transform feedback must be active and paused in order to resume (3.0.2 pg 86) + if (!transformFeedback->isActive() || !transformFeedback->isPaused()) + { + context->handleError(InvalidOperation()); + return false; + } + + return true; +} + +bool ValidateVertexAttribI4i(Context *context, GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4ui(Context *context, + GLuint index, + GLuint x, + GLuint y, + GLuint z, + GLuint w) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4iv(Context *context, GLuint index, const GLint *v) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateVertexAttribI4uiv(Context *context, GLuint index, const GLuint *v) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateGetFragDataLocation(Context *context, GLuint program, const GLchar *name) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (!programObject->isLinked()) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotLinked); + return false; + } + + return true; +} + +bool ValidateGetUniformIndices(Context *context, + GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformCount < 0) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetActiveUniformsiv(Context *context, + GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformCount < 0) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + switch (pname) + { + case GL_UNIFORM_TYPE: + case GL_UNIFORM_SIZE: + case GL_UNIFORM_NAME_LENGTH: + case GL_UNIFORM_BLOCK_INDEX: + case GL_UNIFORM_OFFSET: + case GL_UNIFORM_ARRAY_STRIDE: + case GL_UNIFORM_MATRIX_STRIDE: + case GL_UNIFORM_IS_ROW_MAJOR: + break; + + default: + context->handleError(InvalidEnum()); + return false; + } + + if (uniformCount > programObject->getActiveUniformCount()) + { + context->handleError(InvalidValue()); + return false; + } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + + if (index >= static_cast(programObject->getActiveUniformCount())) + { + context->handleError(InvalidValue()); + return false; + } + } + + return true; +} + +bool ValidateGetUniformBlockIndex(Context *context, GLuint program, const GLchar *uniformBlockName) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + return true; +} + +bool ValidateGetActiveUniformBlockiv(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr); +} + +bool ValidateGetActiveUniformBlockName(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateUniformBlockBinding(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings) + { + context->handleError(InvalidValue()); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + + // if never linked, there won't be any uniform blocks + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateDrawArraysInstanced(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateDrawArraysInstancedBase(context, mode, first, count, primcount); +} + +bool ValidateFenceSync(Context *context, GLenum condition, GLbitfield flags) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) + { + context->handleError(InvalidEnum()); + return false; + } + + if (flags != 0) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateIsSync(Context *context, GLsync sync) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateDeleteSync(Context *context, GLsync sync) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (sync != static_cast(0) && !context->getSync(sync)) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateClientWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) + { + context->handleError(InvalidValue()); + return false; + } + + Sync *clientWaitSync = context->getSync(sync); + if (!clientWaitSync) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (flags != 0) + { + context->handleError(InvalidValue()); + return false; + } + + if (timeout != GL_TIMEOUT_IGNORED) + { + context->handleError(InvalidValue()); + return false; + } + + Sync *waitSync = context->getSync(sync); + if (!waitSync) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateGetInteger64v(Context *context, GLenum pname, GLint64 *params) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + GLenum nativeType = GL_NONE; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return false; + } + + return true; +} + +bool ValidateIsSampler(Context *context, GLuint sampler) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return true; +} + +bool ValidateBindSampler(Context *context, GLuint unit, GLuint sampler) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (sampler != 0 && !context->isSampler(sampler)) + { + context->handleError(InvalidOperation()); + return false; + } + + if (unit >= context->getCaps().maxCombinedTextureImageUnits) + { + context->handleError(InvalidValue()); + return false; + } + + return true; +} + +bool ValidateVertexAttribDivisor(Context *context, GLuint index, GLuint divisor) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + return ValidateVertexAttribIndex(context, index); +} + +bool ValidateTexStorage2D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width, height, + 1)) + { + return false; + } + + return true; +} + +bool ValidateTexStorage3D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth) +{ + if (context->getClientMajorVersion() < 3) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES3Required); + return false; + } + + if (!ValidateES3TexStorage3DParameters(context, target, levels, internalformat, width, height, + depth)) + { + return false; + } + + return true; +} + +bool ValidateGetBufferParameteri64v(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint64 *params) +{ + return ValidateGetBufferParameterBase(context, target, pname, false, nullptr); +} + +bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params) +{ + return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr); +} + +bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params) +{ + return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr); +} + +bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, ¶m); +} + +bool ValidateSamplerParameterfv(Context *context, + GLuint sampler, + GLenum pname, + const GLfloat *params) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, params); +} + +bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, ¶m); +} + +bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params) +{ + return ValidateSamplerParameterBase(context, sampler, pname, -1, params); +} + +bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true); +} + +bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params) +{ + return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true); +} + +bool ValidateGetInternalformativ(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) +{ + return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, + nullptr); +} + } // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.h b/src/3rdparty/angle/src/libANGLE/validationES3.h index 7bc657790a..631b1ca43a 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES3.h +++ b/src/3rdparty/angle/src/libANGLE/validationES3.h @@ -9,11 +9,14 @@ #ifndef LIBANGLE_VALIDATION_ES3_H_ #define LIBANGLE_VALIDATION_ES3_H_ +#include "libANGLE/PackedGLEnums.h" + #include namespace gl { class Context; +struct IndexRange; class ValidationContext; bool ValidateES3TexImageParametersBase(ValidationContext *context, @@ -31,7 +34,8 @@ bool ValidateES3TexImageParametersBase(ValidationContext *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei imageSize, + const void *pixels); bool ValidateES3TexStorageParameters(Context *context, GLenum target, @@ -56,7 +60,8 @@ bool ValidateES3TexImage2DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei imageSize, + const void *pixels); bool ValidateES3TexImage3DParameters(Context *context, GLenum target, @@ -73,7 +78,8 @@ bool ValidateES3TexImage3DParameters(Context *context, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); + GLsizei bufSize, + const void *pixels); bool ValidateES3CopyTexImageParametersBase(ValidationContext *context, GLenum target, @@ -141,10 +147,6 @@ bool ValidateES3TexStorage3DParameters(Context *context, 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); @@ -153,20 +155,38 @@ bool ValidateGetQueryiv(Context *context, GLenum target, GLenum pname, GLint *pa bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint *params); -bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer); - -bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type); - -bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); +bool ValidateFramebufferTextureLayer(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint layer); -bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments, +bool ValidateInvalidateFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, const GLenum *attachments); +bool ValidateInvalidateSubFramebuffer(Context *context, + GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height); + bool ValidateClearBuffer(ValidationContext *context); -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); +bool ValidateDrawRangeElements(Context *context, + GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices); + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint *params); bool ValidateReadBuffer(Context *context, GLenum mode); @@ -179,12 +199,29 @@ bool ValidateCompressedTexImage3D(Context *context, GLsizei depth, GLint border, GLsizei imageSize, - const GLvoid *data); + const void *data); +bool ValidateCompressedTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const void *data); bool ValidateBindVertexArray(Context *context, GLuint array); -bool ValidateDeleteVertexArrays(Context *context, GLsizei n); -bool ValidateGenVertexArrays(Context *context, GLsizei n); -bool ValidateIsVertexArray(Context *context); +bool ValidateIsVertexArray(Context *context, GLuint array); + +bool ValidateBindBufferBase(Context *context, BufferBinding target, GLuint index, GLuint buffer); +bool ValidateBindBufferRange(Context *context, + BufferBinding target, + GLuint index, + GLuint buffer, + GLintptr offset, + GLsizeiptr size); bool ValidateProgramBinary(Context *context, GLuint program, @@ -197,7 +234,7 @@ bool ValidateGetProgramBinary(Context *context, GLsizei *length, GLenum *binaryFormat, void *binary); -bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value); +bool ValidateProgramParameteri(Context *context, GLuint program, GLenum pname, GLint value); bool ValidateBlitFramebuffer(Context *context, GLint srcX0, GLint srcY0, @@ -237,7 +274,341 @@ bool ValidateCopyTexSubImage3D(Context *context, GLint y, GLsizei width, GLsizei height); +bool ValidateTexImage3D(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels); +bool ValidateTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +bool ValidateCompressedTexSubImage3D(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data); +bool ValidateCompressedTexSubImage3DRobustANGLE(Context *context, + GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const void *data); + +bool ValidateGenQueries(Context *context, GLint n, GLuint *ids); +bool ValidateDeleteQueries(Context *context, GLint n, const GLuint *ids); +bool ValidateGenSamplers(Context *context, GLint count, GLuint *samplers); +bool ValidateDeleteSamplers(Context *context, GLint count, const GLuint *samplers); +bool ValidateGenTransformFeedbacks(Context *context, GLint n, GLuint *ids); +bool ValidateDeleteTransformFeedbacks(Context *context, GLint n, const GLuint *ids); +bool ValidateGenVertexArrays(Context *context, GLint n, GLuint *arrays); +bool ValidateDeleteVertexArrays(Context *context, GLint n, const GLuint *arrays); + +bool ValidateBeginTransformFeedback(Context *context, GLenum primitiveMode); + +bool ValidateGetBufferPointerv(Context *context, BufferBinding target, GLenum pname, void **params); +bool ValidateGetBufferPointervRobustANGLE(Context *context, + BufferBinding target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params); +bool ValidateUnmapBuffer(Context *context, BufferBinding target); +bool ValidateMapBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +bool ValidateFlushMappedBufferRange(Context *context, + BufferBinding target, + GLintptr offset, + GLsizeiptr length); + +bool ValidateIndexedStateQuery(ValidationContext *context, + GLenum pname, + GLuint index, + GLsizei *length); +bool ValidateGetIntegeri_v(ValidationContext *context, GLenum target, GLuint index, GLint *data); +bool ValidateGetIntegeri_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *data); +bool ValidateGetInteger64i_v(ValidationContext *context, + GLenum target, + GLuint index, + GLint64 *data); +bool ValidateGetInteger64i_vRobustANGLE(ValidationContext *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data); + +bool ValidateCopyBufferSubData(ValidationContext *context, + BufferBinding readTarget, + BufferBinding writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size); + +bool ValidateGetStringi(Context *context, GLenum name, GLuint index); +bool ValidateRenderbufferStorageMultisample(ValidationContext *context, + GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); + +bool ValidateVertexAttribIPointer(ValidationContext *context, + GLuint index, + GLint size, + GLenum type, + GLsizei stride, + const void *pointer); + +bool ValidateGetSynciv(Context *context, + GLsync sync, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *values); + +bool ValidateDrawElementsInstanced(ValidationContext *context, + GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instanceCount); + +bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews); + +bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets); + +bool ValidateIsQuery(Context *context, GLuint id); + +bool ValidateUniform1ui(Context *context, GLint location, GLuint v0); +bool ValidateUniform2ui(Context *context, GLint location, GLuint v0, GLuint v1); +bool ValidateUniform3ui(Context *context, GLint location, GLuint v0, GLuint v1, GLuint v2); +bool ValidateUniform4ui(Context *context, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); + +bool ValidateUniform1uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform2uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform3uiv(Context *context, GLint location, GLsizei count, const GLuint *value); +bool ValidateUniform4uiv(Context *context, GLint location, GLsizei count, const GLuint *value); + +bool ValidateUniformMatrix2x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix2x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4x2fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix3x4fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateUniformMatrix4x3fv(Context *context, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +bool ValidateEndTransformFeedback(Context *context); +bool ValidateTransformFeedbackVaryings(Context *context, + GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode); +bool ValidateGetTransformFeedbackVarying(Context *context, + GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name); +bool ValidateBindTransformFeedback(Context *context, GLenum target, GLuint id); +bool ValidateIsTransformFeedback(Context *context, GLuint id); +bool ValidatePauseTransformFeedback(Context *context); +bool ValidateResumeTransformFeedback(Context *context); +bool ValidateVertexAttribI4i(Context *context, GLuint index, GLint x, GLint y, GLint z, GLint w); +bool ValidateVertexAttribI4ui(Context *context, + GLuint index, + GLuint x, + GLuint y, + GLuint z, + GLuint w); +bool ValidateVertexAttribI4iv(Context *context, GLuint index, const GLint *v); +bool ValidateVertexAttribI4uiv(Context *context, GLuint index, const GLuint *v); +bool ValidateGetFragDataLocation(Context *context, GLuint program, const GLchar *name); +bool ValidateGetUniformIndices(Context *context, + GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices); +bool ValidateGetActiveUniformsiv(Context *context, + GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params); +bool ValidateGetUniformBlockIndex(Context *context, GLuint program, const GLchar *uniformBlockName); +bool ValidateGetActiveUniformBlockiv(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); +bool ValidateGetActiveUniformBlockName(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName); +bool ValidateUniformBlockBinding(Context *context, + GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding); +bool ValidateDrawArraysInstanced(Context *context, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); + +bool ValidateFenceSync(Context *context, GLenum condition, GLbitfield flags); +bool ValidateIsSync(Context *context, GLsync sync); +bool ValidateDeleteSync(Context *context, GLsync sync); +bool ValidateClientWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout); +bool ValidateWaitSync(Context *context, GLsync sync, GLbitfield flags, GLuint64 timeout); +bool ValidateGetInteger64v(Context *context, GLenum pname, GLint64 *params); + +bool ValidateIsSampler(Context *context, GLuint sampler); +bool ValidateBindSampler(Context *context, GLuint unit, GLuint sampler); +bool ValidateVertexAttribDivisor(Context *context, GLuint index, GLuint divisor); +bool ValidateTexStorage2D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height); +bool ValidateTexStorage3D(Context *context, + GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth); + +bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params); +bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params); +bool ValidateGetBufferParameteri64v(ValidationContext *context, + BufferBinding target, + GLenum pname, + GLint64 *params); +bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param); +bool ValidateSamplerParameteriv(Context *context, + GLuint sampler, + GLenum pname, + const GLint *params); +bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param); +bool ValidateSamplerParameterfv(Context *context, + GLuint sampler, + GLenum pname, + const GLfloat *params); +bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params); +bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params); +bool ValidateGetInternalformativ(Context *context, + GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params); } // namespace gl -#endif // LIBANGLE_VALIDATION_ES3_H_ +#endif // LIBANGLE_VALIDATION_ES3_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES31.cpp b/src/3rdparty/angle/src/libANGLE/validationES31.cpp new file mode 100644 index 0000000000..b1bdccacf7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES31.cpp @@ -0,0 +1,1786 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES31.cpp: Validation functions for OpenGL ES 3.1 entry point parameters + +#include "libANGLE/validationES31.h" + +#include "libANGLE/Context.h" +#include "libANGLE/ErrorStrings.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" + +#include "common/utilities.h" + +using namespace angle; + +namespace gl +{ + +namespace +{ + +bool ValidateNamedProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_BUFFER_VARIABLE: + case GL_SHADER_STORAGE_BLOCK: + return true; + default: + return false; + } +} + +bool ValidateLocationProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + return true; + default: + return false; + } +} + +bool ValidateProgramInterface(GLenum programInterface) +{ + return (programInterface == GL_ATOMIC_COUNTER_BUFFER || + ValidateNamedProgramInterface(programInterface)); +} + +bool ValidateProgramResourceProperty(GLenum prop) +{ + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + + case GL_ARRAY_SIZE: + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + + case GL_BUFFER_DATA_SIZE: + + case GL_LOCATION: + + case GL_NAME_LENGTH: + + case GL_OFFSET: + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + + case GL_TYPE: + return true; + + default: + return false; + } +} + +// GLES 3.10 spec: Page 82 -- Table 7.2 +bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface) +{ + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_ARRAY_SIZE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + { + if (programInterface == GL_UNIFORM) + { + return true; + } + return false; + } + + case GL_BUFFER_DATA_SIZE: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_LOCATION: + { + return ValidateLocationProgramInterface(programInterface); + } + + case GL_NAME_LENGTH: + { + return ValidateNamedProgramInterface(programInterface); + } + + case GL_OFFSET: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + { + if (programInterface == GL_BUFFER_VARIABLE) + { + return true; + } + return false; + } + + case GL_TYPE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + default: + return false; + } +} + +bool ValidateProgramResourceIndex(const Program *programObject, + GLenum programInterface, + GLuint index) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return (index < static_cast(programObject->getActiveAttributeCount())); + + case GL_PROGRAM_OUTPUT: + return (index < static_cast(programObject->getOutputResourceCount())); + + case GL_UNIFORM: + return (index < static_cast(programObject->getActiveUniformCount())); + + case GL_BUFFER_VARIABLE: + return (index < static_cast(programObject->getActiveBufferVariableCount())); + + case GL_SHADER_STORAGE_BLOCK: + return (index < static_cast(programObject->getActiveShaderStorageBlockCount())); + + case GL_UNIFORM_BLOCK: + return (index < programObject->getActiveUniformBlockCount()); + + case GL_ATOMIC_COUNTER_BUFFER: + return (index < programObject->getActiveAtomicCounterBufferCount()); + + // TODO(jie.a.chen@intel.com): more interfaces. + case GL_TRANSFORM_FEEDBACK_VARYING: + UNIMPLEMENTED(); + return false; + + default: + UNREACHABLE(); + return false; + } +} + +bool ValidateProgramUniform(gl::Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformValue(context, valueType, uniform->type); +} + +bool ValidateProgramUniformMatrix(gl::Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformMatrixValue(context, valueType, uniform->type); +} + +bool ValidateVertexAttribFormatCommon(ValidationContext *context, + GLuint attribIndex, + GLint size, + GLenum type, + GLuint relativeOffset, + GLboolean pureInteger) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (relativeOffset > static_cast(caps.maxVertexAttribRelativeOffset)) + { + context->handleError( + InvalidValue() + << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger); +} + +} // anonymous namespace + +bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, nullptr)) + { + return false; + } + + return true; +} + +bool ValidateGetBooleani_vRobustANGLE(Context *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, length)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, *length)) + { + return false; + } + + return true; +} + +bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + // Here the third parameter 1 is only to pass the count validation. + if (!ValidateDrawBase(context, mode, 1)) + { + return false; + } + + const State &state = context->getGLState(); + + // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING, + // DRAW_INDIRECT_BUFFER or to any enabled vertex array. + if (!state.getVertexArrayId()) + { + context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING"); + return false; + } + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + if (!drawIndirectBuffer) + { + context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER"); + return false; + } + + // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic + // machine units, of uint. + GLint64 offset = reinterpret_cast(indirect); + if ((static_cast(offset) % sizeof(GLuint)) != 0) + { + context->handleError( + InvalidValue() + << "indirect is not a multiple of the size, in basic machine units, of uint"); + return false; + } + + // ANGLE_multiview spec, revision 1: + // An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the + // number of views in the draw framebuffer is greater than 1. + const Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer(); + ASSERT(drawFramebuffer != nullptr); + if (drawFramebuffer->getNumViews() > 1) + { + context->handleError( + InvalidOperation() + << "The number of views in the active draw framebuffer is greater than 1."); + return false; + } + + return true; +} + +bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect) +{ + const State &state = context->getGLState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused()) + { + // An INVALID_OPERATION error is generated if transform feedback is active and not paused. + context->handleError(InvalidOperation() << "transform feedback is active and not paused."); + return false; + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric checkedOffset(reinterpret_cast(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand + // which's size is 4 * sizeof(uint). + auto checkedSum = checkedOffset + 4 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast(drawIndirectBuffer->getSize())) + { + context->handleError( + InvalidOperation() + << "the command would source data beyond the end of the buffer object."); + return false; + } + + return true; +} + +bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect) +{ + if (!ValidateDrawElementsBase(context, type)) + return false; + + const State &state = context->getGLState(); + const VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); + if (!elementArrayBuffer) + { + context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER"); + return false; + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + gl::Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric checkedOffset(reinterpret_cast(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand + // which's size is 5 * sizeof(uint). + auto checkedSum = checkedOffset + 5 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast(drawIndirectBuffer->getSize())) + { + context->handleError( + InvalidOperation() + << "the command would source data beyond the end of the buffer object."); + return false; + } + + return true; +} + +bool ValidateProgramUniform1i(Context *context, GLuint program, GLint location, GLint v0) +{ + return ValidateProgramUniform1iv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2i(Context *context, GLuint program, GLint location, GLint v0, GLint v1) +{ + GLint xy[2] = {v0, v1}; + return ValidateProgramUniform2iv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2) +{ + GLint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3iv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3) +{ + GLint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4iv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1ui(Context *context, GLuint program, GLint location, GLuint v0) +{ + return ValidateProgramUniform1uiv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1) +{ + GLuint xy[2] = {v0, v1}; + return ValidateProgramUniform2uiv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2) +{ + GLuint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3uiv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + GLuint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4uiv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1f(Context *context, GLuint program, GLint location, GLfloat v0) +{ + return ValidateProgramUniform1fv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1) +{ + GLfloat xy[2] = {v0, v1}; + return ValidateProgramUniform2fv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2) +{ + GLfloat xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3fv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3) +{ + GLfloat xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4fv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + gl::Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniform1ivValue(context, uniform->type, count, value); +} + +bool ValidateProgramUniform2iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT, program, location, count); +} + +bool ValidateProgramUniform2uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT, program, location, count); +} + +bool ValidateProgramUniform2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC4, program, location, count); +} + +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x3, program, location, count, + transpose); +} + +bool ValidateGetTexLevelParameterBase(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLsizei *length) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (length) + { + *length = 0; + } + + if (!ValidTexLevelDestinationTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget); + return false; + } + + if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) == + nullptr) + { + context->handleError(InvalidEnum() << "No texture bound."); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + context->handleError(InvalidValue()); + return false; + } + + switch (pname) + { + case GL_TEXTURE_RED_TYPE: + case GL_TEXTURE_GREEN_TYPE: + case GL_TEXTURE_BLUE_TYPE: + case GL_TEXTURE_ALPHA_TYPE: + case GL_TEXTURE_DEPTH_TYPE: + break; + case GL_TEXTURE_RED_SIZE: + case GL_TEXTURE_GREEN_SIZE: + case GL_TEXTURE_BLUE_SIZE: + case GL_TEXTURE_ALPHA_SIZE: + case GL_TEXTURE_DEPTH_SIZE: + case GL_TEXTURE_STENCIL_SIZE: + case GL_TEXTURE_SHARED_SIZE: + break; + case GL_TEXTURE_INTERNAL_FORMAT: + case GL_TEXTURE_WIDTH: + case GL_TEXTURE_HEIGHT: + case GL_TEXTURE_DEPTH: + break; + case GL_TEXTURE_SAMPLES: + case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: + break; + case GL_TEXTURE_COMPRESSED: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + if (length) + { + *length = 1; + } + return true; +} + +bool ValidateGetTexLevelParameterfv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params) +{ + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateGetTexLevelParameteriv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLint *params) +{ + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateTexStorage2DMultisample(Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (target != GL_TEXTURE_2D_MULTISAMPLE) + { + context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE."); + return false; + } + + if (width < 1 || height < 1) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize); + return false; + } + + const Caps &caps = context->getCaps(); + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context + ->handleError(InvalidValue() + << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE."); + return false; + } + + if (samples == 0) + { + context->handleError(InvalidValue() << "Samples may not be zero."); + return false; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); + if (!formatCaps.renderable) + { + context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, " + "depth-renderable, or stencil-renderable."); + return false; + } + + // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat + // is one of the unsized base internalformats listed in table 8.11. + const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat); + if (formatInfo.internalFormat == GL_NONE) + { + context->handleError( + InvalidEnum() + << "Internalformat is one of the unsupported unsized base internalformats."); + return false; + } + + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->handleError( + InvalidOperation() + << "Samples must not be greater than maximum supported value for the format."); + return false; + } + + Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->handleError(InvalidOperation() << "Zero is bound to target."); + return false; + } + + if (texture->getImmutableFormat()) + { + context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for " + "the texture currently bound to target on " + "the active texture unit is true."); + return false; + } + + return true; +} + +bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (pname != GL_SAMPLE_POSITION) + { + context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION."); + return false; + } + + Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer(); + + if (index >= static_cast(framebuffer->getSamples(context))) + { + context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES."); + return false; + } + + return true; +} + +bool ValidateFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + context->handleError(InvalidEnum() << "Invalid framebuffer target."); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + { + GLint maxWidth = context->getCaps().maxFramebufferWidth; + if (param < 0 || param > maxWidth) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + { + GLint maxHeight = context->getCaps().maxFramebufferHeight; + if (param < 0 || param > maxHeight) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + { + GLint maxSamples = context->getCaps().maxFramebufferSamples; + if (param < 0 || param > maxSamples) + { + context->handleError( + InvalidValue() + << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES."); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + { + break; + } + default: + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + } + + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + if (framebuffer->id() == 0) + { + context->handleError(InvalidOperation() << "Default framebuffer is bound to target."); + return false; + } + return true; +} + +bool ValidateGetFramebufferParameteriv(Context *context, GLenum target, GLenum pname, GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + default: + ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname); + return false; + } + + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + context->handleError(InvalidOperation() << "Default framebuffer is bound to target."); + return false; + } + return true; +} + +bool ValidateGetProgramResourceIndex(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex + << std::uppercase << programInterface); + return false; + } + + return true; +} + +bool ValidateBindVertexBuffer(ValidationContext *context, + GLuint bindingIndex, + GLuint buffer, + GLintptr offset, + GLsizei stride) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!context->isBufferGenerated(buffer)) + { + context->handleError(InvalidOperation() << "Buffer is not generated."); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + + if (offset < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset); + return false; + } + + if (stride < 0 || stride > caps.maxVertexAttribStride) + { + context->handleError(InvalidValue() + << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 244: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array buffer is bound."); + return false; + } + + return true; +} + +bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + return true; +} + +bool ValidateVertexAttribFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset) +{ + return ValidateVertexAttribFormatCommon(context, attribindex, size, type, relativeoffset, + false); +} + +bool ValidateVertexAttribIFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset) +{ + return ValidateVertexAttribFormatCommon(context, attribindex, size, type, relativeoffset, true); +} + +bool ValidateVertexAttribBinding(ValidationContext *context, + GLuint attribIndex, + GLuint bindingIndex) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getGLState().getVertexArrayId() == 0) + { + context->handleError(InvalidOperation() << "Default vertex array object is bound."); + return false; + } + + const Caps &caps = context->getCaps(); + if (attribIndex >= caps.maxVertexAttributes) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute); + return false; + } + + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->handleError(InvalidValue() + << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS"); + return false; + } + + return true; +} + +bool ValidateGetProgramResourceName(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex + << std::uppercase << programInterface); + return false; + } + + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->handleError(InvalidValue() << "Invalid index: " << index); + return false; + } + + if (bufSize < 0) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize); + return false; + } + + return true; +} + +bool ValidateDispatchCompute(Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + const State &state = context->getGLState(); + Program *program = state.getProgram(); + + if (program == nullptr) + { + context->handleError(InvalidOperation() + << "No active program object for the compute shader stage."); + return false; + } + + if (!program->isLinked() || !program->hasLinkedComputeShader()) + { + context->handleError( + InvalidOperation() + << "Program has not been successfully linked, or program contains no compute shaders."); + return false; + } + + const Caps &caps = context->getCaps(); + if (numGroupsX > caps.maxComputeWorkGroupCount[0]) + { + context->handleError( + InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]=" + << caps.maxComputeWorkGroupCount[0]); + return false; + } + if (numGroupsY > caps.maxComputeWorkGroupCount[1]) + { + context->handleError( + InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]=" + << caps.maxComputeWorkGroupCount[1]); + return false; + } + if (numGroupsZ > caps.maxComputeWorkGroupCount[2]) + { + context->handleError( + InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]=" + << caps.maxComputeWorkGroupCount[2]); + return false; + } + + return true; +} + +bool ValidateDispatchComputeIndirect(Context *context, GLintptr indirect) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateBindImageTexture(Context *context, + GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + GLuint maxImageUnits = context->getCaps().maxImageUnits; + if (unit >= maxImageUnits) + { + context->handleError(InvalidValue() + << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = " + << maxImageUnits); + return false; + } + + if (level < 0) + { + context->handleError(InvalidValue() << "level is negative."); + return false; + } + + if (layer < 0) + { + context->handleError(InvalidValue() << "layer is negative."); + return false; + } + + if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) + { + context->handleError(InvalidEnum() << "access is not one of the supported tokens."); + return false; + } + + switch (format) + { + case GL_RGBA32F: + case GL_RGBA16F: + case GL_R32F: + case GL_RGBA32UI: + case GL_RGBA16UI: + case GL_RGBA8UI: + case GL_R32UI: + case GL_RGBA32I: + case GL_RGBA16I: + case GL_RGBA8I: + case GL_R32I: + case GL_RGBA8: + case GL_RGBA8_SNORM: + break; + default: + context->handleError(InvalidValue() + << "format is not one of supported image unit formats."); + return false; + } + + if (texture != 0) + { + Texture *tex = context->getTexture(texture); + + if (tex == nullptr) + { + context->handleError(InvalidValue() + << "texture is not the name of an existing texture object."); + return false; + } + + if (!tex->getImmutableFormat()) + { + context->handleError(InvalidOperation() + << "texture is not the name of an immutable texture object."); + return false; + } + } + + return true; +} + +bool ValidateGetProgramResourceLocation(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!programObject->isLinked()) + { + context->handleError(InvalidOperation() << "Program is not successfully linked."); + return false; + } + + if (!ValidateLocationProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + return true; +} + +bool ValidateGetProgramResourceiv(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + if (!ValidateProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + if (propCount <= 0) + { + context->handleError(InvalidValue() << "Invalid propCount."); + return false; + } + if (bufSize < 0) + { + context->handleError(InvalidValue() << "Invalid bufSize."); + return false; + } + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->handleError(InvalidValue() << "Invalid index: " << index); + return false; + } + for (GLsizei i = 0; i < propCount; i++) + { + if (!ValidateProgramResourceProperty(props[i])) + { + context->handleError(InvalidEnum() << "Invalid prop."); + return false; + } + if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface)) + { + context->handleError(InvalidOperation() << "Not an allowed prop for interface"); + return false; + } + } + return true; +} + +bool ValidateGetProgramInterfaceiv(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateProgramInterface(programInterface)) + { + context->handleError(InvalidEnum() << "Invalid program interface."); + return false; + } + + switch (pname) + { + case GL_ACTIVE_RESOURCES: + case GL_MAX_NAME_LENGTH: + case GL_MAX_NUM_ACTIVE_VARIABLES: + break; + + default: + context->handleError(InvalidEnum() << "Unknown property of program interface."); + return false; + } + + if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER) + { + context->handleError(InvalidOperation() + << "Active atomic counter resources are not assigned name strings."); + return false; + } + + if (pname == GL_MAX_NUM_ACTIVE_VARIABLES) + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + break; + + default: + context->handleError( + InvalidOperation() + << "MAX_NUM_ACTIVE_VARIABLES requires a buffer or block interface."); + return false; + } + } + + return true; +} + +static bool ValidateGenOrDeleteES31(Context *context, GLint n) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenProgramPipelines(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateDeleteProgramPipelines(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateBindProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (!context->isProgramPipelineGenerated(pipeline)) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ObjectNotGenerated); + return false; + } + + return true; +} + +bool ValidateIsProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + return true; +} + +bool ValidateUseProgramStages(Context *context, GLuint pipeline, GLbitfield stages, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateActiveShaderProgram(Context *context, GLuint pipeline, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateCreateShaderProgramv(Context *context, + GLenum type, + GLsizei count, + const GLchar *const *strings) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineiv(Context *context, GLuint pipeline, GLenum pname, GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateValidateProgramPipeline(Context *context, GLuint pipeline) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineInfoLog(Context *context, + GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateMemoryBarrier(Context *context, GLbitfield barriers) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateMemoryBarrierByRegion(Context *context, GLbitfield barriers) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateSampleMaski(Context *context, GLuint maskNumber, GLbitfield mask) +{ + if (context->getClientVersion() < ES_3_1) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required); + return false; + } + + if (maskNumber >= context->getCaps().maxSampleMaskWords) + { + ANGLE_VALIDATION_ERR(context, InvalidValue(), InvalidSampleMaskNumber); + return false; + } + + return true; +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/validationES31.h b/src/3rdparty/angle/src/libANGLE/validationES31.h new file mode 100644 index 0000000000..a0b76a5bcb --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES31.h @@ -0,0 +1,325 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// validationES31.h: Validation functions for OpenGL ES 3.1 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES31_H_ +#define LIBANGLE_VALIDATION_ES31_H_ + +#include + +namespace gl +{ +class Context; +class ValidationContext; + +bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data); +bool ValidateGetBooleani_vRobustANGLE(Context *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data); + +bool ValidateGetTexLevelParameterfv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLfloat *params); +bool ValidateGetTexLevelParameteriv(Context *context, + GLenum target, + GLint level, + GLenum pname, + GLint *param); + +bool ValidateTexStorage2DMultisample(Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations); +bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val); + +bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect); +bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect); +bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect); + +bool ValidateProgramUniform1i(Context *context, GLuint program, GLint location, GLint v0); +bool ValidateProgramUniform2i(Context *context, GLuint program, GLint location, GLint v0, GLint v1); +bool ValidateProgramUniform3i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2); +bool ValidateProgramUniform4i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3); +bool ValidateProgramUniform1ui(Context *context, GLuint program, GLint location, GLuint v0); +bool ValidateProgramUniform2ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1); +bool ValidateProgramUniform3ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2); +bool ValidateProgramUniform4ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3); +bool ValidateProgramUniform1f(Context *context, GLuint program, GLint location, GLfloat v0); +bool ValidateProgramUniform2f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1); +bool ValidateProgramUniform3f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2); +bool ValidateProgramUniform4f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3); + +bool ValidateProgramUniform1iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform2iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform3iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform4iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value); +bool ValidateProgramUniform1uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform2uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform3uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform4uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +bool ValidateProgramUniform1fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniform4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix2x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix3x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +bool ValidateProgramUniformMatrix4x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +bool ValidateFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param); +bool ValidateGetFramebufferParameteriv(Context *context, + GLenum target, + GLenum pname, + GLint *params); + +bool ValidateGetProgramResourceIndex(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name); +bool ValidateGetProgramResourceName(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); +bool ValidateGetProgramResourceLocation(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name); + +bool ValidateGetProgramResourceiv(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); + +bool ValidateGetProgramInterfaceiv(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params); + +bool ValidateBindVertexBuffer(ValidationContext *context, + GLuint bindingIndex, + GLuint buffer, + GLintptr offset, + GLsizei stride); +bool ValidateVertexAttribFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset); +bool ValidateVertexAttribIFormat(ValidationContext *context, + GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset); +bool ValidateVertexAttribBinding(ValidationContext *context, + GLuint attribIndex, + GLuint bindingIndex); +bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor); + +bool ValidateDispatchCompute(Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ); +bool ValidateDispatchComputeIndirect(Context *context, GLintptr indirect); + +bool ValidateBindImageTexture(Context *context, + GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); + +bool ValidateGenProgramPipelines(Context *context, GLint n, GLuint *pipelines); +bool ValidateDeleteProgramPipelines(Context *context, GLint n, const GLuint *pipelines); +bool ValidateBindProgramPipeline(Context *context, GLuint pipeline); +bool ValidateIsProgramPipeline(Context *context, GLuint pipeline); +bool ValidateUseProgramStages(Context *context, GLuint pipeline, GLbitfield stages, GLuint program); +bool ValidateActiveShaderProgram(Context *context, GLuint pipeline, GLuint program); +bool ValidateCreateShaderProgramv(Context *context, + GLenum type, + GLsizei count, + const GLchar *const *strings); +bool ValidateGetProgramPipelineiv(Context *context, GLuint pipeline, GLenum pname, GLint *params); +bool ValidateValidateProgramPipeline(Context *context, GLuint pipeline); +bool ValidateGetProgramPipelineInfoLog(Context *context, + GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); + +bool ValidateMemoryBarrier(Context *context, GLbitfield barriers); +bool ValidateMemoryBarrierByRegion(Context *context, GLbitfield barriers); + +bool ValidateSampleMaski(Context *context, GLuint maskNumber, GLbitfield mask); + +} // namespace gl + +#endif // LIBANGLE_VALIDATION_ES31_H_ diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp index f28f40fcf5..efe0b0c124 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.cpp +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -288,4 +288,121 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const cha return egl::GetProcAddress(procname); } +EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +{ + return egl::CreateStreamKHR(dpy, attrib_list); +} + +EGLBoolean EGLAPIENTRY eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + return egl::DestroyStreamKHR(dpy, stream); +} + +EGLBoolean EGLAPIENTRY eglStreamAttribKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint value) +{ + return egl::StreamAttribKHR(dpy, stream, attribute, value); +} + +EGLBoolean EGLAPIENTRY eglQueryStreamKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint *value) +{ + return egl::QueryStreamKHR(dpy, stream, attribute, value); +} + +EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLuint64KHR *value) +{ + return egl::QueryStreamu64KHR(dpy, stream, attribute, value); +} + +EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + return egl::StreamConsumerGLTextureExternalKHR(dpy, stream); +} + +EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + return egl::StreamConsumerAcquireKHR(dpy, stream); +} + +EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + return egl::StreamConsumerReleaseKHR(dpy, stream); +} + +EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV(EGLDisplay dpy, + EGLStreamKHR stream, + EGLAttrib *attrib_list) +{ + return egl::StreamConsumerGLTextureExternalAttribsNV(dpy, stream, attrib_list); } + +EGLBoolean EGLAPIENTRY eglCreateStreamProducerD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + const EGLAttrib *attrib_list) +{ + return egl::CreateStreamProducerD3DTextureNV12ANGLE(dpy, stream, attrib_list); +} + +EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + void *texture, + const EGLAttrib *attrib_list) +{ + return egl::StreamPostD3DTextureNV12ANGLE(dpy, stream, texture, attrib_list); +} + +EGLBoolean EGLAPIENTRY eglGetSyncValuesCHROMIUM(EGLDisplay dpy, + EGLSurface surface, + EGLuint64KHR *ust, + EGLuint64KHR *msc, + EGLuint64KHR *sbc) +{ + return egl::GetSyncValuesCHROMIUM(dpy, surface, ust, msc, sbc); +} + +EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT(EGLDisplay dpy, + EGLSurface surface, + EGLint *rects, + EGLint n_rects) +{ + return egl::SwapBuffersWithDamageEXT(dpy, surface, rects, n_rects); +} + +EGLint EGLAPIENTRY eglProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib) +{ + return egl::ProgramCacheGetAttribANGLE(dpy, attrib); +} + +void EGLAPIENTRY eglProgramCacheQueryANGLE(EGLDisplay dpy, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + egl::ProgramCacheQueryANGLE(dpy, index, key, keysize, binary, binarysize); +} + +void EGLAPIENTRY eglProgramCachePopulateANGLE(EGLDisplay dpy, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + egl::ProgramCachePopulateANGLE(dpy, key, keysize, binary, binarysize); +} + +EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode) +{ + return egl::ProgramCacheResizeANGLE(dpy, limit, mode); +} + +} // extern "C" diff --git a/src/3rdparty/angle/src/libEGL/libEGL.def b/src/3rdparty/angle/src/libEGL/libEGL.def index 74b7c2ae14..e68d27295e 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.def +++ b/src/3rdparty/angle/src/libEGL/libEGL.def @@ -1,60 +1,77 @@ LIBRARY libEGL EXPORTS - eglBindAPI @14 - eglBindTexImage @20 - eglChooseConfig @7 - eglCopyBuffers @33 - eglCreateContext @23 - eglCreatePbufferFromClientBuffer @18 - eglCreatePbufferSurface @10 - eglCreatePixmapSurface @11 - eglCreateWindowSurface @9 - eglDestroyContext @24 - eglDestroySurface @12 - eglGetConfigAttrib @8 - eglGetConfigs @6 - eglGetCurrentContext @26 - eglGetCurrentDisplay @28 - eglGetCurrentSurface @27 - eglGetDisplay @2 - eglGetError @1 - eglGetProcAddress @34 - eglInitialize @3 - eglMakeCurrent @25 - eglQueryAPI @15 - eglQueryContext @29 - eglQueryString @5 - eglQuerySurface @13 - eglReleaseTexImage @21 - eglReleaseThread @17 - eglSurfaceAttrib @19 - eglSwapBuffers @32 - eglSwapInterval @22 - eglTerminate @4 - eglWaitClient @16 - eglWaitGL @30 - eglWaitNative @31 + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31 ; Extensions - eglGetPlatformDisplayEXT @35 - eglQuerySurfacePointerANGLE @36 - eglPostSubBufferNV @37 - eglQueryDisplayAttribEXT @48 - eglQueryDeviceAttribEXT @49 - eglQueryDeviceStringEXT @50 - eglCreateImageKHR @51 - eglDestroyImageKHR @52 - eglCreateDeviceANGLE @53 - eglReleaseDeviceANGLE @54 + eglGetPlatformDisplayEXT @35 + eglQuerySurfacePointerANGLE @36 + eglPostSubBufferNV @37 + eglQueryDisplayAttribEXT @48 + eglQueryDeviceAttribEXT @49 + eglQueryDeviceStringEXT @50 + eglCreateImageKHR @51 + eglDestroyImageKHR @52 + eglCreateDeviceANGLE @53 + eglReleaseDeviceANGLE @54 + eglCreateStreamKHR @55 + eglDestroyStreamKHR @56 + eglStreamAttribKHR @57 + eglQueryStreamKHR @58 + eglQueryStreamu64KHR @59 + eglStreamConsumerGLTextureExternalKHR @60 + eglStreamConsumerAcquireKHR @61 + eglStreamConsumerReleaseKHR @62 + eglStreamConsumerGLTextureExternalAttribsNV @63 + eglCreateStreamProducerD3DTextureNV12ANGLE @64 + eglStreamPostD3DTextureNV12ANGLE @65 + eglGetSyncValuesCHROMIUM @66 + eglSwapBuffersWithDamageEXT @67 + eglProgramCacheGetAttribANGLE @68 + eglProgramCachePopulateANGLE @69 + eglProgramCacheQueryANGLE @70 + eglProgramCacheResizeANGLE @71 ; 1.5 entry points - eglCreateSync @38 - eglDestroySync @39 - eglClientWaitSync @40 - eglGetSyncAttrib @41 - eglCreateImage @42 - eglDestroyImage @43 - eglGetPlatformDisplay @44 - eglCreatePlatformWindowSurface @45 - eglCreatePlatformPixmapSurface @46 - eglWaitSync @47 + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def index d8fcf51620..e68d27295e 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def +++ b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def @@ -1,60 +1,77 @@ LIBRARY libEGL EXPORTS - eglBindAPI@4 @14 - eglBindTexImage@12 @20 - eglChooseConfig@20 @7 - eglCopyBuffers@12 @33 - eglCreateContext@16 @23 - eglCreatePbufferFromClientBuffer@20 @18 - eglCreatePbufferSurface@12 @10 - eglCreatePixmapSurface@16 @11 - eglCreateWindowSurface@16 @9 - eglDestroyContext@8 @24 - eglDestroySurface@8 @12 - eglGetConfigAttrib@16 @8 - eglGetConfigs@16 @6 - eglGetCurrentContext@0 @26 - eglGetCurrentDisplay@0 @28 - eglGetCurrentSurface@4 @27 - eglGetDisplay@4 @2 - eglGetError@0 @1 - eglGetProcAddress@4 @34 - eglInitialize@12 @3 - eglMakeCurrent@16 @25 - eglQueryAPI@0 @15 - eglQueryContext@16 @29 - eglQueryString@8 @5 - eglQuerySurface@16 @13 - eglReleaseTexImage@12 @21 - eglReleaseThread@0 @17 - eglSurfaceAttrib@16 @19 - eglSwapBuffers@8 @32 - eglSwapInterval@8 @22 - eglTerminate@4 @4 - eglWaitClient@0 @16 - eglWaitGL@0 @30 - eglWaitNative@4 @31 + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31 ; Extensions - 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 + eglGetPlatformDisplayEXT @35 + eglQuerySurfacePointerANGLE @36 + eglPostSubBufferNV @37 + eglQueryDisplayAttribEXT @48 + eglQueryDeviceAttribEXT @49 + eglQueryDeviceStringEXT @50 + eglCreateImageKHR @51 + eglDestroyImageKHR @52 + eglCreateDeviceANGLE @53 + eglReleaseDeviceANGLE @54 + eglCreateStreamKHR @55 + eglDestroyStreamKHR @56 + eglStreamAttribKHR @57 + eglQueryStreamKHR @58 + eglQueryStreamu64KHR @59 + eglStreamConsumerGLTextureExternalKHR @60 + eglStreamConsumerAcquireKHR @61 + eglStreamConsumerReleaseKHR @62 + eglStreamConsumerGLTextureExternalAttribsNV @63 + eglCreateStreamProducerD3DTextureNV12ANGLE @64 + eglStreamPostD3DTextureNV12ANGLE @65 + eglGetSyncValuesCHROMIUM @66 + eglSwapBuffersWithDamageEXT @67 + eglProgramCacheGetAttribANGLE @68 + eglProgramCachePopulateANGLE @69 + eglProgramCacheQueryANGLE @70 + eglProgramCacheResizeANGLE @71 ; 1.5 entry points - eglCreateSync @38 - eglDestroySync @39 - eglClientWaitSync @40 - eglGetSyncAttrib @41 - eglCreateImage @42 - eglDestroyImage @43 - eglGetPlatformDisplay @44 - eglCreatePlatformWindowSurface @45 - eglCreatePlatformPixmapSurface @46 - eglWaitSync @47 + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/libEGLd.def b/src/3rdparty/angle/src/libEGL/libEGLd.def index 318e04cfa6..e6a8b1bac7 100644 --- a/src/3rdparty/angle/src/libEGL/libEGLd.def +++ b/src/3rdparty/angle/src/libEGL/libEGLd.def @@ -1,60 +1,77 @@ LIBRARY libEGLd EXPORTS - eglBindAPI @14 - eglBindTexImage @20 - eglChooseConfig @7 - eglCopyBuffers @33 - eglCreateContext @23 - eglCreatePbufferFromClientBuffer @18 - eglCreatePbufferSurface @10 - eglCreatePixmapSurface @11 - eglCreateWindowSurface @9 - eglDestroyContext @24 - eglDestroySurface @12 - eglGetConfigAttrib @8 - eglGetConfigs @6 - eglGetCurrentContext @26 - eglGetCurrentDisplay @28 - eglGetCurrentSurface @27 - eglGetDisplay @2 - eglGetError @1 - eglGetProcAddress @34 - eglInitialize @3 - eglMakeCurrent @25 - eglQueryAPI @15 - eglQueryContext @29 - eglQueryString @5 - eglQuerySurface @13 - eglReleaseTexImage @21 - eglReleaseThread @17 - eglSurfaceAttrib @19 - eglSwapBuffers @32 - eglSwapInterval @22 - eglTerminate @4 - eglWaitClient @16 - eglWaitGL @30 - eglWaitNative @31 + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31 ; Extensions - eglGetPlatformDisplayEXT @35 - eglQuerySurfacePointerANGLE @36 - eglPostSubBufferNV @37 - eglQueryDisplayAttribEXT @48 - eglQueryDeviceAttribEXT @49 - eglQueryDeviceStringEXT @50 - eglCreateImageKHR @51 - eglDestroyImageKHR @52 - eglCreateDeviceANGLE @53 - eglReleaseDeviceANGLE @54 + eglGetPlatformDisplayEXT @35 + eglQuerySurfacePointerANGLE @36 + eglPostSubBufferNV @37 + eglQueryDisplayAttribEXT @48 + eglQueryDeviceAttribEXT @49 + eglQueryDeviceStringEXT @50 + eglCreateImageKHR @51 + eglDestroyImageKHR @52 + eglCreateDeviceANGLE @53 + eglReleaseDeviceANGLE @54 + eglCreateStreamKHR @55 + eglDestroyStreamKHR @56 + eglStreamAttribKHR @57 + eglQueryStreamKHR @58 + eglQueryStreamu64KHR @59 + eglStreamConsumerGLTextureExternalKHR @60 + eglStreamConsumerAcquireKHR @61 + eglStreamConsumerReleaseKHR @62 + eglStreamConsumerGLTextureExternalAttribsNV @63 + eglCreateStreamProducerD3DTextureNV12ANGLE @64 + eglStreamPostD3DTextureNV12ANGLE @65 + eglGetSyncValuesCHROMIUM @66 + eglSwapBuffersWithDamageEXT @67 + eglProgramCacheGetAttribANGLE @68 + eglProgramCachePopulateANGLE @69 + eglProgramCacheQueryANGLE @70 + eglProgramCacheResizeANGLE @71 ; 1.5 entry points - eglCreateSync @38 - eglDestroySync @39 - eglClientWaitSync @40 - eglGetSyncAttrib @41 - eglCreateImage @42 - eglDestroyImage @43 - eglGetPlatformDisplay @44 - eglCreatePlatformWindowSurface @45 - eglCreatePlatformPixmapSurface @46 - eglWaitSync @47 + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def b/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def deleted file mode 100644 index d322cf67de..0000000000 --- a/src/3rdparty/angle/src/libEGL/libEGLd_mingw32.def +++ /dev/null @@ -1,48 +0,0 @@ -LIBRARY libEGLd -EXPORTS - eglBindAPI@4 @14 - eglBindTexImage@12 @20 - eglChooseConfig@20 @7 - eglCopyBuffers@12 @33 - eglCreateContext@16 @23 - eglCreatePbufferFromClientBuffer@20 @18 - eglCreatePbufferSurface@12 @10 - eglCreatePixmapSurface@16 @11 - eglCreateWindowSurface@16 @9 - eglDestroyContext@8 @24 - eglDestroySurface@8 @12 - eglGetConfigAttrib@16 @8 - eglGetConfigs@16 @6 - eglGetCurrentContext@0 @26 - eglGetCurrentDisplay@0 @28 - eglGetCurrentSurface@4 @27 - eglGetDisplay@4 @2 - eglGetError@0 @1 - eglGetProcAddress@4 @34 - eglInitialize@12 @3 - eglMakeCurrent@16 @25 - eglQueryAPI@0 @15 - eglQueryContext@16 @29 - eglQueryString@8 @5 - eglQuerySurface@16 @13 - eglReleaseTexImage@12 @21 - eglReleaseThread@0 @17 - eglSurfaceAttrib@16 @19 - eglSwapBuffers@8 @32 - eglSwapInterval@8 @22 - eglTerminate@4 @4 - eglWaitClient@0 @16 - eglWaitGL@0 @30 - eglWaitNative@4 @31 - - ; Extensions - 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 6f9770c57c..97546ee900 100644 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp @@ -7,33 +7,59 @@ // entry_points_egl.cpp : Implements the EGL entry points. #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.h" -#include "libGLESv2/global_state.h" +#include "common/debug.h" +#include "common/version.h" #include "libANGLE/Context.h" #include "libANGLE/Display.h" -#include "libANGLE/Texture.h" #include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Thread.h" +#include "libANGLE/queryutils.h" #include "libANGLE/validationEGL.h" - -#include "common/debug.h" -#include "common/version.h" +#include "libGLESv2/global_state.h" +#include "libGLESv2/proc_table.h" #include namespace egl { +namespace +{ + +bool CompareProc(const ProcEntry &a, const char *b) +{ + return strcmp(a.first, b) < 0; +} + +void ClipConfigs(const std::vector &filteredConfigs, + EGLConfig *output_configs, + EGLint config_size, + EGLint *num_config) +{ + EGLint result_size = static_cast(filteredConfigs.size()); + if (output_configs) + { + result_size = std::max(std::min(result_size, config_size), 0); + for (EGLint i = 0; i < result_size; i++) + { + output_configs[i] = const_cast(filteredConfigs[i]); + } + } + *num_config = result_size; +} + +} // anonymous namespace + // EGL 1.0 EGLint EGLAPIENTRY GetError(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - EGLint error = GetGlobalError(); - SetGlobalError(Error(EGL_SUCCESS)); + EGLint error = thread->getError(); + thread->setError(NoError()); return error; } @@ -41,445 +67,367 @@ EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id) { EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); - return Display::GetDisplayFromAttribs(reinterpret_cast(display_id), AttributeMap()); + return Display::GetDisplayFromNativeDisplay(display_id, AttributeMap()); } 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); + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)", dpy, + major, minor); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) { - SetGlobalError(Error(EGL_BAD_DISPLAY)); + thread->setError(EglBadDisplay()); return EGL_FALSE; } Error error = display->initialize(); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (major) *major = 1; - if (minor) *minor = 4; + if (major) + *major = 1; + if (minor) + *minor = 4; - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy) { EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) { - SetGlobalError(Error(EGL_BAD_DISPLAY)); + thread->setError(EglBadDisplay()); return EGL_FALSE; } - gl::Context *context = GetGlobalContext(); - - if (display->isValidContext(context)) + if (display->isValidContext(thread->getContext())) { - SetGlobalContext(NULL); - SetGlobalDisplay(NULL); + thread->setCurrent(nullptr); } - display->terminate(); + Error error = display->terminate(); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); + Display *display = static_cast(dpy); if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)) { Error error = ValidateDisplay(display); if (error.isError()) { - SetGlobalError(error); - return NULL; + thread->setError(error); + return nullptr; } } const char *result; switch (name) { - case EGL_CLIENT_APIS: - result = "OpenGL_ES"; - break; - case EGL_EXTENSIONS: - if (display == EGL_NO_DISPLAY) - { - result = Display::getClientExtensionString().c_str(); - } - else - { - result = display->getExtensionString().c_str(); - } - break; - case EGL_VENDOR: - result = display->getVendorString().c_str(); - break; - case EGL_VERSION: - result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; - break; - default: - SetGlobalError(Error(EGL_BAD_PARAMETER)); - return NULL; - } - - SetGlobalError(Error(EGL_SUCCESS)); + case EGL_CLIENT_APIS: + result = "OpenGL_ES"; + break; + case EGL_EXTENSIONS: + if (display == EGL_NO_DISPLAY) + { + result = Display::GetClientExtensionString().c_str(); + } + else + { + result = display->getExtensionString().c_str(); + } + break; + case EGL_VENDOR: + result = display->getVendorString().c_str(); + break; + case EGL_VERSION: + result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; + break; + default: + thread->setError(EglBadParameter()); + return nullptr; + } + + thread->setError(NoError()); return result; } -EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, + EGLint *num_config) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, " - "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", - dpy, configs, config_size, num_config); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, " + "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, configs, config_size, num_config); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); + Display *display = static_cast(dpy); - Error error = ValidateDisplay(display); + Error error = ValidateGetConfigs(display, config_size, num_config); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (!num_config) - { - SetGlobalError(Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } + ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config); - std::vector filteredConfigs = display->getConfigs(AttributeMap()); - if (configs) - { - filteredConfigs.resize(std::min(filteredConfigs.size(), config_size)); - for (size_t i = 0; i < filteredConfigs.size(); i++) - { - configs[i] = const_cast(filteredConfigs[i]); - } - } - *num_config = static_cast(filteredConfigs.size()); - - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, + const EGLint *attrib_list, + EGLConfig *configs, + EGLint config_size, + EGLint *num_config) { - EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, " - "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", - dpy, attrib_list, configs, config_size, num_config); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, " + "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, attrib_list, configs, config_size, num_config); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); + Display *display = static_cast(dpy); + AttributeMap attribMap = AttributeMap::CreateFromIntArray(attrib_list); - Error error = ValidateDisplay(display); + Error error = ValidateChooseConfig(display, attribMap, config_size, num_config); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (!num_config) - { - SetGlobalError(Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - std::vector filteredConfigs = display->getConfigs(AttributeMap(attrib_list)); - if (configs) - { - filteredConfigs.resize(std::min(filteredConfigs.size(), config_size)); - for (size_t i = 0; i < filteredConfigs.size(); i++) - { - configs[i] = const_cast(filteredConfigs[i]); - } - } - *num_config = static_cast(filteredConfigs.size()); + ClipConfigs(display->getConfigs(attribMap), configs, config_size, num_config); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, + EGLConfig config, + EGLint attribute, + EGLint *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, config, attribute, value); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint " + "*value = 0x%0.8p)", + dpy, config, attribute, value); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); - Error error = ValidateConfig(display, configuration); + Error error = ValidateGetConfigAttrib(display, configuration, attribute); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (!display->getConfigAttrib(configuration, attribute, value)) - { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } + QueryConfigAttrib(configuration, attribute, value); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, " - "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", + dpy, config, win, attrib_list); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); - AttributeMap attributes(attrib_list); + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); Error error = ValidateCreateWindowSurface(display, configuration, win, attributes); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } egl::Surface *surface = nullptr; - error = display->createWindowSurface(configuration, win, attributes, &surface); + error = display->createWindowSurface(configuration, win, attributes, &surface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } return static_cast(surface); } -EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, + EGLConfig config, + const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", - dpy, config, attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = " + "0x%0.8p)", + dpy, config, attrib_list); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); - AttributeMap attributes(attrib_list); + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); Error error = ValidateCreatePbufferSurface(display, configuration, attributes); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } egl::Surface *surface = nullptr; - error = display->createPbufferSurface(configuration, attributes, &surface); + error = display->createPbufferSurface(configuration, attributes, &surface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } return static_cast(surface); } -EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, + EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, " - "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = " + "0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", + dpy, config, pixmap, attrib_list); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); Error error = ValidateConfig(display, configuration); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } - UNIMPLEMENTED(); // FIXME + UNIMPLEMENTED(); // FIXME - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_NO_SURFACE; } EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = static_cast(surface); + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } - display->destroySurface((Surface*)surface); + error = display->destroySurface(reinterpret_cast(surface)); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + EGLint *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, surface, attribute, value); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint " + "*value = 0x%0.8p)", + dpy, surface, attribute, value); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = (Surface*)surface; + const Display *display = static_cast(dpy); + const Surface *eglSurface = static_cast(surface); - Error error = ValidateSurface(display, eglSurface); + Error error = ValidateQuerySurface(display, eglSurface, attribute, value); if (error.isError()) { - SetGlobalError(error); - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(error); return EGL_FALSE; } - switch (attribute) - { - case EGL_VG_ALPHA_FORMAT: - UNIMPLEMENTED(); // FIXME - break; - case EGL_VG_COLORSPACE: - UNIMPLEMENTED(); // FIXME - break; - case EGL_CONFIG_ID: - *value = eglSurface->getConfig()->configID; - break; - case EGL_HEIGHT: - *value = eglSurface->getHeight(); - break; - case EGL_HORIZONTAL_RESOLUTION: - UNIMPLEMENTED(); // FIXME - break; - case EGL_LARGEST_PBUFFER: - UNIMPLEMENTED(); // FIXME - break; - case EGL_MIPMAP_TEXTURE: - UNIMPLEMENTED(); // FIXME - break; - case EGL_MIPMAP_LEVEL: - UNIMPLEMENTED(); // FIXME - break; - case EGL_MULTISAMPLE_RESOLVE: - UNIMPLEMENTED(); // FIXME - break; - case EGL_PIXEL_ASPECT_RATIO: - *value = eglSurface->getPixelAspectRatio(); - break; - case EGL_RENDER_BUFFER: - *value = eglSurface->getRenderBuffer(); - break; - case EGL_SWAP_BEHAVIOR: - *value = eglSurface->getSwapBehavior(); - break; - case EGL_TEXTURE_FORMAT: - *value = eglSurface->getTextureFormat(); - break; - case EGL_TEXTURE_TARGET: - *value = eglSurface->getTextureTarget(); - break; - case EGL_VERTICAL_RESOLUTION: - UNIMPLEMENTED(); // FIXME - break; - case EGL_WIDTH: - *value = eglSurface->getWidth(); - break; - case EGL_POST_SUB_BUFFER_SUPPORTED_NV: - if (!display->getExtensions().postSubBuffer) - { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - *value = eglSurface->isPostSubBufferSupported(); - break; - case EGL_FIXED_SIZE_ANGLE: - if (!display->getExtensions().windowFixedSize) - { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - *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; - } + QuerySurfaceAttrib(eglSurface, attribute, value); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, + EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, " - "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list); - - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); - gl::Context* sharedGLContext = static_cast(share_context); - AttributeMap attributes(attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = " + "0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", + dpy, config, share_context, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + gl::Context *sharedGLContext = static_cast(share_context); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); Error error = ValidateCreateContext(display, configuration, sharedGLContext, attributes); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_CONTEXT; } @@ -487,208 +435,115 @@ EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContex error = display->createContext(configuration, sharedGLContext, attributes, &context); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_CONTEXT; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return static_cast(context); } EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); Error error = ValidateContext(display, context); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (ctx == EGL_NO_CONTEXT) { - SetGlobalError(Error(EGL_BAD_CONTEXT)); + thread->setError(EglBadContext()); return EGL_FALSE; } - if (context == GetGlobalContext()) + if (context == thread->getContext()) { - SetGlobalDisplay(NULL); - SetGlobalContext(NULL); + thread->setCurrent(nullptr); } - display->destroyContext(context); + error = display->destroyContext(context); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", - dpy, draw, read, ctx); - - Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); - - // 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; - } + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, " + "EGLContext ctx = 0x%0.8p)", + dpy, draw, read, ctx); + Thread *thread = GetCurrentThread(); - if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display)) - { - SetGlobalError(Error(EGL_BAD_DISPLAY, "'dpy' not a valid EGLDisplay handle")); - return EGL_FALSE; - } + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); - // 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)) + Error error = ValidateMakeCurrent(display, draw, read, context); + if (error.isError()) { - SetGlobalError(Error(EGL_NOT_INITIALIZED, "'dpy' not initialized")); + thread->setError(error); return EGL_FALSE; } - if (ctx != EGL_NO_CONTEXT) - { - Error error = ValidateContext(display, context); - if (error.isError()) - { - SetGlobalError(error); - return EGL_FALSE; - } - } - - if (display->isInitialized()) - { - if (display->testDeviceLost()) - { - display->notifyDeviceLost(); - return EGL_FALSE; - } - - if (display->isDeviceLost()) - { - SetGlobalError(Error(EGL_CONTEXT_LOST)); - return EGL_FALSE; - } - } - - Surface *drawSurface = static_cast(draw); - if (draw != EGL_NO_SURFACE) - { - Error error = ValidateSurface(display, drawSurface); - if (error.isError()) - { - SetGlobalError(error); - return EGL_FALSE; - } - } - - Surface *readSurface = static_cast(read); - if (read != EGL_NO_SURFACE) - { - Error error = ValidateSurface(display, readSurface); - if (error.isError()) - { - SetGlobalError(error); - return EGL_FALSE; - } - } - - 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; - } - } - } - + Surface *readSurface = static_cast(read); + Surface *drawSurface = static_cast(draw); Error makeCurrentError = display->makeCurrent(drawSurface, readSurface, context); if (makeCurrentError.isError()) { - SetGlobalError(makeCurrentError); + thread->setError(makeCurrentError); return EGL_FALSE; } - gl::Context *previousContext = GetGlobalContext(); - - SetGlobalDisplay(display); - SetGlobalDrawSurface(drawSurface); - SetGlobalReadSurface(readSurface); - SetGlobalContext(context); + gl::Context *previousContext = thread->getContext(); + thread->setCurrent(context); // Release the surface from the previously-current context, to allow // destroyed surfaces to delete themselves. if (previousContext != nullptr && context != previousContext) { - previousContext->releaseSurface(); + auto err = previousContext->releaseSurface(display); + if (err.isError()) + { + thread->setError(err); + return EGL_FALSE; + } } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw) { EVENT("(EGLint readdraw = %d)", readdraw); + Thread *thread = GetCurrentThread(); if (readdraw == EGL_READ) { - SetGlobalError(Error(EGL_SUCCESS)); - return GetGlobalReadSurface(); + thread->setError(NoError()); + return thread->getCurrentReadSurface(); } else if (readdraw == EGL_DRAW) { - SetGlobalError(Error(EGL_SUCCESS)); - return GetGlobalDrawSurface(); + thread->setError(NoError()); + return thread->getCurrentDrawSurface(); } else { - SetGlobalError(Error(EGL_BAD_PARAMETER)); + thread->setError(EglBadParameter()); return EGL_NO_SURFACE; } } @@ -696,283 +551,294 @@ EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw) EGLDisplay EGLAPIENTRY GetCurrentDisplay(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - EGLDisplay dpy = GetGlobalDisplay(); - - SetGlobalError(Error(EGL_SUCCESS)); - return dpy; + thread->setError(NoError()); + if (thread->getContext() != nullptr) + { + return thread->getContext()->getCurrentDisplay(); + } + return EGL_NO_DISPLAY; } EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, ctx, attribute, value); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value " + "= 0x%0.8p)", + dpy, ctx, attribute, value); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); - Error error = ValidateContext(display, context); + Error error = ValidateQueryContext(display, context, attribute, value); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - switch (attribute) - { - case EGL_CONFIG_ID: - *value = context->getConfig()->configID; - break; - case EGL_CONTEXT_CLIENT_TYPE: - *value = context->getClientType(); - break; - case EGL_CONTEXT_CLIENT_VERSION: - *value = context->getClientVersion(); - break; - case EGL_RENDER_BUFFER: - *value = context->getRenderBuffer(); - break; - default: - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } + QueryContextAttrib(context, attribute, value); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY WaitGL(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - Display *display = GetGlobalDisplay(); + Display *display = thread->getCurrentDisplay(); Error error = ValidateDisplay(display); if (error.isError()) { - SetGlobalError(error); + thread->setError(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(); + error = display->waitClient(thread->getContext()); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY WaitNative(EGLint engine) { EVENT("(EGLint engine = %d)", engine); + Thread *thread = GetCurrentThread(); - Display *display = GetGlobalDisplay(); + Display *display = thread->getCurrentDisplay(); Error error = ValidateDisplay(display); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (engine != EGL_CORE_NATIVE_ENGINE) { - SetGlobalError( - Error(EGL_BAD_PARAMETER, "the 'engine' parameter has an unrecognized value")); + thread->setError(EglBadParameter() << "the 'engine' parameter has an unrecognized value"); } - error = display->waitNative(engine, GetGlobalDrawSurface(), GetGlobalReadSurface()); + error = display->waitNative(thread->getContext(), engine); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = (Surface*)surface; + Display *display = static_cast(dpy); + Surface *eglSurface = (Surface *)surface; Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (display->isDeviceLost()) + if (display->testDeviceLost()) { - SetGlobalError(Error(EGL_CONTEXT_LOST)); + thread->setError(EglContextLost()); return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } - error = eglSurface->swap(); + if (!thread->getContext() || thread->getCurrentDrawSurface() != eglSurface) + { + thread->setError(EglBadSurface()); + return EGL_FALSE; + } + + error = eglSurface->swap(thread->getContext()); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = " + "0x%0.8p)", + dpy, surface, target); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = static_cast(surface); + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (display->isDeviceLost()) + if (display->testDeviceLost()) { - SetGlobalError(Error(EGL_CONTEXT_LOST)); + thread->setError(EglContextLost()); return EGL_FALSE; } - UNIMPLEMENTED(); // FIXME + UNIMPLEMENTED(); // FIXME - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return 0; } // EGL 1.1 EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, + surface, buffer); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = static_cast(surface); + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (buffer != EGL_BACK_BUFFER) { - SetGlobalError(Error(EGL_BAD_PARAMETER)); + thread->setError(EglBadParameter()); return EGL_FALSE; } if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } if (eglSurface->getBoundTexture()) { - SetGlobalError(Error(EGL_BAD_ACCESS)); + thread->setError(EglBadAccess()); return EGL_FALSE; } if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) { - SetGlobalError(Error(EGL_BAD_MATCH)); + thread->setError(EglBadMatch()); return EGL_FALSE; } - gl::Context *context = GetGlobalContext(); + gl::Context *context = thread->getContext(); if (context) { gl::Texture *textureObject = context->getTargetTexture(GL_TEXTURE_2D); - ASSERT(textureObject != NULL); + ASSERT(textureObject != nullptr); if (textureObject->getImmutableFormat()) { - SetGlobalError(Error(EGL_BAD_MATCH)); + thread->setError(EglBadMatch()); return EGL_FALSE; } - error = eglSurface->bindTexImage(textureObject, buffer); + error = eglSurface->bindTexImage(context, textureObject, buffer); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + EGLint value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)", + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint " + "value = %d)", dpy, surface, attribute, value); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = static_cast(surface); + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); - Error error = ValidateSurface(display, eglSurface); + Error error = ValidateSurfaceAttrib(display, eglSurface, attribute, value); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - UNIMPLEMENTED(); // FIXME + SetSurfaceAttrib(eglSurface, attribute, value); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, + surface, buffer); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); - Surface *eglSurface = static_cast(surface); + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (buffer != EGL_BACK_BUFFER) { - SetGlobalError(Error(EGL_BAD_PARAMETER)); + thread->setError(EglBadParameter()); return EGL_FALSE; } if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) { - SetGlobalError(Error(EGL_BAD_MATCH)); + thread->setError(EglBadMatch()); return EGL_FALSE; } @@ -980,105 +846,116 @@ EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLin if (texture) { - error = eglSurface->releaseTexImage(buffer); + error = eglSurface->releaseTexImage(thread->getContext(), buffer); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval); + Thread *thread = GetCurrentThread(); - Display *display = static_cast(dpy); + Display *display = static_cast(dpy); Error error = ValidateDisplay(display); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - Surface *draw_surface = static_cast(GetGlobalDrawSurface()); + Surface *draw_surface = static_cast(thread->getCurrentDrawSurface()); - if (draw_surface == NULL) + if (draw_surface == nullptr) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } const egl::Config *surfaceConfig = draw_surface->getConfig(); - EGLint clampedInterval = std::min(std::max(interval, surfaceConfig->minSwapInterval), surfaceConfig->maxSwapInterval); + EGLint clampedInterval = std::min(std::max(interval, surfaceConfig->minSwapInterval), + surfaceConfig->maxSwapInterval); draw_surface->setSwapInterval(clampedInterval); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } - // EGL 1.2 EGLBoolean EGLAPIENTRY BindAPI(EGLenum api) { EVENT("(EGLenum api = 0x%X)", api); + Thread *thread = GetCurrentThread(); switch (api) { - case EGL_OPENGL_API: - case EGL_OPENVG_API: - SetGlobalError(Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; // Not supported by this implementation - case EGL_OPENGL_ES_API: - break; - default: - SetGlobalError(Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; + case EGL_OPENGL_API: + case EGL_OPENVG_API: + thread->setError(EglBadParameter()); + return EGL_FALSE; // Not supported by this implementation + case EGL_OPENGL_ES_API: + break; + default: + thread->setError(EglBadParameter()); + return EGL_FALSE; } - SetGlobalAPI(api); + thread->setAPI(api); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLenum EGLAPIENTRY QueryAPI(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - EGLenum API = GetGlobalAPI(); + EGLenum API = thread->getAPI(); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return API; } -EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, + EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, " - "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", - dpy, buftype, buffer, config, attrib_list); - - Display *display = static_cast(dpy); - Config *configuration = static_cast(config); - AttributeMap attributes(attrib_list); - - Error error = ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, " + "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", + dpy, buftype, buffer, config, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); + + Error error = + ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } egl::Surface *surface = nullptr; - error = display->createPbufferFromClientBuffer(configuration, buffer, attributes, &surface); + error = display->createPbufferFromClientBuffer(configuration, buftype, buffer, attributes, + &surface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_SURFACE; } @@ -1088,34 +965,36 @@ EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buf EGLBoolean EGLAPIENTRY ReleaseThread(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); MakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } EGLBoolean EGLAPIENTRY WaitClient(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - Display *display = GetGlobalDisplay(); + Display *display = thread->getCurrentDisplay(); Error error = ValidateDisplay(display); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - error = display->waitClient(); + error = display->waitClient(thread->getContext()); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } @@ -1123,540 +1002,185 @@ EGLBoolean EGLAPIENTRY WaitClient(void) EGLContext EGLAPIENTRY GetCurrentContext(void) { EVENT("()"); + Thread *thread = GetCurrentThread(); - gl::Context *context = GetGlobalContext(); + gl::Context *context = thread->getContext(); - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return static_cast(context); } // EGL 1.5 EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum type = 0x%X, const EGLint* attrib_list = 0x%0.8p)", dpy, type, attrib_list); + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum type = 0x%X, const EGLint* attrib_list = 0x%0.8p)", + dpy, type, attrib_list); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglCreateSync unimplemented."); return EGL_NO_SYNC; } EGLBoolean EGLAPIENTRY DestroySync(EGLDisplay dpy, EGLSync sync) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p)", dpy, sync); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglDestroySync unimplemented."); return EGL_FALSE; } EGLint EGLAPIENTRY ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X, EGLTime timeout = %d)", dpy, sync, flags, timeout); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X, EGLTime timeout = " + "%d)", + dpy, sync, flags, timeout); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglClientWaitSync unimplemented."); return 0; } -EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) +EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, + EGLSync sync, + EGLint attribute, + EGLAttrib *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint attribute = 0x%X, EGLAttrib *value = 0x%0.8p)", dpy, sync, attribute, value); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint attribute = 0x%X, EGLAttrib " + "*value = 0x%0.8p)", + dpy, sync, attribute, value); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglSyncAttrib unimplemented."); return EGL_FALSE; } -EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) +EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, + EGLContext ctx, + EGLenum target, + EGLClientBuffer buffer, + const EGLAttrib *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); + 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); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglCreateImage unimplemented."); return EGL_NO_IMAGE; } EGLBoolean EGLAPIENTRY DestroyImage(EGLDisplay dpy, EGLImage image) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglDestroyImage unimplemented."); return EGL_FALSE; } -EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) +EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, + void *native_display, + const EGLAttrib *attrib_list) { - EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", - platform, native_display, attrib_list); + EVENT( + "(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = " + "0x%0.8p)", + platform, native_display, attrib_list); + Thread *thread = GetCurrentThread(); - UNIMPLEMENTED(); - return EGL_NO_DISPLAY; + Error err = ValidateGetPlatformDisplay(platform, native_display, attrib_list); + thread->setError(err); + if (err.isError()) + { + return EGL_NO_DISPLAY; + } + + const auto &attribMap = AttributeMap::CreateFromAttribArray(attrib_list); + if (platform == EGL_PLATFORM_ANGLE_ANGLE) + { + return Display::GetDisplayFromNativeDisplay( + gl::bitCast(native_display), attribMap); + } + else if (platform == EGL_PLATFORM_DEVICE_EXT) + { + Device *eglDevice = reinterpret_cast(native_display); + return Display::GetDisplayFromDevice(eglDevice, attribMap); + } + else + { + UNREACHABLE(); + return EGL_NO_DISPLAY; + } } -EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) +EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, + EGLConfig config, + void *native_window, + const EGLAttrib *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_window = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", - dpy, config, native_window, attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_window = 0x%0.8p, " + "const EGLint* attrib_list = 0x%0.8p)", + dpy, config, native_window, attrib_list); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglCreatePlatformWindowSurface unimplemented."); return EGL_NO_SURFACE; } -EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) +EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, + EGLConfig config, + void *native_pixmap, + const EGLAttrib *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_pixmap = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", - dpy, config, native_pixmap, attrib_list); + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_pixmap = 0x%0.8p, " + "const EGLint* attrib_list = 0x%0.8p)", + dpy, config, native_pixmap, attrib_list); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglCreatePlatformPixmapSurface unimplemented."); return EGL_NO_SURFACE; } EGLBoolean EGLAPIENTRY WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X)", dpy, sync, flags); + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X)", dpy, sync, + flags); + Thread *thread = GetCurrentThread(); UNIMPLEMENTED(); + thread->setError(EglBadDisplay() << "eglWaitSync unimplemented."); return EGL_FALSE; } __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname) { EVENT("(const char *procname = \"%s\")", procname); + Thread *thread = GetCurrentThread(); - 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 ProcAddressMap procAddressMap = generateProcAddressMap(); - - auto iter = procAddressMap.find(procname); - if (iter != procAddressMap.end()) - { - return iter->second; - } - else + ProcEntry *entry = + std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc); + + thread->setError(NoError()); + + if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0) { return nullptr; } -} + return entry->second; +} } 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 6c7e2ffc3d..ee8cdb94dc 100644 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp @@ -9,9 +9,12 @@ #include "libGLESv2/entry_points_egl_ext.h" #include "libGLESv2/global_state.h" +#include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Device.h" #include "libANGLE/Surface.h" +#include "libANGLE/Stream.h" +#include "libANGLE/Thread.h" #include "libANGLE/validationEGL.h" #include "common/debug.h" @@ -24,6 +27,7 @@ EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surfa { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)", dpy, surface, attribute, value); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); Surface *eglSurface = static_cast(surface); @@ -31,19 +35,19 @@ EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surfa Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } if (!display->getExtensions().querySurfacePointer) { - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } @@ -55,24 +59,24 @@ EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surfa case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: if (!display->getExtensions().surfaceD3DTexture2DShareHandle) { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + thread->setError(EglBadAttribute()); return EGL_FALSE; } break; case EGL_DXGI_KEYED_MUTEX_ANGLE: if (!display->getExtensions().keyedMutex) { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + thread->setError(EglBadAttribute()); return EGL_FALSE; } break; default: - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; + thread->setError(EglBadAttribute()); + return EGL_FALSE; } error = eglSurface->querySurfacePointerANGLE(attribute, value); - SetGlobalError(error); + thread->setError(error); return (error.isError() ? EGL_FALSE : EGL_TRUE); } @@ -81,10 +85,11 @@ EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surfa EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, EGLint width = %d, EGLint height = %d)", dpy, surface, x, y, width, height); + Thread *thread = GetCurrentThread(); if (x < 0 || y < 0 || width < 0 || height < 0) { - SetGlobalError(Error(EGL_BAD_PARAMETER)); + thread->setError(EglBadParameter()); return EGL_FALSE; } @@ -94,39 +99,38 @@ EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLin Error error = ValidateSurface(display, eglSurface); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - if (display->isDeviceLost()) + if (display->testDeviceLost()) { - SetGlobalError(Error(EGL_CONTEXT_LOST)); + thread->setError(EglContextLost()); return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - SetGlobalError(Error(EGL_BAD_SURFACE)); + thread->setError(EglBadSurface()); return EGL_FALSE; } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: Allow this entry point as a workaround if (!display->getExtensions().postSubBuffer) { // Spec is not clear about how this should be handled. - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } -#endif - error = eglSurface->postSubBuffer(x, y, width, height); + // TODO(jmadill): Validate Surface is bound to the thread. + error = eglSurface->postSubBuffer(thread->getContext(), x, y, width, height); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return EGL_TRUE; } @@ -135,215 +139,25 @@ EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_disp { EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", platform, native_display, attrib_list); + Thread *thread = GetCurrentThread(); - const ClientExtensions &clientExtensions = Display::getClientExtensions(); - - switch (platform) + Error err = ValidateGetPlatformDisplayEXT(platform, native_display, attrib_list); + thread->setError(err); + if (err.isError()) { - case EGL_PLATFORM_ANGLE_ANGLE: - if (!clientExtensions.platformANGLE) - { - SetGlobalError(Error(EGL_BAD_PARAMETER)); - 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; } + const auto &attribMap = AttributeMap::CreateFromIntArray(attrib_list); if (platform == EGL_PLATFORM_ANGLE_ANGLE) { - 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) - { - for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2) - { - switch (curAttrib[0]) - { - 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_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; - - 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; - - default: - break; - } - } - } - - if (!majorVersionSpecified && minorVersionSpecified) - { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_NO_DISPLAY; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - SetGlobalError(Error(EGL_SUCCESS)); - return Display::GetDisplayFromAttribs(native_display, AttributeMap(attrib_list)); + return Display::GetDisplayFromNativeDisplay( + gl::bitCast(native_display), attribMap); } 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); + return Display::GetDisplayFromDevice(eglDevice, attribMap); } else { @@ -357,11 +171,12 @@ EGLBoolean EGLAPIENTRY QueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribut { EVENT("(EGLDeviceEXT device = 0x%0.8p, EGLint attribute = %d, EGLAttrib *value = 0x%0.8p)", device, attribute, value); + Thread *thread = GetCurrentThread(); Device *dev = static_cast(device); if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev)) { - SetGlobalError(Error(EGL_BAD_ACCESS)); + thread->setError(EglBadAccess()); return EGL_FALSE; } @@ -370,13 +185,13 @@ EGLBoolean EGLAPIENTRY QueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribut 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")); + thread->setError(EglBadAccess() << "Device wasn't created using eglCreateDeviceANGLE, " + "and the Display that created it doesn't support " + "device querying"); return EGL_FALSE; } - Error error(EGL_SUCCESS); + Error error(NoError()); // validate the attribute parameter switch (attribute) @@ -385,17 +200,17 @@ EGLBoolean EGLAPIENTRY QueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribut case EGL_D3D9_DEVICE_ANGLE: if (!dev->getExtensions().deviceD3D || dev->getType() != attribute) { - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + thread->setError(EglBadAttribute()); return EGL_FALSE; } error = dev->getDevice(value); break; default: - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; + thread->setError(EglBadAttribute()); + return EGL_FALSE; } - SetGlobalError(error); + thread->setError(error); return (error.isError() ? EGL_FALSE : EGL_TRUE); } @@ -404,11 +219,12 @@ const char * EGLAPIENTRY QueryDeviceStringEXT(EGLDeviceEXT device, EGLint name) { EVENT("(EGLDeviceEXT device = 0x%0.8p, EGLint name = %d)", device, name); + Thread *thread = GetCurrentThread(); Device *dev = static_cast(device); if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev)) { - SetGlobalError(Error(EGL_BAD_DEVICE_EXT)); + thread->setError(EglBadDevice()); return nullptr; } @@ -419,11 +235,11 @@ const char * EGLAPIENTRY QueryDeviceStringEXT(EGLDeviceEXT device, EGLint name) result = dev->getExtensionString().c_str(); break; default: - SetGlobalError(Error(EGL_BAD_DEVICE_EXT)); - return nullptr; + thread->setError(EglBadDevice()); + return nullptr; } - SetGlobalError(Error(EGL_SUCCESS)); + thread->setError(NoError()); return result; } @@ -432,13 +248,20 @@ EGLBoolean EGLAPIENTRY QueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, E { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint attribute = %d, EGLAttrib *value = 0x%0.8p)", dpy, attribute, value); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); - Error error(EGL_SUCCESS); + + Error error = ValidateDisplay(display); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } if (!display->getExtensions().deviceQuery) { - SetGlobalError(Error(EGL_BAD_ACCESS)); + thread->setError(EglBadAccess()); return EGL_FALSE; } @@ -450,11 +273,11 @@ EGLBoolean EGLAPIENTRY QueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, E break; default: - SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; + thread->setError(EglBadAttribute()); + return EGL_FALSE; } - SetGlobalError(error); + thread->setError(error); return (error.isError() ? EGL_FALSE : EGL_TRUE); } @@ -468,23 +291,24 @@ ANGLE_EXPORT EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, "(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); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); gl::Context *context = static_cast(ctx); - AttributeMap attributes(attrib_list); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); Error error = ValidateCreateImageKHR(display, context, target, buffer, attributes); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_IMAGE; } Image *image = nullptr; - error = display->createImage(context, target, buffer, attributes, &image); + error = display->createImage(context, target, buffer, attributes, &image); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_IMAGE; } @@ -494,6 +318,7 @@ ANGLE_EXPORT EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy, ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) { EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image); + Thread *thread = GetCurrentThread(); Display *display = static_cast(dpy); Image *img = static_cast(image); @@ -501,7 +326,7 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyImageKHR(EGLDisplay dpy, EGLImageKHR Error error = ValidateDestroyImageKHR(display, img); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } @@ -518,11 +343,12 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type, "(EGLint device_type = %d, void* native_device = 0x%0.8p, const EGLAttrib* attrib_list = " "0x%0.8p)", device_type, native_device, attrib_list); + Thread *thread = GetCurrentThread(); Error error = ValidateCreateDeviceANGLE(device_type, native_device, attrib_list); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_NO_DEVICE_EXT; } @@ -531,7 +357,7 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type, if (error.isError()) { ASSERT(device == nullptr); - SetGlobalError(error); + thread->setError(error); return EGL_NO_DEVICE_EXT; } @@ -541,13 +367,14 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type, ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device) { EVENT("(EGLDeviceEXT device = 0x%0.8p)", device); + Thread *thread = GetCurrentThread(); Device *dev = static_cast(device); Error error = ValidateReleaseDeviceANGLE(dev); if (error.isError()) { - SetGlobalError(error); + thread->setError(error); return EGL_FALSE; } @@ -555,4 +382,475 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device) return EGL_TRUE; } + +// EGL_KHR_stream +EGLStreamKHR EGLAPIENTRY CreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLAttrib* attrib_list = 0x%0.8p)", dpy, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + AttributeMap attributes = AttributeMap::CreateFromIntArray(attrib_list); + + Error error = ValidateCreateStreamKHR(display, attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_NO_STREAM_KHR; + } + + Stream *stream; + error = display->createStream(attributes, &stream); + if (error.isError()) + { + thread->setError(error); + return EGL_NO_STREAM_KHR; + } + + thread->setError(error); + return static_cast(stream); +} + +EGLBoolean EGLAPIENTRY DestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR = 0x%0.8p)", dpy, stream); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + + Error error = ValidateDestroyStreamKHR(display, streamObject); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + display->destroyStream(streamObject); + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY StreamAttribKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint value) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, " + "EGLint value = 0x%X)", + dpy, stream, attribute, value); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + + Error error = ValidateStreamAttribKHR(display, streamObject, attribute, value); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + switch (attribute) + { + case EGL_CONSUMER_LATENCY_USEC_KHR: + streamObject->setConsumerLatency(value); + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + streamObject->setConsumerAcquireTimeout(value); + break; + default: + UNREACHABLE(); + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY QueryStreamKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint *value) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, " + "EGLint value = 0x%0.8p)", + dpy, stream, attribute, value); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + + Error error = ValidateQueryStreamKHR(display, streamObject, attribute, value); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + switch (attribute) + { + case EGL_STREAM_STATE_KHR: + *value = streamObject->getState(); + break; + case EGL_CONSUMER_LATENCY_USEC_KHR: + *value = streamObject->getConsumerLatency(); + break; + case EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: + *value = streamObject->getConsumerAcquireTimeout(); + break; + default: + UNREACHABLE(); + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY QueryStreamu64KHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLuint64KHR *value) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, " + "EGLuint64KHR value = 0x%0.8p)", + dpy, stream, attribute, value); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + + Error error = ValidateQueryStreamu64KHR(display, streamObject, attribute, value); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + switch (attribute) + { + case EGL_PRODUCER_FRAME_KHR: + *value = streamObject->getProducerFrame(); + break; + case EGL_CONSUMER_FRAME_KHR: + *value = streamObject->getConsumerFrame(); + break; + default: + UNREACHABLE(); + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY StreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR = 0x%0.8p)", dpy, stream); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + gl::Context *context = gl::GetValidGlobalContext(); + + Error error = ValidateStreamConsumerGLTextureExternalKHR(display, context, streamObject); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->createConsumerGLTextureExternal(AttributeMap(), context); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; } + +EGLBoolean EGLAPIENTRY StreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR = 0x%0.8p)", dpy, stream); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + gl::Context *context = gl::GetValidGlobalContext(); + + Error error = ValidateStreamConsumerAcquireKHR(display, context, streamObject); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->consumerAcquire(context); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY StreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR = 0x%0.8p)", dpy, stream); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + gl::Context *context = gl::GetValidGlobalContext(); + + Error error = ValidateStreamConsumerReleaseKHR(display, context, streamObject); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->consumerRelease(context); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY StreamConsumerGLTextureExternalAttribsNV(EGLDisplay dpy, + EGLStreamKHR stream, + const EGLAttrib *attrib_list) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLAttrib attrib_list = 0x%0.8p", + dpy, stream, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + gl::Context *context = gl::GetValidGlobalContext(); + AttributeMap attributes = AttributeMap::CreateFromAttribArray(attrib_list); + + Error error = ValidateStreamConsumerGLTextureExternalAttribsNV(display, context, streamObject, + attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->createConsumerGLTextureExternal(attributes, context); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY CreateStreamProducerD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + const EGLAttrib *attrib_list) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLAttrib attrib_list = 0x%0.8p", + dpy, stream, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + AttributeMap attributes = AttributeMap::CreateFromAttribArray(attrib_list); + + Error error = + ValidateCreateStreamProducerD3DTextureNV12ANGLE(display, streamObject, attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->createProducerD3D11TextureNV12(attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY StreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + void *texture, + const EGLAttrib *attrib_list) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, void* texture = 0x%0.8p, " + "EGLAttrib attrib_list = 0x%0.8p", + dpy, stream, texture, attrib_list); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Stream *streamObject = static_cast(stream); + AttributeMap attributes = AttributeMap::CreateFromAttribArray(attrib_list); + + Error error = ValidateStreamPostD3DTextureNV12ANGLE(display, streamObject, texture, attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = streamObject->postD3D11NV12Texture(texture, attributes); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY GetSyncValuesCHROMIUM(EGLDisplay dpy, + EGLSurface surface, + EGLuint64KHR *ust, + EGLuint64KHR *msc, + EGLuint64KHR *sbc) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLuint64KHR* ust = 0x%0.8p, " + "EGLuint64KHR* msc = 0x%0.8p, EGLuint64KHR* sbc = 0x%0.8p", + dpy, surface, ust, msc, sbc); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateGetSyncValuesCHROMIUM(display, eglSurface, ust, msc, sbc); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = eglSurface->getSyncValues(ust, msc, sbc); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + thread->setError(error); + return EGL_TRUE; +} + +ANGLE_EXPORT EGLBoolean SwapBuffersWithDamageEXT(EGLDisplay dpy, + EGLSurface surface, + EGLint *rects, + EGLint n_rects) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint *rects = 0x%0.8p, EGLint " + "n_rects = %d)", + dpy, surface, rects, n_rects); + Thread *thread = GetCurrentThread(); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSwapBuffersWithDamageEXT(display, eglSurface, rects, n_rects); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + error = eglSurface->swapWithDamage(thread->getContext(), rects, n_rects); + if (error.isError()) + { + thread->setError(error); + return EGL_FALSE; + } + + return EGL_TRUE; +} + +EGLint EGLAPIENTRY ProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum attrib = 0x%X)", dpy, attrib); + + Display *display = static_cast(dpy); + Thread *thread = GetCurrentThread(); + + ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheGetAttribANGLE(display, attrib), 0); + + return display->programCacheGetAttrib(attrib); +} + +void EGLAPIENTRY ProgramCacheQueryANGLE(EGLDisplay dpy, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, EGLint index = %d, void *key = 0x%0.8p, EGLint *keysize = " + "0x%0.8p, void *binary = 0x%0.8p, EGLint *size = 0x%0.8p)", + dpy, index, key, keysize, binary, binarysize); + + Display *display = static_cast(dpy); + Thread *thread = GetCurrentThread(); + + ANGLE_EGL_TRY(thread, + ValidateProgramCacheQueryANGLE(display, index, key, keysize, binary, binarysize)); + + ANGLE_EGL_TRY(thread, display->programCacheQuery(index, key, keysize, binary, binarysize)); +} + +void EGLAPIENTRY ProgramCachePopulateANGLE(EGLDisplay dpy, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize) +{ + EVENT( + "(EGLDisplay dpy = 0x%0.8p, void *key = 0x%0.8p, EGLint keysize = %d, void *binary = " + "0x%0.8p, EGLint *size = 0x%0.8p)", + dpy, key, keysize, binary, binarysize); + + Display *display = static_cast(dpy); + Thread *thread = GetCurrentThread(); + + ANGLE_EGL_TRY(thread, + ValidateProgramCachePopulateANGLE(display, key, keysize, binary, binarysize)); + + ANGLE_EGL_TRY(thread, display->programCachePopulate(key, keysize, binary, binarysize)); +} + +EGLint EGLAPIENTRY ProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint limit = %d, EGLenum mode = 0x%X)", dpy, limit, mode); + + Display *display = static_cast(dpy); + Thread *thread = GetCurrentThread(); + + ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheResizeANGLE(display, limit, mode), 0); + + return display->programCacheResize(limit, mode); +} + +} // namespace egl 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 d64fa6e483..3cde6ec9c6 100644 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h @@ -43,6 +43,71 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list); ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device); -} + +// EGL_KHR_stream +ANGLE_EXPORT EGLStreamKHR EGLAPIENTRY CreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamAttribKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint value); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryStreamKHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLint *value); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryStreamu64KHR(EGLDisplay dpy, + EGLStreamKHR stream, + EGLenum attribute, + EGLuint64KHR *value); + +// EGL_KHR_stream_consumer_gltexture +ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamConsumerGLTextureExternalKHR(EGLDisplay dpy, + EGLStreamKHR stream); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY +StreamConsumerGLTextureExternalAttribsNV(EGLDisplay dpy, + EGLStreamKHR stream, + const EGLAttrib *attrib_list); + +// EGL_ANGLE_stream_producer_d3d_texture_nv12 +ANGLE_EXPORT EGLBoolean EGLAPIENTRY +CreateStreamProducerD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, + EGLStreamKHR stream, + void *texture, + const EGLAttrib *attrib_list); + +// EGL_CHROMIUM_get_sync_values +ANGLE_EXPORT EGLBoolean EGLAPIENTRY GetSyncValuesCHROMIUM(EGLDisplay dpy, + EGLSurface surface, + EGLuint64KHR *ust, + EGLuint64KHR *msc, + EGLuint64KHR *sbc); + +// EGL_EXT_swap_buffers_with_damage +ANGLE_EXPORT EGLBoolean SwapBuffersWithDamageEXT(EGLDisplay dpy, + EGLSurface surface, + EGLint *rects, + EGLint n_rects); + +// +ANGLE_EXPORT EGLint EGLAPIENTRY ProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib); +ANGLE_EXPORT void EGLAPIENTRY ProgramCacheQueryANGLE(EGLDisplay dpy, + EGLint index, + void *key, + EGLint *keysize, + void *binary, + EGLint *binarysize); +ANGLE_EXPORT void EGLAPIENTRY ProgramCachePopulateANGLE(EGLDisplay dpy, + const void *key, + EGLint keysize, + const void *binary, + EGLint binarysize); +ANGLE_EXPORT EGLint EGLAPIENTRY ProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode); + +} // namespace egl #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 deleted file mode 100644 index 336b320ba5..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp +++ /dev/null @@ -1,4155 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_2_0.cpp : Implements the GLES 2.0 entry points. - -#include "libGLESv2/entry_points_gles_2_0.h" -#include "libGLESv2/global_state.h" - -#include "libANGLE/formatutils.h" -#include "libANGLE/Buffer.h" -#include "libANGLE/Compiler.h" -#include "libANGLE/Context.h" -#include "libANGLE/Error.h" -#include "libANGLE/Framebuffer.h" -#include "libANGLE/Renderbuffer.h" -#include "libANGLE/Shader.h" -#include "libANGLE/Program.h" -#include "libANGLE/Texture.h" -#include "libANGLE/VertexArray.h" -#include "libANGLE/VertexAttribute.h" -#include "libANGLE/FramebufferAttachment.h" - -#include "libANGLE/validationES.h" -#include "libANGLE/validationES2.h" -#include "libANGLE/validationES3.h" -#include "libANGLE/queryconversions.h" - -#include "common/debug.h" -#include "common/utilities.h" -#include "common/version.h" - -namespace gl -{ - -void GL_APIENTRY ActiveTexture(GLenum texture) -{ - EVENT("(GLenum texture = 0x%X)", texture); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setActiveSampler(texture - GL_TEXTURE0); - } -} - -void GL_APIENTRY AttachShader(GLuint program, GLuint shader) -{ - EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - - if (!programObject->attachShader(shaderObject)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - } -} - -void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar* name) -{ - EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (strncmp(name, "gl_", 3) == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - programObject->bindAttributeLocation(index, name); - } -} - -void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer) -{ - EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_ARRAY_BUFFER: - context->bindArrayBuffer(buffer); - return; - case GL_ELEMENT_ARRAY_BUFFER: - context->bindElementArrayBuffer(buffer); - return; - case GL_COPY_READ_BUFFER: - context->bindCopyReadBuffer(buffer); - return; - case GL_COPY_WRITE_BUFFER: - context->bindCopyWriteBuffer(buffer); - return; - case GL_PIXEL_PACK_BUFFER: - context->bindPixelPackBuffer(buffer); - return; - case GL_PIXEL_UNPACK_BUFFER: - context->bindPixelUnpackBuffer(buffer); - return; - case GL_UNIFORM_BUFFER: - context->bindGenericUniformBuffer(buffer); - return; - case GL_TRANSFORM_FEEDBACK_BUFFER: - context->bindGenericTransformFeedbackBuffer(buffer); - return; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer) -{ - EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindReadFramebuffer(framebuffer); - } - - if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindDrawFramebuffer(framebuffer); - } - } -} - -void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer) -{ - EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (target != GL_RENDERBUFFER) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->bindRenderbuffer(renderbuffer); - } -} - -void GL_APIENTRY BindTexture(GLenum target, GLuint texture) -{ - EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); - - Context *context = GetValidGlobalContext(); - if (context) - { - Texture *textureObject = context->getTexture(texture); - - if (textureObject && textureObject->getTarget() != target && texture != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - break; - - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->bindTexture(target, texture); - } -} - -void GL_APIENTRY BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", - red, green, blue, alpha); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setBlendColor(clamp01(red), clamp01(green), clamp01(blue), clamp01(alpha)); - } -} - -void GL_APIENTRY BlendEquation(GLenum mode) -{ - BlendEquationSeparate(mode, mode); -} - -void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) -{ - EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (modeRGB) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - case GL_MIN: - case GL_MAX: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (modeAlpha) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - case GL_MIN: - case GL_MAX: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setBlendEquation(modeRGB, modeAlpha); - } -} - -void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor) -{ - BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); -} - -void GL_APIENTRY BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) -{ - EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", - srcRGB, dstRGB, srcAlpha, dstAlpha); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (srcRGB) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - case GL_SRC_ALPHA_SATURATE: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (dstRGB) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - break; - - case GL_SRC_ALPHA_SATURATE: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (srcAlpha) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - case GL_SRC_ALPHA_SATURATE: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (dstAlpha) - { - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - break; - - case GL_SRC_ALPHA_SATURATE: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - 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); - - 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); - } -} - -void GL_APIENTRY BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) -{ - EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", - target, size, data, usage); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (size < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (usage) - { - case GL_STREAM_DRAW: - case GL_STATIC_DRAW: - case GL_DYNAMIC_DRAW: - break; - - case GL_STREAM_READ: - case GL_STREAM_COPY: - case GL_STATIC_READ: - case GL_STATIC_COPY: - case GL_DYNAMIC_READ: - case GL_DYNAMIC_COPY: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - Error error = buffer->bufferData(data, size, usage); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) -{ - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", - target, offset, size, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (size < 0 || offset < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (buffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // Check for possible overflow of size + offset - if (!rx::IsUnsignedAdditionSafe(size, offset)) - { - context->recordError(Error(GL_OUT_OF_MEMORY)); - return; - } - - if (size + offset > buffer->getSize()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (data == NULL) - { - return; - } - - Error error = buffer->bufferSubData(data, size, offset); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target) -{ - EVENT("(GLenum target = 0x%X)", target); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return 0; - } - - Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - return framebuffer->checkStatus(context->getData()); - } - - return 0; -} - -void GL_APIENTRY Clear(GLbitfield mask) -{ - EVENT("(GLbitfield mask = 0x%X)", mask); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && !ValidateClear(context, mask)) - { - return; - } - - context->clear(mask); - } -} - -void GL_APIENTRY ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", - red, green, blue, alpha); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setColorClearValue(red, green, blue, alpha); - } -} - -void GL_APIENTRY ClearDepthf(GLclampf depth) -{ - EVENT("(GLclampf depth = %f)", depth); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setDepthClearValue(depth); - } -} - -void GL_APIENTRY ClearStencil(GLint s) -{ - EVENT("(GLint s = %d)", s); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setStencilClearValue(s); - } -} - -void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) -{ - EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", - red, green, blue, alpha); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); - } -} - -void GL_APIENTRY CompileShader(GLuint shader) -{ - EVENT("(GLuint shader = %d)", shader); - - Context *context = GetValidGlobalContext(); - if (context) - { - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - shaderObject->compile(context->getCompiler()); - } -} - -void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid* data) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " - "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", - target, level, internalformat, width, height, border, imageSize, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, internalformat, true, false, - 0, 0, width, height, border, GL_NONE, GL_NONE, data)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImage2DParameters(context, target, level, internalformat, true, false, 0, - 0, 0, width, height, 1, border, GL_NONE, GL_NONE, - data)) - { - 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; - } - - Extents size(width, height, 1); - Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - Error error = - texture->setCompressedImage(context, target, level, internalformat, size, imageSize, - reinterpret_cast(data)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid* data) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, " - "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", - target, level, xoffset, yoffset, width, height, format, imageSize, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, - xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImage2DParameters(context, target, level, GL_NONE, true, true, xoffset, - yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, - data)) - { - return; - } - - const InternalFormat &formatInfo = GetInternalFormatInfo(format); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Box area(xoffset, yoffset, 0, width, height, 1); - Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - Error error = - texture->setCompressedSubImage(context, target, level, area, format, imageSize, - reinterpret_cast(data)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " - "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", - target, level, internalformat, x, y, width, height, border); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateCopyTexImage2D(context, target, level, internalformat, x, y, width, height, - border)) - { - return; - } - context->copyTexImage2D(target, level, internalformat, x, y, width, height, border); - } -} - -void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", - target, level, xoffset, yoffset, x, y, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateCopyTexSubImage2D(context, target, level, xoffset, yoffset, x, y, width, - height)) - { - return; - } - - context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); - } -} - -GLuint GL_APIENTRY CreateProgram(void) -{ - EVENT("()"); - - Context *context = GetValidGlobalContext(); - if (context) - { - return context->createProgram(); - } - - return 0; -} - -GLuint GL_APIENTRY CreateShader(GLenum type) -{ - EVENT("(GLenum type = 0x%X)", type); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (type) - { - case GL_FRAGMENT_SHADER: - case GL_VERTEX_SHADER: - return context->createShader(type); - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return 0; - } - } - - return 0; -} - -void GL_APIENTRY CullFace(GLenum mode) -{ - EVENT("(GLenum mode = 0x%X)", mode); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (mode) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setCullMode(mode); - } -} - -void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint* buffers) -{ - EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteBuffer(buffers[i]); - } - } -} - -void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) -{ - EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - if (framebuffers[i] != 0) - { - context->deleteFramebuffer(framebuffers[i]); - } - } - } -} - -void GL_APIENTRY DeleteProgram(GLuint program) -{ - EVENT("(GLuint program = %d)", program); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (program == 0) - { - return; - } - - if (!context->getProgram(program)) - { - if(context->getShader(program)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - } - - context->deleteProgram(program); - } -} - -void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) -{ - EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteRenderbuffer(renderbuffers[i]); - } - } -} - -void GL_APIENTRY DeleteShader(GLuint shader) -{ - EVENT("(GLuint shader = %d)", shader); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (shader == 0) - { - return; - } - - if (!context->getShader(shader)) - { - if(context->getProgram(shader)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - } - - context->deleteShader(shader); - } -} - -void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint* textures) -{ - EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - if (textures[i] != 0) - { - context->deleteTexture(textures[i]); - } - } - } -} - -void GL_APIENTRY DepthFunc(GLenum func) -{ - EVENT("(GLenum func = 0x%X)", func); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (func) - { - case GL_NEVER: - case GL_ALWAYS: - case GL_LESS: - case GL_LEQUAL: - case GL_EQUAL: - case GL_GREATER: - case GL_GEQUAL: - case GL_NOTEQUAL: - context->getState().setDepthFunc(func); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY DepthMask(GLboolean flag) -{ - EVENT("(GLboolean flag = %u)", flag); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setDepthMask(flag != GL_FALSE); - } -} - -void GL_APIENTRY DepthRangef(GLclampf zNear, GLclampf zFar) -{ - EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setDepthRange(zNear, zFar); - } -} - -void GL_APIENTRY DetachShader(GLuint program, GLuint shader) -{ - EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - - if (!programObject->detachShader(shaderObject)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - } -} - -void GL_APIENTRY Disable(GLenum cap) -{ - EVENT("(GLenum cap = 0x%X)", cap); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setEnableFeature(cap, false); - } -} - -void GL_APIENTRY DisableVertexAttribArray(GLuint index) -{ - EVENT("(GLuint index = %d)", index); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setEnableVertexAttribArray(index, false); - } -} - -void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count) -{ - EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateDrawArrays(context, mode, first, count, 0)) - { - return; - } - - Error error = context->drawArrays(mode, first, count); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) -{ - EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", - mode, count, type, indices); - - Context *context = GetValidGlobalContext(); - if (context) - { - IndexRange indexRange; - if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange)) - { - return; - } - - Error error = context->drawElements(mode, count, type, indices, indexRange); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY Enable(GLenum cap) -{ - EVENT("(GLenum cap = 0x%X)", cap); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(Error(GL_INVALID_ENUM)); - 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); - } -} - -void GL_APIENTRY EnableVertexAttribArray(GLuint index) -{ - EVENT("(GLuint index = %d)", index); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setEnableVertexAttribArray(index, true); - } -} - -void GL_APIENTRY Finish(void) -{ - EVENT("()"); - - Context *context = GetValidGlobalContext(); - if (context) - { - Error error = context->finish(); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY Flush(void) -{ - EVENT("()"); - - Context *context = GetValidGlobalContext(); - if (context) - { - Error error = context->flush(); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) -{ - EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " - "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateFramebufferRenderbuffer(context, target, attachment, renderbuffertarget, - renderbuffer)) - { - return; - } - - context->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); - } -} - -void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) -{ - EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " - "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) - { - return; - } - - context->framebufferTexture2D(target, attachment, textarget, texture, level); - } -} - -void GL_APIENTRY FrontFace(GLenum mode) -{ - EVENT("(GLenum mode = 0x%X)", mode); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (mode) - { - case GL_CW: - case GL_CCW: - context->getState().setFrontFace(mode); - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GenBuffers(GLsizei n, GLuint* buffers) -{ - EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - buffers[i] = context->createBuffer(); - } - } -} - -void GL_APIENTRY GenerateMipmap(GLenum target) -{ - EVENT("(GLenum target = 0x%X)", target); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidTextureTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Texture *texture = context->getTargetTexture(target); - - if (texture == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; - GLenum internalFormat = texture->getInternalFormat(baseTarget, 0); - const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat); - - // GenerateMipmap should not generate an INVALID_OPERATION for textures created with - // unsized formats or that are color renderable and filterable. Since we do not track if - // the texture was created with sized or unsized format (only sized formats are stored), - // it is not possible to make sure the the LUMA formats can generate mipmaps (they should - // be able to) because they aren't color renderable. Simply do a special case for LUMA - // textures since they're the only texture format that can be created with unsized formats - // that is not color renderable. New unsized formats are unlikely to be added, since ES2 - // was the last version to use add them. - bool isLUMA = internalFormat == GL_LUMINANCE8_EXT || - internalFormat == GL_LUMINANCE8_ALPHA8_EXT || - internalFormat == GL_ALPHA8_EXT; - - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable || - (!formatCaps.renderable && !isLUMA) || formatInfo.compressed) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // GL_EXT_sRGB does not support mipmap generation on sRGB textures - if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // Non-power of 2 ES2 check - 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)); - return; - } - - // Cube completeness check - if (target == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - Error error = texture->generateMipmaps(); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint* framebuffers) -{ - EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - framebuffers[i] = context->createFramebuffer(); - } - } -} - -void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint* renderbuffers) -{ - EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - renderbuffers[i] = context->createRenderbuffer(); - } - } -} - -void GL_APIENTRY GenTextures(GLsizei n, GLuint* textures) -{ - EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (n < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - textures[i] = context->createTexture(); - } - } -} - -void GL_APIENTRY GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) -{ - EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, " - "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)", - program, index, bufsize, length, size, type, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (index >= (GLuint)programObject->getActiveAttributeCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - programObject->getActiveAttribute(index, bufsize, length, size, type, name); - } -} - -void GL_APIENTRY GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) -{ - EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, " - "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", - program, index, bufsize, length, size, type, name); - - - Context *context = GetValidGlobalContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (index >= (GLuint)programObject->getActiveUniformCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - programObject->getActiveUniform(index, bufsize, length, size, type, name); - } -} - -void GL_APIENTRY GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) -{ - EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", - program, maxcount, count, shaders); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (maxcount < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - return programObject->getAttachedShaders(maxcount, count, shaders); - } -} - -GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name) -{ - EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return -1; - } - - if (!programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return -1; - } - - return programObject->getAttributeLocation(name); - } - - return -1; -} - -void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean* params) -{ - EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_BOOL) - { - context->getBooleanv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } -} - -void GL_APIENTRY GetBufferParameteriv(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 (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (!ValidBufferParameter(context, pname)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - // A null buffer means that "0" is bound to the requested buffer target - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (pname) - { - case GL_BUFFER_USAGE: - *params = static_cast(buffer->getUsage()); - break; - case GL_BUFFER_SIZE: - *params = clampCast(buffer->getSize()); - break; - 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: - *params = clampCast(buffer->getMapOffset()); - break; - case GL_BUFFER_MAP_LENGTH: - *params = clampCast(buffer->getMapLength()); - break; - default: UNREACHABLE(); break; - } - } -} - -GLenum GL_APIENTRY GetError(void) -{ - EVENT("()"); - - Context *context = GetGlobalContext(); - - if (context) - { - return context->getError(); - } - - return GL_NO_ERROR; -} - -void GL_APIENTRY GetFloatv(GLenum pname, GLfloat* params) -{ - EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_FLOAT) - { - context->getFloatv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } -} - -void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) -{ - EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - target, attachment, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - int clientVersion = context->getClientVersion(); - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - if (clientVersion < 3 && !context->getExtensions().sRGB) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: - if (clientVersion < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - // Determine if the attachment is a valid enum - switch (attachment) - { - case GL_BACK: - case GL_FRONT: - case GL_DEPTH: - case GL_STENCIL: - case GL_DEPTH_STENCIL_ATTACHMENT: - if (clientVersion < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - - default: - if (attachment < GL_COLOR_ATTACHMENT0_EXT || - (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - } - - const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (framebuffer->id() == 0) - { - if (clientVersion < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (attachment) - { - case GL_BACK: - case GL_DEPTH: - case GL_STENCIL: - break; - - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - } - else - { - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - // Valid attachment query - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - - case GL_DEPTH_STENCIL_ATTACHMENT: - if (framebuffer->hasValidDepthStencil()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - } - } - - const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); - if (attachmentObject) - { - ASSERT(attachmentObject->type() == GL_RENDERBUFFER || - attachmentObject->type() == GL_TEXTURE || - attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT); - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - *params = attachmentObject->type(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - if (attachmentObject->type() != GL_RENDERBUFFER && attachmentObject->type() != GL_TEXTURE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentObject->id(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - if (attachmentObject->type() != GL_TEXTURE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentObject->mipLevel(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: - if (attachmentObject->type() != GL_TEXTURE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentObject->cubeMapFace(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - *params = attachmentObject->getRedSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - *params = attachmentObject->getGreenSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - *params = attachmentObject->getBlueSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - *params = attachmentObject->getAlphaSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - *params = attachmentObject->getDepthSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - *params = attachmentObject->getStencilSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - *params = attachmentObject->getComponentType(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - *params = attachmentObject->getColorEncoding(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: - if (attachmentObject->type() != GL_TEXTURE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentObject->layer(); - break; - - default: - UNREACHABLE(); - break; - } - } - else - { - // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE - // is NONE, then querying any other pname will generate INVALID_ENUM. - - // ES 3.0.2 spec pg 235 states that if the attachment type is none, - // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an - // INVALID_OPERATION for all other pnames - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - *params = GL_NONE; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - if (clientVersion < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = 0; - break; - - default: - if (clientVersion < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - else - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - } - } - } -} - -void GL_APIENTRY GetIntegerv(GLenum pname, GLint* params) -{ - EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_INT) - { - context->getIntegerv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } -} - -void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params) -{ - EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (context->getClientVersion() < 3) - { - switch (pname) - { - case GL_ACTIVE_UNIFORM_BLOCKS: - case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: - 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; - } - } - - switch (pname) - { - case GL_DELETE_STATUS: - *params = programObject->isFlaggedForDeletion(); - return; - case GL_LINK_STATUS: - *params = programObject->isLinked(); - return; - case GL_VALIDATE_STATUS: - *params = programObject->isValidated(); - return; - case GL_INFO_LOG_LENGTH: - *params = programObject->getInfoLogLength(); - return; - case GL_ATTACHED_SHADERS: - *params = programObject->getAttachedShadersCount(); - return; - case GL_ACTIVE_ATTRIBUTES: - *params = programObject->getActiveAttributeCount(); - return; - case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: - *params = programObject->getActiveAttributeMaxLength(); - return; - case GL_ACTIVE_UNIFORMS: - *params = programObject->getActiveUniformCount(); - return; - case GL_ACTIVE_UNIFORM_MAX_LENGTH: - *params = programObject->getActiveUniformMaxLength(); - return; - case GL_PROGRAM_BINARY_LENGTH_OES: - *params = programObject->getBinaryLength(); - return; - case GL_ACTIVE_UNIFORM_BLOCKS: - *params = programObject->getActiveUniformBlockCount(); - return; - case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: - *params = programObject->getActiveUniformBlockMaxLength(); - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: - *params = programObject->getTransformFeedbackBufferMode(); - break; - case GL_TRANSFORM_FEEDBACK_VARYINGS: - *params = programObject->getTransformFeedbackVaryingCount(); - break; - 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)); - return; - } - } -} - -void GL_APIENTRY GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) -{ - EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", - program, bufsize, length, infolog); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - programObject->getInfoLog(bufsize, length, infolog); - } -} - -void GL_APIENTRY GetRenderbufferParameteriv(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 (target != GL_RENDERBUFFER) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (context->getState().getRenderbufferId() == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - Renderbuffer *renderbuffer = context->getRenderbuffer(context->getState().getRenderbufferId()); - - switch (pname) - { - case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; - case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; - case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break; - case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; - case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; - case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; - case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; - case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; - case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; - - case GL_RENDERBUFFER_SAMPLES_ANGLE: - if (!context->getExtensions().framebufferMultisample) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = renderbuffer->getSamples(); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params) -{ - EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - - switch (pname) - { - case GL_SHADER_TYPE: - *params = shaderObject->getType(); - return; - case GL_DELETE_STATUS: - *params = shaderObject->isFlaggedForDeletion(); - return; - case GL_COMPILE_STATUS: - *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; - return; - case GL_INFO_LOG_LENGTH: - *params = shaderObject->getInfoLogLength(); - return; - case GL_SHADER_SOURCE_LENGTH: - *params = shaderObject->getSourceLength(); - return; - case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: - *params = shaderObject->getTranslatedSourceWithDebugInfoLength(); - return; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) -{ - EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", - shader, bufsize, length, infolog); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - - shaderObject->getInfoLog(bufsize, length, infolog); - } -} - -void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) -{ - EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", - shadertype, precisiontype, range, precision); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (shadertype) - { - case GL_VERTEX_SHADER: - switch (precisiontype) - { - case GL_LOW_FLOAT: - context->getCaps().vertexLowpFloat.get(range, precision); - break; - case GL_MEDIUM_FLOAT: - context->getCaps().vertexMediumpFloat.get(range, precision); - break; - case GL_HIGH_FLOAT: - context->getCaps().vertexHighpFloat.get(range, precision); - break; - - case GL_LOW_INT: - context->getCaps().vertexLowpInt.get(range, precision); - break; - case GL_MEDIUM_INT: - context->getCaps().vertexMediumpInt.get(range, precision); - break; - case GL_HIGH_INT: - context->getCaps().vertexHighpInt.get(range, precision); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - case GL_FRAGMENT_SHADER: - switch (precisiontype) - { - case GL_LOW_FLOAT: - context->getCaps().fragmentLowpFloat.get(range, precision); - break; - case GL_MEDIUM_FLOAT: - context->getCaps().fragmentMediumpFloat.get(range, precision); - break; - case GL_HIGH_FLOAT: - context->getCaps().fragmentHighpFloat.get(range, precision); - break; - - case GL_LOW_INT: - context->getCaps().fragmentLowpInt.get(range, precision); - break; - case GL_MEDIUM_INT: - context->getCaps().fragmentMediumpInt.get(range, precision); - break; - case GL_HIGH_INT: - context->getCaps().fragmentHighpInt.get(range, precision); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - } -} - -void GL_APIENTRY GetShaderSource(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)", - shader, bufsize, length, source); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - - shaderObject->getSource(bufsize, length, source); - } -} - -const GLubyte *GL_APIENTRY GetString(GLenum name) -{ - EVENT("(GLenum name = 0x%X)", name); - - Context *context = GetValidGlobalContext(); - - if (context) - { - switch (name) - { - case GL_VENDOR: - return reinterpret_cast("Google Inc."); - - case GL_RENDERER: - return reinterpret_cast(context->getRendererString().c_str()); - - 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 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 reinterpret_cast(context->getExtensionString().c_str()); - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return nullptr; - } - } - - return nullptr; -} - -void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, 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) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_MAG_FILTER: - *params = (GLfloat)texture->getMagFilter(); - break; - case GL_TEXTURE_MIN_FILTER: - *params = (GLfloat)texture->getMinFilter(); - break; - case GL_TEXTURE_WRAP_S: - *params = (GLfloat)texture->getWrapS(); - break; - case GL_TEXTURE_WRAP_T: - *params = (GLfloat)texture->getWrapT(); - break; - case GL_TEXTURE_WRAP_R: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *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->getImmutableFormat() ? GL_TRUE : GL_FALSE); - break; - case GL_TEXTURE_IMMUTABLE_LEVELS: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getImmutableLevels(); - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = (GLfloat)texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getMaxAnisotropy(); - break; - case GL_TEXTURE_SWIZZLE_R: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSwizzleRed(); - break; - case GL_TEXTURE_SWIZZLE_G: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSwizzleGreen(); - break; - case GL_TEXTURE_SWIZZLE_B: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSwizzleBlue(); - break; - case GL_TEXTURE_SWIZZLE_A: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSwizzleAlpha(); - break; - case GL_TEXTURE_BASE_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getBaseLevel(); - break; - case GL_TEXTURE_MAX_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getMaxLevel(); - break; - case GL_TEXTURE_MIN_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().minLod; - break; - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().maxLod; - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetTexParameteriv(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 (!ValidTextureTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target")); - return; - } - - Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_MAG_FILTER: - *params = texture->getSamplerState().magFilter; - break; - case GL_TEXTURE_MIN_FILTER: - *params = texture->getSamplerState().minFilter; - break; - case GL_TEXTURE_WRAP_S: - *params = texture->getSamplerState().wrapS; - break; - case GL_TEXTURE_WRAP_T: - *params = texture->getSamplerState().wrapT; - break; - case GL_TEXTURE_WRAP_R: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().wrapR; - break; - case GL_TEXTURE_IMMUTABLE_FORMAT: - // Exposed to ES2.0 through EXT_texture_storage, no client version validation. - *params = texture->getImmutableFormat() ? GL_TRUE : GL_FALSE; - break; - case GL_TEXTURE_IMMUTABLE_LEVELS: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = static_cast(texture->getImmutableLevels()); - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getMaxAnisotropy(); - break; - case GL_TEXTURE_SWIZZLE_R: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSwizzleRed(); - break; - case GL_TEXTURE_SWIZZLE_G: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSwizzleGreen(); - break; - case GL_TEXTURE_SWIZZLE_B: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSwizzleBlue(); - break; - case GL_TEXTURE_SWIZZLE_A: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSwizzleAlpha(); - break; - case GL_TEXTURE_BASE_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getBaseLevel(); - break; - case GL_TEXTURE_MAX_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getMaxLevel(); - break; - case GL_TEXTURE_MIN_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getMinLod(); - break; - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getMaxLod(); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat* params) -{ - EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGetUniformfv(context, program, location, params)) - { - return; - } - - Program *programObject = context->getProgram(program); - ASSERT(programObject); - - programObject->getUniformfv(location, params); - } -} - -void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint* params) -{ - EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGetUniformiv(context, program, location, params)) - { - return; - } - - Program *programObject = context->getProgram(program); - ASSERT(programObject); - - programObject->getUniformiv(location, params); - } -} - -GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name) -{ - EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (strstr(name, "gl_") == name) - { - return -1; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return -1; - } - - if (!programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return -1; - } - - return programObject->getUniformLocation(name); - } - - return -1; -} - -void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) -{ - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.FloatValues[i]; - } - } - else - { - const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); - *params = QuerySingleVertexAttributeParameter(attribState, pname); - } - } -} - -void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) -{ - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - float currentValue = currentValueData.FloatValues[i]; - params[i] = iround(currentValue); - } - } - else - { - const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); - *params = QuerySingleVertexAttributeParameter(attribState, pname); - } - } -} - -void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) -{ - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - *pointer = const_cast(context->getState().getVertexAttribPointer(index)); - } -} - -void GL_APIENTRY Hint(GLenum target, GLenum mode) -{ - EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (mode) - { - case GL_FASTEST: - case GL_NICEST: - case GL_DONT_CARE: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_GENERATE_MIPMAP_HINT: - context->getState().setGenerateMipmapHint(mode); - break; - - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: - context->getState().setFragmentShaderDerivativeHint(mode); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -GLboolean GL_APIENTRY IsBuffer(GLuint buffer) -{ - EVENT("(GLuint buffer = %d)", buffer); - - Context *context = GetValidGlobalContext(); - if (context && buffer) - { - Buffer *bufferObject = context->getBuffer(buffer); - - if (bufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY IsEnabled(GLenum cap) -{ - EVENT("(GLenum cap = 0x%X)", cap); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return GL_FALSE; - } - - return context->getState().getEnableFeature(cap); - } - - return false; -} - -GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer) -{ - EVENT("(GLuint framebuffer = %d)", framebuffer); - - Context *context = GetValidGlobalContext(); - if (context && framebuffer) - { - Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); - - if (framebufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY IsProgram(GLuint program) -{ - EVENT("(GLuint program = %d)", program); - - Context *context = GetValidGlobalContext(); - if (context && program) - { - Program *programObject = context->getProgram(program); - - if (programObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer) -{ - EVENT("(GLuint renderbuffer = %d)", renderbuffer); - - Context *context = GetValidGlobalContext(); - if (context && renderbuffer) - { - Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); - - if (renderbufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY IsShader(GLuint shader) -{ - EVENT("(GLuint shader = %d)", shader); - - Context *context = GetValidGlobalContext(); - if (context && shader) - { - Shader *shaderObject = context->getShader(shader); - - if (shaderObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY IsTexture(GLuint texture) -{ - EVENT("(GLuint texture = %d)", texture); - - Context *context = GetValidGlobalContext(); - if (context && texture) - { - Texture *textureObject = context->getTexture(texture); - - if (textureObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -void GL_APIENTRY LineWidth(GLfloat width) -{ - EVENT("(GLfloat width = %f)", width); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (width <= 0.0f) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setLineWidth(width); - } -} - -void GL_APIENTRY LinkProgram(GLuint program) -{ - EVENT("(GLuint program = %d)", program); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - Error error = programObject->link(context->getData()); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY PixelStorei(GLenum pname, GLint param) -{ - EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - switch (pname) - { - 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: - if (!context->getExtensions().packSubimage) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - } - } - - if (param < 0) - { - context->recordError(Error(GL_INVALID_VALUE, "Cannot use negative values in PixelStorei")); - return; - } - - State &state = context->getState(); - - switch (pname) - { - case GL_UNPACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - state.setUnpackAlignment(param); - break; - - case GL_PACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - state.setPackAlignment(param); - break; - - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: - state.setPackReverseRowOrder(param != 0); - break; - - case GL_UNPACK_ROW_LENGTH: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage); - state.setUnpackRowLength(param); - break; - - case GL_UNPACK_IMAGE_HEIGHT: - ASSERT(context->getClientVersion() >= 3); - state.setUnpackImageHeight(param); - break; - - case GL_UNPACK_SKIP_IMAGES: - ASSERT(context->getClientVersion() >= 3); - state.setUnpackSkipImages(param); - break; - - case GL_UNPACK_SKIP_ROWS: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage); - state.setUnpackSkipRows(param); - break; - - case GL_UNPACK_SKIP_PIXELS: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().unpackSubimage); - state.setUnpackSkipPixels(param); - break; - - case GL_PACK_ROW_LENGTH: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage); - state.setPackRowLength(param); - break; - - case GL_PACK_SKIP_ROWS: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage); - state.setPackSkipRows(param); - break; - - case GL_PACK_SKIP_PIXELS: - ASSERT((context->getClientVersion() >= 3) || context->getExtensions().packSubimage); - state.setPackSkipPixels(param); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units) -{ - EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); - - Context *context = GetValidGlobalContext(); - if (context) - { - context->getState().setPolygonOffsetParams(factor, units); - } -} - -void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid* pixels) -{ - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " - "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)", - x, y, width, height, format, type, pixels); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateReadPixels(context, x, y, width, height, format, type, pixels)) - { - return; - } - - context->readPixels(x, y, width, height, format, type, pixels); - } -} - -void GL_APIENTRY ReleaseShaderCompiler(void) -{ - EVENT("()"); - - Context *context = GetValidGlobalContext(); - - if (context) - { - Compiler *compiler = context->getCompiler(); - Error error = compiler->release(); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, internalformat, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateRenderbufferStorageParametersANGLE(context, target, 0, internalformat, - width, height)) - { - return; - } - - Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - Error error = renderbuffer->setStorage(internalformat, width, height); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY SampleCoverage(GLclampf value, GLboolean invert) -{ - EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert); - - Context* context = GetValidGlobalContext(); - - if (context) - { - context->getState().setSampleCoverageParams(clamp01(value), invert == GL_TRUE); - } -} - -void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height) -{ - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); - - Context* context = GetValidGlobalContext(); - if (context) - { - if (width < 0 || height < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setScissorParams(x, y, width, height); - } -} - -void GL_APIENTRY ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) -{ - EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " - "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", - n, shaders, binaryformat, binary, length); - - Context* context = GetValidGlobalContext(); - if (context) - { - const std::vector &shaderBinaryFormats = context->getCaps().shaderBinaryFormats; - if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == shaderBinaryFormats.end()) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - // No binary shader formats are supported. - UNIMPLEMENTED(); - } -} - -void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) -{ - EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", - shader, count, string, length); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Shader *shaderObject = GetValidShader(context, shader); - if (!shaderObject) - { - return; - } - shaderObject->setSource(count, string, length); - } -} - -void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask) -{ - StencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); -} - -void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) -{ - EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (func) - { - case GL_NEVER: - case GL_ALWAYS: - case GL_LESS: - case GL_LEQUAL: - case GL_EQUAL: - case GL_GEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilParams(func, ref, mask); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackParams(func, ref, mask); - } - } -} - -void GL_APIENTRY StencilMask(GLuint mask) -{ - StencilMaskSeparate(GL_FRONT_AND_BACK, mask); -} - -void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask) -{ - EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilWritemask(mask); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackWritemask(mask); - } - } -} - -void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass) -{ - StencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); -} - -void GL_APIENTRY StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) -{ - EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", - face, fail, zfail, zpass); - - Context *context = GetValidGlobalContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (fail) - { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (zfail) - { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (zpass) - { - case GL_ZERO: - case GL_KEEP: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - case GL_INCR_WRAP: - case GL_DECR_WRAP: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilOperations(fail, zfail, zpass); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackOperations(fail, zfail, zpass); - } - } -} - -void GL_APIENTRY TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const GLvoid* pixels) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " - "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", - target, level, internalformat, width, height, border, format, type, pixels); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, internalformat, false, false, - 0, 0, width, height, border, format, type, pixels)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !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(context, target, level, internalformat, size, format, type, - reinterpret_cast(pixels)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, 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; - } - - Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - // clang-format off - switch (pname) - { - 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 - } -} - -void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) -{ - TexParameterf(target, pname, (GLfloat)*params); -} - -void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, 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; - } - - Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - // clang-format off - switch (pname) - { - 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 - } -} - -void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint* params) -{ - TexParameteri(target, pname, *params); -} - -void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid* pixels) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " - "const GLvoid* pixels = 0x%0.8p)", - target, level, xoffset, yoffset, width, height, format, type, pixels); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, - xoffset, yoffset, width, height, 0, format, type, pixels)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset, - yoffset, 0, width, height, 1, 0, format, type, pixels)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0) - { - return; - } - - Box area(xoffset, yoffset, 0, width, height, 1); - Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); - Error error = texture->setSubImage(context, target, level, area, format, type, - reinterpret_cast(pixels)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY Uniform1f(GLint location, GLfloat x) -{ - Uniform1fv(location, 1, &x); -} - -void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform1fv(location, count, v); - } -} - -void GL_APIENTRY Uniform1i(GLint location, GLint x) -{ - Uniform1iv(location, 1, &x); -} - -void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform1iv(location, count, v); - } -} - -void GL_APIENTRY Uniform2f(GLint location, GLfloat x, GLfloat y) -{ - GLfloat xy[2] = {x, y}; - - Uniform2fv(location, 1, xy); -} - -void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC2, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform2fv(location, count, v); - } -} - -void GL_APIENTRY Uniform2i(GLint location, GLint x, GLint y) -{ - GLint xy[2] = {x, y}; - - Uniform2iv(location, 1, xy); -} - -void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC2, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform2iv(location, count, v); - } -} - -void GL_APIENTRY Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) -{ - GLfloat xyz[3] = {x, y, z}; - - Uniform3fv(location, 1, xyz); -} - -void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC3, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform3fv(location, count, v); - } -} - -void GL_APIENTRY Uniform3i(GLint location, GLint x, GLint y, GLint z) -{ - GLint xyz[3] = {x, y, z}; - - Uniform3iv(location, 1, xyz); -} - -void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC3, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform3iv(location, count, v); - } -} - -void GL_APIENTRY Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - GLfloat xyzw[4] = {x, y, z, w}; - - Uniform4fv(location, 1, xyzw); -} - -void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC4, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform4fv(location, count, v); - } -} - -void GL_APIENTRY Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) -{ - GLint xyzw[4] = {x, y, z, w}; - - Uniform4iv(location, 1, xyzw); -} - -void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint* v) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC4, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform4iv(location, count, v); - } -} - -void GL_APIENTRY UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix2fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix3fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix4fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UseProgram(GLuint program) -{ - EVENT("(GLuint program = %d)", program); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = context->getProgram(program); - - if (!programObject && program != 0) - { - if (context->getShader(program)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - } - - if (program != 0 && !programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->useProgram(program); - } -} - -void GL_APIENTRY ValidateProgram(GLuint program) -{ - EVENT("(GLuint program = %d)", program); - - Context *context = GetValidGlobalContext(); - if (context) - { - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - programObject->validate(context->getCaps()); - } -} - -void GL_APIENTRY VertexAttrib1f(GLuint index, GLfloat x) -{ - EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, 0, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib1fv(GLuint index, const GLfloat* values) -{ - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], 0, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) -{ - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib2fv(GLuint index, const GLfloat* values) -{ - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], values[1], 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) -{ - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, z, 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib3fv(GLuint index, const GLfloat* values) -{ - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], values[1], values[2], 1 }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, z, w }; - context->getState().setVertexAttribf(index, vals); - } -} - -void GL_APIENTRY VertexAttrib4fv(GLuint index, const GLfloat* values) -{ - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribf(index, values); - } -} - -void GL_APIENTRY VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) -{ - EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " - "GLboolean normalized = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", - index, size, type, normalized, stride, ptr); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (size < 1 || size > 4) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (type) - { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_FIXED: - case GL_FLOAT: - break; - - case GL_HALF_FLOAT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_INT_2_10_10_10_REV: - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (stride < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // [OpenGL ES 3.0.2] Section 2.8 page 24: - // An INVALID_OPERATION error is generated when a non-zero vertex array object - // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, - // and the pointer argument is not NULL. - if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && ptr != NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, - normalized == GL_TRUE, false, stride, ptr); - } -} - -void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height) -{ - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (width < 0 || height < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setViewportParams(x, y, width, height); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h deleted file mode 100644 index eee5fb5468..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h +++ /dev/null @@ -1,163 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_2_0.h : Defines the GLES 2.0 entry points. - -#ifndef LIBGLESV2_ENTRYPOINTGLES20_H_ -#define LIBGLESV2_ENTRYPOINTGLES20_H_ - -#include -#include - -namespace gl -{ - -ANGLE_EXPORT void GL_APIENTRY ActiveTexture(GLenum texture); -ANGLE_EXPORT void GL_APIENTRY AttachShader(GLuint program, GLuint shader); -ANGLE_EXPORT void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar* name); -ANGLE_EXPORT void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer); -ANGLE_EXPORT void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer); -ANGLE_EXPORT void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer); -ANGLE_EXPORT void GL_APIENTRY BindTexture(GLenum target, GLuint texture); -ANGLE_EXPORT void GL_APIENTRY BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -ANGLE_EXPORT void GL_APIENTRY BlendEquation(GLenum mode); -ANGLE_EXPORT void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); -ANGLE_EXPORT void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor); -ANGLE_EXPORT void GL_APIENTRY BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -ANGLE_EXPORT void GL_APIENTRY BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); -ANGLE_EXPORT void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); -ANGLE_EXPORT GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target); -ANGLE_EXPORT void GL_APIENTRY Clear(GLbitfield mask); -ANGLE_EXPORT void GL_APIENTRY ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -ANGLE_EXPORT void GL_APIENTRY ClearDepthf(GLfloat depth); -ANGLE_EXPORT void GL_APIENTRY ClearStencil(GLint s); -ANGLE_EXPORT void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -ANGLE_EXPORT void GL_APIENTRY CompileShader(GLuint shader); -ANGLE_EXPORT void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); -ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); -ANGLE_EXPORT void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -ANGLE_EXPORT GLuint GL_APIENTRY CreateProgram(void); -ANGLE_EXPORT GLuint GL_APIENTRY CreateShader(GLenum type); -ANGLE_EXPORT void GL_APIENTRY CullFace(GLenum mode); -ANGLE_EXPORT void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint* buffers); -ANGLE_EXPORT void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint* framebuffers); -ANGLE_EXPORT void GL_APIENTRY DeleteProgram(GLuint program); -ANGLE_EXPORT void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); -ANGLE_EXPORT void GL_APIENTRY DeleteShader(GLuint shader); -ANGLE_EXPORT void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint* textures); -ANGLE_EXPORT void GL_APIENTRY DepthFunc(GLenum func); -ANGLE_EXPORT void GL_APIENTRY DepthMask(GLboolean flag); -ANGLE_EXPORT void GL_APIENTRY DepthRangef(GLfloat n, GLfloat f); -ANGLE_EXPORT void GL_APIENTRY DetachShader(GLuint program, GLuint shader); -ANGLE_EXPORT void GL_APIENTRY Disable(GLenum cap); -ANGLE_EXPORT void GL_APIENTRY DisableVertexAttribArray(GLuint index); -ANGLE_EXPORT void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count); -ANGLE_EXPORT void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); -ANGLE_EXPORT void GL_APIENTRY Enable(GLenum cap); -ANGLE_EXPORT void GL_APIENTRY EnableVertexAttribArray(GLuint index); -ANGLE_EXPORT void GL_APIENTRY Finish(void); -ANGLE_EXPORT void GL_APIENTRY Flush(void); -ANGLE_EXPORT void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -ANGLE_EXPORT void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -ANGLE_EXPORT void GL_APIENTRY FrontFace(GLenum mode); -ANGLE_EXPORT void GL_APIENTRY GenBuffers(GLsizei n, GLuint* buffers); -ANGLE_EXPORT void GL_APIENTRY GenerateMipmap(GLenum target); -ANGLE_EXPORT void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint* framebuffers); -ANGLE_EXPORT void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint* renderbuffers); -ANGLE_EXPORT void GL_APIENTRY GenTextures(GLsizei n, GLuint* textures); -ANGLE_EXPORT void GL_APIENTRY GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); -ANGLE_EXPORT void GL_APIENTRY GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); -ANGLE_EXPORT void GL_APIENTRY GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); -ANGLE_EXPORT GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name); -ANGLE_EXPORT void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean* params); -ANGLE_EXPORT void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint* params); -ANGLE_EXPORT GLenum GL_APIENTRY GetError(void); -ANGLE_EXPORT void GL_APIENTRY GetFloatv(GLenum pname, GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetIntegerv(GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); -ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); -ANGLE_EXPORT void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); -ANGLE_EXPORT void GL_APIENTRY GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); -ANGLE_EXPORT const GLubyte *GL_APIENTRY GetString(GLenum name); -ANGLE_EXPORT void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint* params); -ANGLE_EXPORT GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name); -ANGLE_EXPORT void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer); -ANGLE_EXPORT void GL_APIENTRY Hint(GLenum target, GLenum mode); -ANGLE_EXPORT GLboolean GL_APIENTRY IsBuffer(GLuint buffer); -ANGLE_EXPORT GLboolean GL_APIENTRY IsEnabled(GLenum cap); -ANGLE_EXPORT GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer); -ANGLE_EXPORT GLboolean GL_APIENTRY IsProgram(GLuint program); -ANGLE_EXPORT GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer); -ANGLE_EXPORT GLboolean GL_APIENTRY IsShader(GLuint shader); -ANGLE_EXPORT GLboolean GL_APIENTRY IsTexture(GLuint texture); -ANGLE_EXPORT void GL_APIENTRY LineWidth(GLfloat width); -ANGLE_EXPORT void GL_APIENTRY LinkProgram(GLuint program); -ANGLE_EXPORT void GL_APIENTRY PixelStorei(GLenum pname, GLint param); -ANGLE_EXPORT void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units); -ANGLE_EXPORT void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); -ANGLE_EXPORT void GL_APIENTRY ReleaseShaderCompiler(void); -ANGLE_EXPORT void GL_APIENTRY RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY SampleCoverage(GLfloat value, GLboolean invert); -ANGLE_EXPORT void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); -ANGLE_EXPORT void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); -ANGLE_EXPORT void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask); -ANGLE_EXPORT void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); -ANGLE_EXPORT void GL_APIENTRY StencilMask(GLuint mask); -ANGLE_EXPORT void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask); -ANGLE_EXPORT void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass); -ANGLE_EXPORT void GL_APIENTRY StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); -ANGLE_EXPORT void GL_APIENTRY TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); -ANGLE_EXPORT void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param); -ANGLE_EXPORT void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param); -ANGLE_EXPORT void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint* params); -ANGLE_EXPORT void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); -ANGLE_EXPORT void GL_APIENTRY Uniform1f(GLint location, GLfloat x); -ANGLE_EXPORT void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat* v); -ANGLE_EXPORT void GL_APIENTRY Uniform1i(GLint location, GLint x); -ANGLE_EXPORT void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint* v); -ANGLE_EXPORT void GL_APIENTRY Uniform2f(GLint location, GLfloat x, GLfloat y); -ANGLE_EXPORT void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat* v); -ANGLE_EXPORT void GL_APIENTRY Uniform2i(GLint location, GLint x, GLint y); -ANGLE_EXPORT void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint* v); -ANGLE_EXPORT void GL_APIENTRY Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z); -ANGLE_EXPORT void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat* v); -ANGLE_EXPORT void GL_APIENTRY Uniform3i(GLint location, GLint x, GLint y, GLint z); -ANGLE_EXPORT void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint* v); -ANGLE_EXPORT void GL_APIENTRY Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -ANGLE_EXPORT void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat* v); -ANGLE_EXPORT void GL_APIENTRY Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w); -ANGLE_EXPORT void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint* v); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UseProgram(GLuint program); -ANGLE_EXPORT void GL_APIENTRY ValidateProgram(GLuint program); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib1f(GLuint indx, GLfloat x); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib1fv(GLuint indx, const GLfloat* values); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib2fv(GLuint indx, const GLfloat* values); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib3fv(GLuint indx, const GLfloat* values); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -ANGLE_EXPORT void GL_APIENTRY VertexAttrib4fv(GLuint indx, const GLfloat* values); -ANGLE_EXPORT void GL_APIENTRY VertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); -ANGLE_EXPORT void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height); - -} - -#endif // LIBGLESV2_ENTRYPOINTGLES20_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.cpp new file mode 100644 index 0000000000..ae0e944406 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.cpp @@ -0,0 +1,2612 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_2_0_autogen.cpp: +// Defines the GLES 2.0 entry points. + +#include "libANGLE/Context.h" +#include "libANGLE/validationES2.h" +#include "libGLESv2/global_state.h" + +namespace gl +{ +void GL_APIENTRY ActiveTexture(GLenum texture) +{ + EVENT("(GLenum texture = 0x%X)", texture); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(texture); + + if (context->skipValidation() || ValidateActiveTexture(context, texture)) + { + context->activeTexture(texture); + } + } +} + +void GL_APIENTRY AttachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %u, GLuint shader = %u)", program, shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, shader); + + if (context->skipValidation() || ValidateAttachShader(context, program, shader)) + { + context->attachShader(program, shader); + } + } +} + +void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar *name) +{ + EVENT("(GLuint program = %u, GLuint index = %u, const GLchar *name = 0x%0.8p)", program, index, + name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, index, name); + + if (context->skipValidation() || ValidateBindAttribLocation(context, program, index, name)) + { + context->bindAttribLocation(program, index, name); + } + } +} + +void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint buffer = %u)", target, buffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, buffer); + + if (context->skipValidation() || ValidateBindBuffer(context, targetPacked, buffer)) + { + context->bindBuffer(targetPacked, buffer); + } + } +} + +void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint framebuffer = %u)", target, framebuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, framebuffer); + + if (context->skipValidation() || ValidateBindFramebuffer(context, target, framebuffer)) + { + context->bindFramebuffer(target, framebuffer); + } + } +} + +void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %u)", target, renderbuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, renderbuffer); + + if (context->skipValidation() || ValidateBindRenderbuffer(context, target, renderbuffer)) + { + context->bindRenderbuffer(target, renderbuffer); + } + } +} + +void GL_APIENTRY BindTexture(GLenum target, GLuint texture) +{ + EVENT("(GLenum target = 0x%X, GLuint texture = %u)", target, texture); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, texture); + + if (context->skipValidation() || ValidateBindTexture(context, target, texture)) + { + context->bindTexture(target, texture); + } + } +} + +void GL_APIENTRY BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + EVENT("(GLfloat red = %f, GLfloat green = %f, GLfloat blue = %f, GLfloat alpha = %f)", red, + green, blue, alpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(red, green, blue, alpha); + + if (context->skipValidation() || ValidateBlendColor(context, red, green, blue, alpha)) + { + context->blendColor(red, green, blue, alpha); + } + } +} + +void GL_APIENTRY BlendEquation(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode); + + if (context->skipValidation() || ValidateBlendEquation(context, mode)) + { + context->blendEquation(mode); + } + } +} + +void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(modeRGB, modeAlpha); + + if (context->skipValidation() || ValidateBlendEquationSeparate(context, modeRGB, modeAlpha)) + { + context->blendEquationSeparate(modeRGB, modeAlpha); + } + } +} + +void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor) +{ + EVENT("(GLenum sfactor = 0x%X, GLenum dfactor = 0x%X)", sfactor, dfactor); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sfactor, dfactor); + + if (context->skipValidation() || ValidateBlendFunc(context, sfactor, dfactor)) + { + context->blendFunc(sfactor, dfactor); + } + } +} + +void GL_APIENTRY BlendFuncSeparate(GLenum sfactorRGB, + GLenum dfactorRGB, + GLenum sfactorAlpha, + GLenum dfactorAlpha) +{ + EVENT( + "(GLenum sfactorRGB = 0x%X, GLenum dfactorRGB = 0x%X, GLenum sfactorAlpha = 0x%X, GLenum " + "dfactorAlpha = 0x%X)", + sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sfactorRGB, dfactorRGB, sfactorAlpha, + dfactorAlpha); + + if (context->skipValidation() || + ValidateBlendFuncSeparate(context, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha)) + { + context->blendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); + } + } +} + +void GL_APIENTRY BufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) +{ + EVENT( + "(GLenum target = 0x%X, GLsizeiptr size = %d, const void *data = 0x%0.8p, GLenum usage = " + "0x%X)", + target, size, data, usage); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + BufferUsage usagePacked = FromGLenum(usage); + context->gatherParams(targetPacked, size, data, usagePacked); + + if (context->skipValidation() || + ValidateBufferData(context, targetPacked, size, data, usagePacked)) + { + context->bufferData(targetPacked, size, data, usagePacked); + } + } +} + +void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) +{ + EVENT( + "(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const void *data = " + "0x%0.8p)", + target, offset, size, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, offset, size, data); + + if (context->skipValidation() || + ValidateBufferSubData(context, targetPacked, offset, size, data)) + { + context->bufferSubData(targetPacked, offset, size, data); + } + } +} + +GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target); + + if (context->skipValidation() || ValidateCheckFramebufferStatus(context, target)) + { + return context->checkFramebufferStatus(target); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY Clear(GLbitfield mask) +{ + EVENT("(GLbitfield mask = 0x%X)", mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mask); + + if (context->skipValidation() || ValidateClear(context, mask)) + { + context->clear(mask); + } + } +} + +void GL_APIENTRY ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + EVENT("(GLfloat red = %f, GLfloat green = %f, GLfloat blue = %f, GLfloat alpha = %f)", red, + green, blue, alpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(red, green, blue, alpha); + + if (context->skipValidation() || ValidateClearColor(context, red, green, blue, alpha)) + { + context->clearColor(red, green, blue, alpha); + } + } +} + +void GL_APIENTRY ClearDepthf(GLfloat d) +{ + EVENT("(GLfloat d = %f)", d); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(d); + + if (context->skipValidation() || ValidateClearDepthf(context, d)) + { + context->clearDepthf(d); + } + } +} + +void GL_APIENTRY ClearStencil(GLint s) +{ + EVENT("(GLint s = %d)", s); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(s); + + if (context->skipValidation() || ValidateClearStencil(context, s)) + { + context->clearStencil(s); + } + } +} + +void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + EVENT("(GLboolean red = %u, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", + red, green, blue, alpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(red, green, blue, alpha); + + if (context->skipValidation() || ValidateColorMask(context, red, green, blue, alpha)) + { + context->colorMask(red, green, blue, alpha); + } + } +} + +void GL_APIENTRY CompileShader(GLuint shader) +{ + EVENT("(GLuint shader = %u)", shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader); + + if (context->skipValidation() || ValidateCompileShader(context, shader)) + { + context->compileShader(shader); + } + } +} + +void GL_APIENTRY CompressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const void *data = " + "0x%0.8p)", + target, level, internalformat, width, height, border, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, level, internalformat, width, height, border, imageSize, data); + + if (context->skipValidation() || + ValidateCompressedTexImage2D(context, target, level, internalformat, width, height, + border, imageSize, data)) + { + context->compressedTexImage2D(target, level, internalformat, width, height, border, + imageSize, data); + } + } +} + +void GL_APIENTRY CompressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLsizei " + "width = %d, GLsizei height = %d, GLenum format = 0x%X, GLsizei imageSize = %d, const void " + "*data = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, level, xoffset, yoffset, width, height, format, imageSize, data); + + if (context->skipValidation() || + ValidateCompressedTexSubImage2D(context, target, level, xoffset, yoffset, width, height, + format, imageSize, data)) + { + context->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + imageSize, data); + } + } +} + +void GL_APIENTRY CopyTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLint x = %d, " + "GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", + target, level, internalformat, x, y, width, height, border); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, internalformat, x, y, + width, height, border); + + if (context->skipValidation() || + ValidateCopyTexImage2D(context, target, level, internalformat, x, y, width, height, + border)) + { + context->copyTexImage2D(target, level, internalformat, x, y, width, height, border); + } + } +} + +void GL_APIENTRY CopyTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLint x " + "= %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, level, xoffset, yoffset, x, y, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, xoffset, yoffset, x, y, + width, height); + + if (context->skipValidation() || ValidateCopyTexSubImage2D(context, target, level, xoffset, + yoffset, x, y, width, height)) + { + context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + } + } +} + +GLuint GL_APIENTRY CreateProgram() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateCreateProgram(context)) + { + return context->createProgram(); + } + } + + return GetDefaultReturnValue(); +} + +GLuint GL_APIENTRY CreateShader(GLenum type) +{ + EVENT("(GLenum type = 0x%X)", type); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(type); + + if (context->skipValidation() || ValidateCreateShader(context, type)) + { + return context->createShader(type); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY CullFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + CullFaceMode modePacked = FromGLenum(mode); + context->gatherParams(modePacked); + + if (context->skipValidation() || ValidateCullFace(context, modePacked)) + { + context->cullFace(modePacked); + } + } +} + +void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint *buffers) +{ + EVENT("(GLsizei n = %d, const GLuint *buffers = 0x%0.8p)", n, buffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, buffers); + + if (context->skipValidation() || ValidateDeleteBuffers(context, n, buffers)) + { + context->deleteBuffers(n, buffers); + } + } +} + +void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ + EVENT("(GLsizei n = %d, const GLuint *framebuffers = 0x%0.8p)", n, framebuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, framebuffers); + + if (context->skipValidation() || ValidateDeleteFramebuffers(context, n, framebuffers)) + { + context->deleteFramebuffers(n, framebuffers); + } + } +} + +void GL_APIENTRY DeleteProgram(GLuint program) +{ + EVENT("(GLuint program = %u)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program); + + if (context->skipValidation() || ValidateDeleteProgram(context, program)) + { + context->deleteProgram(program); + } + } +} + +void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) +{ + EVENT("(GLsizei n = %d, const GLuint *renderbuffers = 0x%0.8p)", n, renderbuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, renderbuffers); + + if (context->skipValidation() || ValidateDeleteRenderbuffers(context, n, renderbuffers)) + { + context->deleteRenderbuffers(n, renderbuffers); + } + } +} + +void GL_APIENTRY DeleteShader(GLuint shader) +{ + EVENT("(GLuint shader = %u)", shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader); + + if (context->skipValidation() || ValidateDeleteShader(context, shader)) + { + context->deleteShader(shader); + } + } +} + +void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint *textures) +{ + EVENT("(GLsizei n = %d, const GLuint *textures = 0x%0.8p)", n, textures); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, textures); + + if (context->skipValidation() || ValidateDeleteTextures(context, n, textures)) + { + context->deleteTextures(n, textures); + } + } +} + +void GL_APIENTRY DepthFunc(GLenum func) +{ + EVENT("(GLenum func = 0x%X)", func); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(func); + + if (context->skipValidation() || ValidateDepthFunc(context, func)) + { + context->depthFunc(func); + } + } +} + +void GL_APIENTRY DepthMask(GLboolean flag) +{ + EVENT("(GLboolean flag = %u)", flag); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(flag); + + if (context->skipValidation() || ValidateDepthMask(context, flag)) + { + context->depthMask(flag); + } + } +} + +void GL_APIENTRY DepthRangef(GLfloat n, GLfloat f) +{ + EVENT("(GLfloat n = %f, GLfloat f = %f)", n, f); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, f); + + if (context->skipValidation() || ValidateDepthRangef(context, n, f)) + { + context->depthRangef(n, f); + } + } +} + +void GL_APIENTRY DetachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %u, GLuint shader = %u)", program, shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, shader); + + if (context->skipValidation() || ValidateDetachShader(context, program, shader)) + { + context->detachShader(program, shader); + } + } +} + +void GL_APIENTRY Disable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(cap); + + if (context->skipValidation() || ValidateDisable(context, cap)) + { + context->disable(cap); + } + } +} + +void GL_APIENTRY DisableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %u)", index); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index); + + if (context->skipValidation() || ValidateDisableVertexAttribArray(context, index)) + { + context->disableVertexAttribArray(index); + } + } +} + +void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, first, count); + + if (context->skipValidation() || ValidateDrawArrays(context, mode, first, count)) + { + context->drawArrays(mode, first, count); + } + } +} + +void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + EVENT( + "(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = " + "0x%0.8p)", + mode, count, type, indices); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, count, type, indices); + + if (context->skipValidation() || ValidateDrawElements(context, mode, count, type, indices)) + { + context->drawElements(mode, count, type, indices); + } + } +} + +void GL_APIENTRY Enable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(cap); + + if (context->skipValidation() || ValidateEnable(context, cap)) + { + context->enable(cap); + } + } +} + +void GL_APIENTRY EnableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %u)", index); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index); + + if (context->skipValidation() || ValidateEnableVertexAttribArray(context, index)) + { + context->enableVertexAttribArray(index); + } + } +} + +void GL_APIENTRY Finish() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateFinish(context)) + { + context->finish(); + } + } +} + +void GL_APIENTRY Flush() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateFlush(context)) + { + context->flush(); + } + } +} + +void GL_APIENTRY FramebufferRenderbuffer(GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, GLuint " + "renderbuffer = %u)", + target, attachment, renderbuffertarget, renderbuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, attachment, renderbuffertarget, renderbuffer); + + if (context->skipValidation() || + ValidateFramebufferRenderbuffer(context, target, attachment, renderbuffertarget, + renderbuffer)) + { + context->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + } + } +} + +void GL_APIENTRY FramebufferTexture2D(GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, GLuint texture " + "= %u, GLint level = %d)", + target, attachment, textarget, texture, level); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, attachment, textarget, + texture, level); + + if (context->skipValidation() || + ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) + { + context->framebufferTexture2D(target, attachment, textarget, texture, level); + } + } +} + +void GL_APIENTRY FrontFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode); + + if (context->skipValidation() || ValidateFrontFace(context, mode)) + { + context->frontFace(mode); + } + } +} + +void GL_APIENTRY GenBuffers(GLsizei n, GLuint *buffers) +{ + EVENT("(GLsizei n = %d, GLuint *buffers = 0x%0.8p)", n, buffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, buffers); + + if (context->skipValidation() || ValidateGenBuffers(context, n, buffers)) + { + context->genBuffers(n, buffers); + } + } +} + +void GL_APIENTRY GenerateMipmap(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target); + + if (context->skipValidation() || ValidateGenerateMipmap(context, target)) + { + context->generateMipmap(target); + } + } +} + +void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint *framebuffers) +{ + EVENT("(GLsizei n = %d, GLuint *framebuffers = 0x%0.8p)", n, framebuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, framebuffers); + + if (context->skipValidation() || ValidateGenFramebuffers(context, n, framebuffers)) + { + context->genFramebuffers(n, framebuffers); + } + } +} + +void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + EVENT("(GLsizei n = %d, GLuint *renderbuffers = 0x%0.8p)", n, renderbuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, renderbuffers); + + if (context->skipValidation() || ValidateGenRenderbuffers(context, n, renderbuffers)) + { + context->genRenderbuffers(n, renderbuffers); + } + } +} + +void GL_APIENTRY GenTextures(GLsizei n, GLuint *textures) +{ + EVENT("(GLsizei n = %d, GLuint *textures = 0x%0.8p)", n, textures); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, textures); + + if (context->skipValidation() || ValidateGenTextures(context, n, textures)) + { + context->genTextures(n, textures); + } + } +} + +void GL_APIENTRY GetActiveAttrib(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + EVENT( + "(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, " + "GLint *size = 0x%0.8p, GLenum *type = 0x%0.8p, GLchar *name = 0x%0.8p)", + program, index, bufSize, length, size, type, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, index, bufSize, length, size, + type, name); + + if (context->skipValidation() || + ValidateGetActiveAttrib(context, program, index, bufSize, length, size, type, name)) + { + context->getActiveAttrib(program, index, bufSize, length, size, type, name); + } + } +} + +void GL_APIENTRY GetActiveUniform(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) +{ + EVENT( + "(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, " + "GLint *size = 0x%0.8p, GLenum *type = 0x%0.8p, GLchar *name = 0x%0.8p)", + program, index, bufSize, length, size, type, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, index, bufSize, length, size, + type, name); + + if (context->skipValidation() || + ValidateGetActiveUniform(context, program, index, bufSize, length, size, type, name)) + { + context->getActiveUniform(program, index, bufSize, length, size, type, name); + } + } +} + +void GL_APIENTRY GetAttachedShaders(GLuint program, + GLsizei maxCount, + GLsizei *count, + GLuint *shaders) +{ + EVENT( + "(GLuint program = %u, GLsizei maxCount = %d, GLsizei *count = 0x%0.8p, GLuint *shaders = " + "0x%0.8p)", + program, maxCount, count, shaders); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, maxCount, count, shaders); + + if (context->skipValidation() || + ValidateGetAttachedShaders(context, program, maxCount, count, shaders)) + { + context->getAttachedShaders(program, maxCount, count, shaders); + } + } +} + +GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar *name) +{ + EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, name); + + if (context->skipValidation() || ValidateGetAttribLocation(context, program, name)) + { + return context->getAttribLocation(program, name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean *data) +{ + EVENT("(GLenum pname = 0x%X, GLboolean *data = 0x%0.8p)", pname, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, data); + + if (context->skipValidation() || ValidateGetBooleanv(context, pname, data)) + { + context->getBooleanv(pname, data); + } + } +} + +void GL_APIENTRY GetBufferParameteriv(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) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, pname, params); + + if (context->skipValidation() || + ValidateGetBufferParameteriv(context, targetPacked, pname, params)) + { + context->getBufferParameteriv(targetPacked, pname, params); + } + } +} + +GLenum GL_APIENTRY GetError() +{ + EVENT("()"); + + Context *context = GetGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateGetError(context)) + { + return context->getError(); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetFloatv(GLenum pname, GLfloat *data) +{ + EVENT("(GLenum pname = 0x%X, GLfloat *data = 0x%0.8p)", pname, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, data); + + if (context->skipValidation() || ValidateGetFloatv(context, pname, data)) + { + context->getFloatv(pname, data); + } + } +} + +void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint *params = " + "0x%0.8p)", + target, attachment, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, attachment, + pname, params); + + if (context->skipValidation() || + ValidateGetFramebufferAttachmentParameteriv(context, target, attachment, pname, params)) + { + context->getFramebufferAttachmentParameteriv(target, attachment, pname, params); + } + } +} + +void GL_APIENTRY GetIntegerv(GLenum pname, GLint *data) +{ + EVENT("(GLenum pname = 0x%X, GLint *data = 0x%0.8p)", pname, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, data); + + if (context->skipValidation() || ValidateGetIntegerv(context, pname, data)) + { + context->getIntegerv(pname, data); + } + } +} + +void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint *params) +{ + EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", program, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, pname, params); + + if (context->skipValidation() || ValidateGetProgramiv(context, program, pname, params)) + { + context->getProgramiv(program, pname, params); + } + } +} + +void GL_APIENTRY GetProgramInfoLog(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + EVENT( + "(GLuint program = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLchar *infoLog = " + "0x%0.8p)", + program, bufSize, length, infoLog); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, bufSize, length, infoLog); + + if (context->skipValidation() || + ValidateGetProgramInfoLog(context, program, bufSize, length, infoLog)) + { + context->getProgramInfoLog(program, bufSize, length, infoLog); + } + } +} + +void GL_APIENTRY GetRenderbufferParameteriv(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) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || + ValidateGetRenderbufferParameteriv(context, target, pname, params)) + { + context->getRenderbufferParameteriv(target, pname, params); + } + } +} + +void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + EVENT("(GLuint shader = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", shader, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader, pname, params); + + if (context->skipValidation() || ValidateGetShaderiv(context, shader, pname, params)) + { + context->getShaderiv(shader, pname, params); + } + } +} + +void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +{ + EVENT( + "(GLuint shader = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLchar *infoLog = " + "0x%0.8p)", + shader, bufSize, length, infoLog); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader, bufSize, length, infoLog); + + if (context->skipValidation() || + ValidateGetShaderInfoLog(context, shader, bufSize, length, infoLog)) + { + context->getShaderInfoLog(shader, bufSize, length, infoLog); + } + } +} + +void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) +{ + EVENT( + "(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint *range = 0x%0.8p, GLint " + "*precision = 0x%0.8p)", + shadertype, precisiontype, range, precision); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shadertype, precisiontype, + range, precision); + + if (context->skipValidation() || + ValidateGetShaderPrecisionFormat(context, shadertype, precisiontype, range, precision)) + { + context->getShaderPrecisionFormat(shadertype, precisiontype, range, precision); + } + } +} + +void GL_APIENTRY GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) +{ + EVENT( + "(GLuint shader = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLchar *source = " + "0x%0.8p)", + shader, bufSize, length, source); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader, bufSize, length, source); + + if (context->skipValidation() || + ValidateGetShaderSource(context, shader, bufSize, length, source)) + { + context->getShaderSource(shader, bufSize, length, source); + } + } +} + +const GLubyte *GL_APIENTRY GetString(GLenum name) +{ + EVENT("(GLenum name = 0x%X)", name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(name); + + if (context->skipValidation() || ValidateGetString(context, name)) + { + return context->getString(name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat *params = 0x%0.8p)", target, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || ValidateGetTexParameterfv(context, target, pname, params)) + { + context->getTexParameterfv(target, pname, params); + } + } +} + +void GL_APIENTRY GetTexParameteriv(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) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || ValidateGetTexParameteriv(context, target, pname, params)) + { + context->getTexParameteriv(target, pname, params); + } + } +} + +void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat *params) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLfloat *params = 0x%0.8p)", program, + location, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, params); + + if (context->skipValidation() || ValidateGetUniformfv(context, program, location, params)) + { + context->getUniformfv(program, location, params); + } + } +} + +void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint *params) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLint *params = 0x%0.8p)", program, location, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, params); + + if (context->skipValidation() || ValidateGetUniformiv(context, program, location, params)) + { + context->getUniformiv(program, location, params); + } + } +} + +GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar *name) +{ + EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, name); + + if (context->skipValidation() || ValidateGetUniformLocation(context, program, name)) + { + return context->getUniformLocation(program, name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLfloat *params = 0x%0.8p)", index, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, pname, params); + + if (context->skipValidation() || ValidateGetVertexAttribfv(context, index, pname, params)) + { + context->getVertexAttribfv(index, pname, params); + } + } +} + +void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint *params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", index, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, pname, params); + + if (context->skipValidation() || ValidateGetVertexAttribiv(context, index, pname, params)) + { + context->getVertexAttribiv(index, pname, params); + } + } +} + +void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, void **pointer = 0x%0.8p)", index, pname, + pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, pname, pointer); + + if (context->skipValidation() || + ValidateGetVertexAttribPointerv(context, index, pname, pointer)) + { + context->getVertexAttribPointerv(index, pname, pointer); + } + } +} + +void GL_APIENTRY Hint(GLenum target, GLenum mode) +{ + EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, mode); + + if (context->skipValidation() || ValidateHint(context, target, mode)) + { + context->hint(target, mode); + } + } +} + +GLboolean GL_APIENTRY IsBuffer(GLuint buffer) +{ + EVENT("(GLuint buffer = %u)", buffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(buffer); + + if (context->skipValidation() || ValidateIsBuffer(context, buffer)) + { + return context->isBuffer(buffer); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsEnabled(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(cap); + + if (context->skipValidation() || ValidateIsEnabled(context, cap)) + { + return context->isEnabled(cap); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer) +{ + EVENT("(GLuint framebuffer = %u)", framebuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(framebuffer); + + if (context->skipValidation() || ValidateIsFramebuffer(context, framebuffer)) + { + return context->isFramebuffer(framebuffer); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsProgram(GLuint program) +{ + EVENT("(GLuint program = %u)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program); + + if (context->skipValidation() || ValidateIsProgram(context, program)) + { + return context->isProgram(program); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer) +{ + EVENT("(GLuint renderbuffer = %u)", renderbuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(renderbuffer); + + if (context->skipValidation() || ValidateIsRenderbuffer(context, renderbuffer)) + { + return context->isRenderbuffer(renderbuffer); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsShader(GLuint shader) +{ + EVENT("(GLuint shader = %u)", shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader); + + if (context->skipValidation() || ValidateIsShader(context, shader)) + { + return context->isShader(shader); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsTexture(GLuint texture) +{ + EVENT("(GLuint texture = %u)", texture); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(texture); + + if (context->skipValidation() || ValidateIsTexture(context, texture)) + { + return context->isTexture(texture); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY LineWidth(GLfloat width) +{ + EVENT("(GLfloat width = %f)", width); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(width); + + if (context->skipValidation() || ValidateLineWidth(context, width)) + { + context->lineWidth(width); + } + } +} + +void GL_APIENTRY LinkProgram(GLuint program) +{ + EVENT("(GLuint program = %u)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program); + + if (context->skipValidation() || ValidateLinkProgram(context, program)) + { + context->linkProgram(program); + } + } +} + +void GL_APIENTRY PixelStorei(GLenum pname, GLint param) +{ + EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, param); + + if (context->skipValidation() || ValidatePixelStorei(context, pname, param)) + { + context->pixelStorei(pname, param); + } + } +} + +void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units) +{ + EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(factor, units); + + if (context->skipValidation() || ValidatePolygonOffset(context, factor, units)) + { + context->polygonOffset(factor, units); + } + } +} + +void GL_APIENTRY ReadPixels(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels) +{ + EVENT( + "(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLenum format = " + "0x%X, GLenum type = 0x%X, void *pixels = 0x%0.8p)", + x, y, width, height, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(x, y, width, height, format, type, pixels); + + if (context->skipValidation() || + ValidateReadPixels(context, x, y, width, height, format, type, pixels)) + { + context->readPixels(x, y, width, height, format, type, pixels); + } + } +} + +void GL_APIENTRY ReleaseShaderCompiler() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateReleaseShaderCompiler(context)) + { + context->releaseShaderCompiler(); + } + } +} + +void GL_APIENTRY RenderbufferStorage(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = " + "%d)", + target, internalformat, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, internalformat, width, + height); + + if (context->skipValidation() || + ValidateRenderbufferStorage(context, target, internalformat, width, height)) + { + context->renderbufferStorage(target, internalformat, width, height); + } + } +} + +void GL_APIENTRY SampleCoverage(GLfloat value, GLboolean invert) +{ + EVENT("(GLfloat value = %f, GLboolean invert = %u)", value, invert); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(value, invert); + + if (context->skipValidation() || ValidateSampleCoverage(context, value, invert)) + { + context->sampleCoverage(value, invert); + } + } +} + +void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, + height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(x, y, width, height); + + if (context->skipValidation() || ValidateScissor(context, x, y, width, height)) + { + context->scissor(x, y, width, height); + } + } +} + +void GL_APIENTRY ShaderBinary(GLsizei count, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) +{ + EVENT( + "(GLsizei count = %d, const GLuint *shaders = 0x%0.8p, GLenum binaryformat = 0x%X, const " + "void *binary = 0x%0.8p, GLsizei length = %d)", + count, shaders, binaryformat, binary, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(count, shaders, binaryformat, binary, + length); + + if (context->skipValidation() || + ValidateShaderBinary(context, count, shaders, binaryformat, binary, length)) + { + context->shaderBinary(count, shaders, binaryformat, binary, length); + } + } +} + +void GL_APIENTRY ShaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) +{ + EVENT( + "(GLuint shader = %u, GLsizei count = %d, const GLchar *const*string = 0x%0.8p, const " + "GLint *length = 0x%0.8p)", + shader, count, string, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(shader, count, string, length); + + if (context->skipValidation() || + ValidateShaderSource(context, shader, count, string, length)) + { + context->shaderSource(shader, count, string, length); + } + } +} + +void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum func = 0x%X, GLint ref = %d, GLuint mask = %u)", func, ref, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(func, ref, mask); + + if (context->skipValidation() || ValidateStencilFunc(context, func, ref, mask)) + { + context->stencilFunc(func, ref, mask); + } + } +} + +void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %u)", face, func, + ref, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(face, func, ref, mask); + + if (context->skipValidation() || + ValidateStencilFuncSeparate(context, face, func, ref, mask)) + { + context->stencilFuncSeparate(face, func, ref, mask); + } + } +} + +void GL_APIENTRY StencilMask(GLuint mask) +{ + EVENT("(GLuint mask = %u)", mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mask); + + if (context->skipValidation() || ValidateStencilMask(context, mask)) + { + context->stencilMask(mask); + } + } +} + +void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLuint mask = %u)", face, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(face, mask); + + if (context->skipValidation() || ValidateStencilMaskSeparate(context, face, mask)) + { + context->stencilMaskSeparate(face, mask); + } + } +} + +void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + EVENT("(GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpass = 0x%X)", fail, zfail, zpass); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(fail, zfail, zpass); + + if (context->skipValidation() || ValidateStencilOp(context, fail, zfail, zpass)) + { + context->stencilOp(fail, zfail, zpass); + } + } +} + +void GL_APIENTRY StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) +{ + EVENT("(GLenum face = 0x%X, GLenum sfail = 0x%X, GLenum dpfail = 0x%X, GLenum dppass = 0x%X)", + face, sfail, dpfail, dppass); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(face, sfail, dpfail, dppass); + + if (context->skipValidation() || + ValidateStencilOpSeparate(context, face, sfail, dpfail, dppass)) + { + context->stencilOpSeparate(face, sfail, dpfail, dppass); + } + } +} + +void GL_APIENTRY TexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " + "GLsizei height = %d, GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const " + "void *pixels = 0x%0.8p)", + target, level, internalformat, width, height, border, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, internalformat, width, height, + border, format, type, pixels); + + if (context->skipValidation() || + ValidateTexImage2D(context, target, level, internalformat, width, height, border, + format, type, pixels)) + { + context->texImage2D(target, level, internalformat, width, height, border, format, type, + pixels); + } + } +} + +void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat param = %f)", target, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, param); + + if (context->skipValidation() || ValidateTexParameterf(context, target, pname, param)) + { + context->texParameterf(target, pname, param); + } + } +} + +void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, const GLfloat *params = 0x%0.8p)", target, + pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || ValidateTexParameterfv(context, target, pname, params)) + { + context->texParameterfv(target, pname, params); + } + } +} + +void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, param); + + if (context->skipValidation() || ValidateTexParameteri(context, target, pname, param)) + { + context->texParameteri(target, pname, param); + } + } +} + +void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, const GLint *params = 0x%0.8p)", target, + pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || ValidateTexParameteriv(context, target, pname, params)) + { + context->texParameteriv(target, pname, params); + } + } +} + +void GL_APIENTRY TexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLsizei " + "width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, const void " + "*pixels = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, xoffset, yoffset, width, + height, format, type, pixels); + + if (context->skipValidation() || + ValidateTexSubImage2D(context, target, level, xoffset, yoffset, width, height, format, + type, pixels)) + { + context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, + pixels); + } + } +} + +void GL_APIENTRY Uniform1f(GLint location, GLfloat v0) +{ + EVENT("(GLint location = %d, GLfloat v0 = %f)", location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0); + + if (context->skipValidation() || ValidateUniform1f(context, location, v0)) + { + context->uniform1f(location, v0); + } + } +} + +void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform1fv(context, location, count, value)) + { + context->uniform1fv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform1i(GLint location, GLint v0) +{ + EVENT("(GLint location = %d, GLint v0 = %d)", location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0); + + if (context->skipValidation() || ValidateUniform1i(context, location, v0)) + { + context->uniform1i(location, v0); + } + } +} + +void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform1iv(context, location, count, value)) + { + context->uniform1iv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform2f(GLint location, GLfloat v0, GLfloat v1) +{ + EVENT("(GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f)", location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1); + + if (context->skipValidation() || ValidateUniform2f(context, location, v0, v1)) + { + context->uniform2f(location, v0, v1); + } + } +} + +void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform2fv(context, location, count, value)) + { + context->uniform2fv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform2i(GLint location, GLint v0, GLint v1) +{ + EVENT("(GLint location = %d, GLint v0 = %d, GLint v1 = %d)", location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1); + + if (context->skipValidation() || ValidateUniform2i(context, location, v0, v1)) + { + context->uniform2i(location, v0, v1); + } + } +} + +void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform2iv(context, location, count, value)) + { + context->uniform2iv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + EVENT("(GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f, GLfloat v2 = %f)", location, v0, + v1, v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2); + + if (context->skipValidation() || ValidateUniform3f(context, location, v0, v1, v2)) + { + context->uniform3f(location, v0, v1, v2); + } + } +} + +void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform3fv(context, location, count, value)) + { + context->uniform3fv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform3i(GLint location, GLint v0, GLint v1, GLint v2) +{ + EVENT("(GLint location = %d, GLint v0 = %d, GLint v1 = %d, GLint v2 = %d)", location, v0, v1, + v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2); + + if (context->skipValidation() || ValidateUniform3i(context, location, v0, v1, v2)) + { + context->uniform3i(location, v0, v1, v2); + } + } +} + +void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform3iv(context, location, count, value)) + { + context->uniform3iv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + EVENT( + "(GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f, GLfloat v2 = %f, GLfloat v3 = %f)", + location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2, v3); + + if (context->skipValidation() || ValidateUniform4f(context, location, v0, v1, v2, v3)) + { + context->uniform4f(location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform4fv(context, location, count, value)) + { + context->uniform4fv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + EVENT("(GLint location = %d, GLint v0 = %d, GLint v1 = %d, GLint v2 = %d, GLint v3 = %d)", + location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2, v3); + + if (context->skipValidation() || ValidateUniform4i(context, location, v0, v1, v2, v3)) + { + context->uniform4i(location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform4iv(context, location, count, value)) + { + context->uniform4iv(location, count, value); + } + } +} + +void GL_APIENTRY UniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix2fv(context, location, count, transpose, value)) + { + context->uniformMatrix2fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix3fv(context, location, count, transpose, value)) + { + context->uniformMatrix3fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix4fv(context, location, count, transpose, value)) + { + context->uniformMatrix4fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UseProgram(GLuint program) +{ + EVENT("(GLuint program = %u)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program); + + if (context->skipValidation() || ValidateUseProgram(context, program)) + { + context->useProgram(program); + } + } +} + +void GL_APIENTRY ValidateProgram(GLuint program) +{ + EVENT("(GLuint program = %u)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program); + + if (context->skipValidation() || ValidateValidateProgram(context, program)) + { + context->validateProgram(program); + } + } +} + +void GL_APIENTRY VertexAttrib1f(GLuint index, GLfloat x) +{ + EVENT("(GLuint index = %u, GLfloat x = %f)", index, x); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x); + + if (context->skipValidation() || ValidateVertexAttrib1f(context, index, x)) + { + context->vertexAttrib1f(index, x); + } + } +} + +void GL_APIENTRY VertexAttrib1fv(GLuint index, const GLfloat *v) +{ + EVENT("(GLuint index = %u, const GLfloat *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttrib1fv(context, index, v)) + { + context->vertexAttrib1fv(index, v); + } + } +} + +void GL_APIENTRY VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + EVENT("(GLuint index = %u, GLfloat x = %f, GLfloat y = %f)", index, x, y); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x, y); + + if (context->skipValidation() || ValidateVertexAttrib2f(context, index, x, y)) + { + context->vertexAttrib2f(index, x, y); + } + } +} + +void GL_APIENTRY VertexAttrib2fv(GLuint index, const GLfloat *v) +{ + EVENT("(GLuint index = %u, const GLfloat *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttrib2fv(context, index, v)) + { + context->vertexAttrib2fv(index, v); + } + } +} + +void GL_APIENTRY VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + EVENT("(GLuint index = %u, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x, y, z); + + if (context->skipValidation() || ValidateVertexAttrib3f(context, index, x, y, z)) + { + context->vertexAttrib3f(index, x, y, z); + } + } +} + +void GL_APIENTRY VertexAttrib3fv(GLuint index, const GLfloat *v) +{ + EVENT("(GLuint index = %u, const GLfloat *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttrib3fv(context, index, v)) + { + context->vertexAttrib3fv(index, v); + } + } +} + +void GL_APIENTRY VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + EVENT("(GLuint index = %u, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", + index, x, y, z, w); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x, y, z, w); + + if (context->skipValidation() || ValidateVertexAttrib4f(context, index, x, y, z, w)) + { + context->vertexAttrib4f(index, x, y, z, w); + } + } +} + +void GL_APIENTRY VertexAttrib4fv(GLuint index, const GLfloat *v) +{ + EVENT("(GLuint index = %u, const GLfloat *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttrib4fv(context, index, v)) + { + context->vertexAttrib4fv(index, v); + } + } +} + +void GL_APIENTRY VertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *pointer) +{ + EVENT( + "(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLboolean normalized = %u, " + "GLsizei stride = %d, const void *pointer = 0x%0.8p)", + index, size, type, normalized, stride, pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, size, type, normalized, + stride, pointer); + + if (context->skipValidation() || + ValidateVertexAttribPointer(context, index, size, type, normalized, stride, pointer)) + { + context->vertexAttribPointer(index, size, type, normalized, stride, pointer); + } + } +} + +void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, + height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(x, y, width, height); + + if (context->skipValidation() || ValidateViewport(context, x, y, width, height)) + { + context->viewport(x, y, width, height); + } + } +} +} // namespace gl diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.h new file mode 100644 index 0000000000..7735b46fa4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_autogen.h @@ -0,0 +1,297 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_2_0_autogen.h: +// Defines the GLES 2.0 entry points. + +#ifndef LIBGLESV2_ENTRYPOINTSGLES20_AUTOGEN_H_ +#define LIBGLESV2_ENTRYPOINTSGLES20_AUTOGEN_H_ + +#include +#include + +namespace gl +{ +ANGLE_EXPORT void GL_APIENTRY ActiveTexture(GLenum texture); +ANGLE_EXPORT void GL_APIENTRY AttachShader(GLuint program, GLuint shader); +ANGLE_EXPORT void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer); +ANGLE_EXPORT void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer); +ANGLE_EXPORT void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer); +ANGLE_EXPORT void GL_APIENTRY BindTexture(GLenum target, GLuint texture); +ANGLE_EXPORT void GL_APIENTRY BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +ANGLE_EXPORT void GL_APIENTRY BlendEquation(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); +ANGLE_EXPORT void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor); +ANGLE_EXPORT void GL_APIENTRY BlendFuncSeparate(GLenum sfactorRGB, + GLenum dfactorRGB, + GLenum sfactorAlpha, + GLenum dfactorAlpha); +ANGLE_EXPORT void GL_APIENTRY BufferData(GLenum target, + GLsizeiptr size, + const void *data, + GLenum usage); +ANGLE_EXPORT void GL_APIENTRY BufferSubData(GLenum target, + GLintptr offset, + GLsizeiptr size, + const void *data); +ANGLE_EXPORT GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target); +ANGLE_EXPORT void GL_APIENTRY Clear(GLbitfield mask); +ANGLE_EXPORT void GL_APIENTRY ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +ANGLE_EXPORT void GL_APIENTRY ClearDepthf(GLfloat d); +ANGLE_EXPORT void GL_APIENTRY ClearStencil(GLint s); +ANGLE_EXPORT void GL_APIENTRY ColorMask(GLboolean red, + GLboolean green, + GLboolean blue, + GLboolean alpha); +ANGLE_EXPORT void GL_APIENTRY CompileShader(GLuint shader); +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data); +ANGLE_EXPORT void GL_APIENTRY CopyTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border); +ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height); +ANGLE_EXPORT GLuint GL_APIENTRY CreateProgram(); +ANGLE_EXPORT GLuint GL_APIENTRY CreateShader(GLenum type); +ANGLE_EXPORT void GL_APIENTRY CullFace(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint *buffers); +ANGLE_EXPORT void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint *framebuffers); +ANGLE_EXPORT void GL_APIENTRY DeleteProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); +ANGLE_EXPORT void GL_APIENTRY DeleteShader(GLuint shader); +ANGLE_EXPORT void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint *textures); +ANGLE_EXPORT void GL_APIENTRY DepthFunc(GLenum func); +ANGLE_EXPORT void GL_APIENTRY DepthMask(GLboolean flag); +ANGLE_EXPORT void GL_APIENTRY DepthRangef(GLfloat n, GLfloat f); +ANGLE_EXPORT void GL_APIENTRY DetachShader(GLuint program, GLuint shader); +ANGLE_EXPORT void GL_APIENTRY Disable(GLenum cap); +ANGLE_EXPORT void GL_APIENTRY DisableVertexAttribArray(GLuint index); +ANGLE_EXPORT void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count); +ANGLE_EXPORT void GL_APIENTRY DrawElements(GLenum mode, + GLsizei count, + GLenum type, + const void *indices); +ANGLE_EXPORT void GL_APIENTRY Enable(GLenum cap); +ANGLE_EXPORT void GL_APIENTRY EnableVertexAttribArray(GLuint index); +ANGLE_EXPORT void GL_APIENTRY Finish(); +ANGLE_EXPORT void GL_APIENTRY Flush(); +ANGLE_EXPORT void GL_APIENTRY FramebufferRenderbuffer(GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +ANGLE_EXPORT void GL_APIENTRY FramebufferTexture2D(GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level); +ANGLE_EXPORT void GL_APIENTRY FrontFace(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY GenBuffers(GLsizei n, GLuint *buffers); +ANGLE_EXPORT void GL_APIENTRY GenerateMipmap(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint *framebuffers); +ANGLE_EXPORT void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint *renderbuffers); +ANGLE_EXPORT void GL_APIENTRY GenTextures(GLsizei n, GLuint *textures); +ANGLE_EXPORT void GL_APIENTRY GetActiveAttrib(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniform(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetAttachedShaders(GLuint program, + GLsizei maxCount, + GLsizei *count, + GLuint *shaders); +ANGLE_EXPORT GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean *data); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint *params); +ANGLE_EXPORT GLenum GL_APIENTRY GetError(); +ANGLE_EXPORT void GL_APIENTRY GetFloatv(GLenum pname, GLfloat *data); +ANGLE_EXPORT void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetIntegerv(GLenum pname, GLint *data); +ANGLE_EXPORT void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetProgramInfoLog(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); +ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, + GLenum pname, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetShaderInfoLog(GLuint shader, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); +ANGLE_EXPORT void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision); +ANGLE_EXPORT void GL_APIENTRY GetShaderSource(GLuint shader, + GLsizei bufSize, + GLsizei *length, + GLchar *source); +ANGLE_EXPORT const GLubyte *GL_APIENTRY GetString(GLenum name); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint *params); +ANGLE_EXPORT GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer); +ANGLE_EXPORT void GL_APIENTRY Hint(GLenum target, GLenum mode); +ANGLE_EXPORT GLboolean GL_APIENTRY IsBuffer(GLuint buffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsEnabled(GLenum cap); +ANGLE_EXPORT GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsProgram(GLuint program); +ANGLE_EXPORT GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsShader(GLuint shader); +ANGLE_EXPORT GLboolean GL_APIENTRY IsTexture(GLuint texture); +ANGLE_EXPORT void GL_APIENTRY LineWidth(GLfloat width); +ANGLE_EXPORT void GL_APIENTRY LinkProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY PixelStorei(GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units); +ANGLE_EXPORT void GL_APIENTRY ReadPixels(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels); +ANGLE_EXPORT void GL_APIENTRY ReleaseShaderCompiler(); +ANGLE_EXPORT void GL_APIENTRY RenderbufferStorage(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height); +ANGLE_EXPORT void GL_APIENTRY SampleCoverage(GLfloat value, GLboolean invert); +ANGLE_EXPORT void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY ShaderBinary(GLsizei count, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length); +ANGLE_EXPORT void GL_APIENTRY ShaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length); +ANGLE_EXPORT void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilMask(GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass); +ANGLE_EXPORT void GL_APIENTRY StencilOpSeparate(GLenum face, + GLenum sfail, + GLenum dpfail, + GLenum dppass); +ANGLE_EXPORT void GL_APIENTRY TexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param); +ANGLE_EXPORT void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint *params); +ANGLE_EXPORT void GL_APIENTRY TexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY Uniform1f(GLint location, GLfloat v0); +ANGLE_EXPORT void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY Uniform1i(GLint location, GLint v0); +ANGLE_EXPORT void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint *value); +ANGLE_EXPORT void GL_APIENTRY Uniform2f(GLint location, GLfloat v0, GLfloat v1); +ANGLE_EXPORT void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY Uniform2i(GLint location, GLint v0, GLint v1); +ANGLE_EXPORT void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint *value); +ANGLE_EXPORT void GL_APIENTRY Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +ANGLE_EXPORT void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY Uniform3i(GLint location, GLint v0, GLint v1, GLint v2); +ANGLE_EXPORT void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint *value); +ANGLE_EXPORT void GL_APIENTRY +Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +ANGLE_EXPORT void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +ANGLE_EXPORT void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UseProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY ValidateProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib1f(GLuint index, GLfloat x); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib1fv(GLuint index, const GLfloat *v); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib2f(GLuint index, GLfloat x, GLfloat y); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib2fv(GLuint index, const GLfloat *v); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib3fv(GLuint index, const GLfloat *v); +ANGLE_EXPORT void GL_APIENTRY +VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib4fv(GLuint index, const GLfloat *v); +ANGLE_EXPORT void GL_APIENTRY VertexAttribPointer(GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *pointer); +ANGLE_EXPORT void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height); +} // namespace gl + +#endif // LIBGLESV2_ENTRYPOINTSGLES20_AUTOGEN_H_ 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 7df6fcb0cd..d4459ec287 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 @@ -12,14 +12,20 @@ #include "libANGLE/Buffer.h" #include "libANGLE/Context.h" #include "libANGLE/Error.h" +#include "libANGLE/ErrorStrings.h" #include "libANGLE/Fence.h" #include "libANGLE/Framebuffer.h" -#include "libANGLE/Shader.h" #include "libANGLE/Query.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Thread.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/queryconversions.h" +#include "libANGLE/queryutils.h" #include "libANGLE/validationES.h" #include "libANGLE/validationES2.h" #include "libANGLE/validationES3.h" +#include "libANGLE/validationES31.h" #include "common/debug.h" #include "common/utilities.h" @@ -27,6 +33,19 @@ namespace gl { +namespace +{ + +void SetRobustLengthParam(GLsizei *length, GLsizei value) +{ + if (length) + { + *length = value; + } +} + +} // anonymous namespace + void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint *ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); @@ -34,15 +53,12 @@ void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint *ids) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateGenQueriesEXT(context, n, ids)) + if (!context->skipValidation() && !ValidateGenQueriesEXT(context, n, ids)) { return; } - for (GLsizei i = 0; i < n; i++) - { - ids[i] = context->createQuery(); - } + context->genQueries(n, ids); } } @@ -53,15 +69,12 @@ void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateDeleteQueriesEXT(context, n, ids)) + if (!context->skipValidation() && !ValidateDeleteQueriesEXT(context, n, ids)) { return; } - for (int i = 0; i < n; i++) - { - context->deleteQuery(ids[i]); - } + context->deleteQueries(n, ids); } } @@ -72,7 +85,12 @@ GLboolean GL_APIENTRY IsQueryEXT(GLuint id) Context *context = GetValidGlobalContext(); if (context) { - return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; + if (!context->skipValidation() && !ValidateIsQueryEXT(context, id)) + { + return GL_FALSE; + } + + return context->isQuery(id); } return GL_FALSE; @@ -85,17 +103,12 @@ void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateBeginQueryEXT(context, target, id)) + if (!context->skipValidation() && !ValidateBeginQueryEXT(context, target, id)) { return; } - Error error = context->beginQuery(target, id); - if (error.isError()) - { - context->recordError(error); - return; - } + context->beginQuery(target, id); } } @@ -106,17 +119,12 @@ void GL_APIENTRY EndQueryEXT(GLenum target) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateEndQueryEXT(context, target)) + if (!context->skipValidation() && !ValidateEndQueryEXT(context, target)) { return; } - Error error = context->endQuery(target); - if (error.isError()) - { - context->recordError(error); - return; - } + context->endQuery(target); } } @@ -127,17 +135,12 @@ void GL_APIENTRY QueryCounterEXT(GLuint id, GLenum target) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateQueryCounterEXT(context, id, target)) + if (!context->skipValidation() && !ValidateQueryCounterEXT(context, id, target)) { return; } - Error error = context->queryCounter(id, target); - if (error.isError()) - { - context->recordError(error); - return; - } + context->queryCounter(id, target); } } @@ -170,12 +173,7 @@ void GL_APIENTRY GetQueryObjectivEXT(GLuint id, GLenum pname, GLint *params) return; } - Error error = context->getQueryObjectiv(id, pname, params); - if (error.isError()) - { - context->recordError(error); - return; - } + context->getQueryObjectiv(id, pname, params); } } @@ -191,12 +189,7 @@ void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) return; } - Error error = context->getQueryObjectuiv(id, pname, params); - if (error.isError()) - { - context->recordError(error); - return; - } + context->getQueryObjectuiv(id, pname, params); } } @@ -212,12 +205,7 @@ void GL_APIENTRY GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64 *params) return; } - Error error = context->getQueryObjecti64v(id, pname, params); - if (error.isError()) - { - context->recordError(error); - return; - } + context->getQueryObjecti64v(id, pname, params); } } @@ -233,12 +221,7 @@ void GL_APIENTRY GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64 *param return; } - Error error = context->getQueryObjectui64v(id, pname, params); - if (error.isError()) - { - context->recordError(error); - return; - } + context->getQueryObjectui64v(id, pname, params); } } @@ -251,7 +234,7 @@ void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint *fences) { if (n < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return; } @@ -278,43 +261,34 @@ void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, return; } - Error error = context->drawArraysInstanced(mode, first, count, primcount); - if (error.isError()) - { - context->recordError(error); - return; - } + context->drawArraysInstanced(mode, first, count, primcount); } } void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, + const void *indices, GLsizei primcount) { EVENT( - "(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = " + "(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void* 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; - } + context->gatherParams(mode, count, type, indices, + primcount); - Error error = - context->drawElementsInstanced(mode, count, type, indices, primcount, indexRange); - if (error.isError()) + if (!context->skipValidation() && + !ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount)) { - context->recordError(error); return; } + + context->drawElementsInstanced(mode, count, type, indices, primcount); } } @@ -327,19 +301,19 @@ void GL_APIENTRY FinishFenceNV(GLuint fence) { FenceNV *fenceObject = context->getFenceNV(fence); - if (fenceObject == NULL) + if (fenceObject == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } if (fenceObject->isSet() != GL_TRUE) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } - fenceObject->finish(); + context->handleError(fenceObject->finish()); } } @@ -352,7 +326,7 @@ void GL_APIENTRY GenFencesNV(GLsizei n, GLuint *fences) { if (n < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return; } @@ -365,39 +339,41 @@ void GL_APIENTRY GenFencesNV(GLsizei n, GLuint *fences) void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params) { - EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); + EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, + params); Context *context = GetValidGlobalContext(); if (context) { FenceNV *fenceObject = context->getFenceNV(fence); - if (fenceObject == NULL) + if (fenceObject == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } if (fenceObject->isSet() != GL_TRUE) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } switch (pname) { - case GL_FENCE_STATUS_NV: + case GL_FENCE_STATUS_NV: { // GL_NV_fence spec: - // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV - // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + // Once the status of a fence has been finished (via FinishFenceNV) or tested and + // the returned status is TRUE (via either TestFenceNV or GetFenceivNV querying the + // FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. GLboolean status = GL_TRUE; if (fenceObject->getStatus() != GL_TRUE) { Error error = fenceObject->test(&status); if (error.isError()) { - context->recordError(error); + context->handleError(error); return; } } @@ -405,15 +381,15 @@ void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params) break; } - case GL_FENCE_CONDITION_NV: + case GL_FENCE_CONDITION_NV: { *params = static_cast(fenceObject->getCondition()); break; } - default: + default: { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return; } } @@ -434,17 +410,22 @@ GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void) return GL_NO_ERROR; } -void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +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)", - shader, bufsize, length, source); + EVENT( + "(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = " + "0x%0.8p)", + shader, bufsize, length, source); Context *context = GetValidGlobalContext(); if (context) { if (bufsize < 0) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return; } @@ -452,18 +433,20 @@ void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, if (!shaderObject) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } - shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source); + shaderObject->getTranslatedSourceWithDebugInfo(context, bufsize, length, source); } } -void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { - EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", - program, location, bufSize, params); + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = " + "0x%0.8p)", + program, location, bufSize, params); Context *context = GetValidGlobalContext(); if (context) @@ -476,14 +459,15 @@ void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSiz Program *programObject = context->getProgram(program); ASSERT(programObject); - programObject->getUniformfv(location, params); + programObject->getUniformfv(context, location, params); } } -void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) +void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params) { - EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", - program, location, bufSize, params); + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", + program, location, bufSize, params); Context *context = GetValidGlobalContext(); if (context) @@ -496,7 +480,7 @@ void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSiz Program *programObject = context->getProgram(program); ASSERT(programObject); - programObject->getUniformiv(location, params); + programObject->getUniformiv(context, location, params); } } @@ -509,26 +493,33 @@ GLboolean GL_APIENTRY IsFenceNV(GLuint fence) { FenceNV *fenceObject = context->getFenceNV(fence); - if (fenceObject == NULL) + if (fenceObject == nullptr) { return 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. + // 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; } -void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei bufSize, - GLvoid *data) +void GL_APIENTRY ReadnPixelsEXT(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + void *data) { - EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " - "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", - x, y, width, height, format, type, bufSize, data); + EVENT( + "(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, void *data = 0x%0.8p)", + x, y, width, height, format, type, bufSize, data); Context *context = GetValidGlobalContext(); if (context) @@ -543,27 +534,28 @@ void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, } } -void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) { - EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + EVENT( + "(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width " + "= %d, GLsizei height = %d)", target, samples, internalformat, width, height); Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateRenderbufferStorageParametersANGLE(context, target, samples, internalformat, - width, height)) + if (!context->skipValidation() && + !ValidateRenderbufferStorageMultisampleANGLE(context, target, samples, internalformat, + width, height)) { return; } - Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - Error error = renderbuffer->setStorageMultisample(samples, internalformat, width, height); - if (error.isError()) - { - context->recordError(error); - return; - } + context->renderbufferStorageMultisample(target, samples, internalformat, width, height); } } @@ -576,22 +568,22 @@ void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition) { if (condition != GL_ALL_COMPLETED_NV) { - context->recordError(Error(GL_INVALID_ENUM)); + context->handleError(InvalidEnum()); return; } FenceNV *fenceObject = context->getFenceNV(fence); - if (fenceObject == NULL) + if (fenceObject == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } Error error = fenceObject->set(condition); if (error.isError()) { - context->recordError(error); + context->handleError(error); return; } } @@ -606,15 +598,15 @@ GLboolean GL_APIENTRY TestFenceNV(GLuint fence) { FenceNV *fenceObject = context->getFenceNV(fence); - if (fenceObject == NULL) + if (fenceObject == nullptr) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return GL_TRUE; } if (fenceObject->isSet() != GL_TRUE) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return GL_TRUE; } @@ -622,7 +614,7 @@ GLboolean GL_APIENTRY TestFenceNV(GLuint fence) Error error = fenceObject->test(&result); if (error.isError()) { - context->recordError(error); + context->handleError(error); return GL_TRUE; } @@ -632,41 +624,38 @@ GLboolean GL_APIENTRY TestFenceNV(GLuint fence) return GL_TRUE; } -void GL_APIENTRY TexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY +TexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, levels, internalformat, width, height); + EVENT( + "(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, GLsizei height = %d)", + target, levels, internalformat, width, height); Context *context = GetValidGlobalContext(); if (context) { if (!context->getExtensions().textureStorage) { - context->recordError(Error(GL_INVALID_OPERATION)); + context->handleError(InvalidOperation()); return; } - if (context->getClientVersion() < 3 && - !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, height)) + if (context->getClientMajorVersion() < 3 && + !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, + height)) { return; } - if (context->getClientVersion() >= 3 && + if (context->getClientMajorVersion() >= 3 && !ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width, height, 1)) { return; } - Extents size(width, height, 1); - Texture *texture = context->getTargetTexture(target); - Error error = texture->setStorage(target, levels, internalformat, size); - if (error.isError()) - { - context->recordError(error); - return; - } + context->texStorage2D(target, levels, internalformat, width, height); } } @@ -677,9 +666,15 @@ void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor) Context *context = GetValidGlobalContext(); if (context) { + if (!context->getExtensions().instancedArrays) + { + ANGLE_VALIDATION_ERR(context, InvalidOperation(), ExtensionNotEnabled); + return; + } + if (index >= MAX_VERTEX_ATTRIBS) { - context->recordError(Error(GL_INVALID_VALUE)); + context->handleError(InvalidValue()); return; } @@ -687,28 +682,41 @@ void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor) { 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)); + 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->handleError(InvalidOperation() << 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); + // We also output an error message to the debugger window if tracing is active, so + // that developers can see the error message. + ERR() << errorMessage; return; } } - context->setVertexAttribDivisor(index, divisor); + context->vertexAttribDivisor(index, divisor); } } -void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) +void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) { - EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " - "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " - "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", - srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); + EVENT( + "(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " + "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " + "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", + srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); Context *context = GetValidGlobalContext(); if (context) @@ -725,9 +733,12 @@ void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi } } -void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) +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); + EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, attachments = 0x%0.8p)", target, + numAttachments, attachments); Context *context = GetValidGlobalContext(); if (context) @@ -742,64 +753,68 @@ void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, co } } -void GL_APIENTRY TexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, const GLvoid* pixels) +void GL_APIENTRY TexImage3DOES(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " - "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, " - "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)", - target, level, internalformat, width, height, depth, border, format, type, pixels); + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " + "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, " + "GLenum format = 0x%X, GLenum type = 0x%x, const void* pixels = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, format, type, pixels); - UNIMPLEMENTED(); // FIXME + UNIMPLEMENTED(); // FIXME } -void GL_APIENTRY GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) +void GL_APIENTRY GetProgramBinaryOES(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) { - EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)", - program, bufSize, length, binaryFormat, binary); + EVENT( + "(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = " + "0x%0.8p)", + program, bufSize, length, binaryFormat, binary); Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateGetProgramBinaryOES(context, program, bufSize, length, binaryFormat, binary)) + if (!context->skipValidation() && + !ValidateGetProgramBinaryOES(context, program, bufSize, length, binaryFormat, binary)) { return; } - Program *programObject = context->getProgram(program); - ASSERT(programObject != nullptr); - - Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length); - if (error.isError()) - { - context->recordError(error); - return; - } + context->getProgramBinary(program, bufSize, length, binaryFormat, binary); } } -void GL_APIENTRY ProgramBinaryOES(GLuint program, GLenum binaryFormat, const void *binary, GLint length) +void GL_APIENTRY ProgramBinaryOES(GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) { - EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", - program, binaryFormat, binary, length); + EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", program, + binaryFormat, binary, length); Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateProgramBinaryOES(context, program, binaryFormat, binary, length)) + if (!context->skipValidation() && + !ValidateProgramBinaryOES(context, program, binaryFormat, binary, length)) { return; } - Program *programObject = context->getProgram(program); - ASSERT(programObject != nullptr); - - Error error = programObject->loadBinary(binaryFormat, binary, length); - if (error.isError()) - { - context->recordError(error); - return; - } + context->programBinary(program, binaryFormat, binary, length); } } @@ -819,35 +834,23 @@ void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs) } } -void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, void** params) +void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, void **params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, void** params = 0x%0.8p)", target, pname, + params); Context *context = GetValidGlobalContext(); if (context) { - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } + BufferBinding targetPacked = FromGLenum(target); - if (pname != GL_BUFFER_MAP_POINTER) + if (!context->skipValidation() && + !ValidateGetBufferPointervOES(context, targetPacked, pname, params)) { - context->recordError(Error(GL_INVALID_ENUM)); return; } - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer || !buffer->isMapped()) - { - *params = NULL; - } - else - { - *params = buffer->getMapPointer(); - } + context->getBufferPointerv(targetPacked, pname, params); } } @@ -858,43 +861,17 @@ void *GL_APIENTRY MapBufferOES(GLenum target, GLenum access) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return NULL; - } + BufferBinding targetPacked = FromGLenum(target); - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - if (access != GL_WRITE_ONLY_OES) - { - context->recordError(Error(GL_INVALID_ENUM)); - return NULL; - } - - if (buffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - Error error = buffer->map(access); - if (error.isError()) + if (!context->skipValidation() && !ValidateMapBufferOES(context, targetPacked, access)) { - context->recordError(error); - return NULL; + return nullptr; } - return buffer->getMapPointer(); + return context->mapBuffer(targetPacked, access); } - return NULL; + return nullptr; } GLboolean GL_APIENTRY UnmapBufferOES(GLenum target) @@ -904,174 +881,63 @@ GLboolean GL_APIENTRY UnmapBufferOES(GLenum target) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return GL_FALSE; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL || !buffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } + BufferBinding targetPacked = FromGLenum(target); - GLboolean result; - Error error = buffer->unmap(&result); - if (error.isError()) + if (!context->skipValidation() && !ValidateUnmapBufferOES(context, targetPacked)) { - context->recordError(error); return GL_FALSE; } - return result; + return context->unmapBuffer(targetPacked); } return GL_FALSE; } -void *GL_APIENTRY MapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +void *GL_APIENTRY MapBufferRangeEXT(GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", - target, offset, length, access); + EVENT( + "(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = " + "0x%X)", + target, offset, length, access); Context *context = GetValidGlobalContext(); if (context) { - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return NULL; - } - - if (offset < 0 || length < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return NULL; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - // Check for buffer overflow - size_t offsetSize = static_cast(offset); - size_t lengthSize = static_cast(length); - - if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || - offsetSize + lengthSize > static_cast(buffer->getSize())) - { - context->recordError(Error(GL_INVALID_VALUE)); - return NULL; - } - - // Check for invalid bits in the mask - GLbitfield allAccessBits = GL_MAP_READ_BIT | - GL_MAP_WRITE_BIT | - GL_MAP_INVALIDATE_RANGE_BIT | - GL_MAP_INVALIDATE_BUFFER_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_UNSYNCHRONIZED_BIT; - - if (access & ~(allAccessBits)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return NULL; - } - - if (length == 0 || buffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - // Check for invalid bit combinations - if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - GLbitfield writeOnlyBits = GL_MAP_INVALIDATE_RANGE_BIT | - GL_MAP_INVALIDATE_BUFFER_BIT | - GL_MAP_UNSYNCHRONIZED_BIT; - - if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } + BufferBinding targetPacked = FromGLenum(target); - Error error = buffer->mapRange(offset, length, access); - if (error.isError()) + if (!context->skipValidation() && + !ValidateMapBufferRangeEXT(context, targetPacked, offset, length, access)) { - context->recordError(error); - return NULL; + return nullptr; } - return buffer->getMapPointer(); + return context->mapBufferRange(targetPacked, offset, length, access); } - return NULL; + return nullptr; } void GL_APIENTRY FlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length) { - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, + length); Context *context = GetValidGlobalContext(); if (context) { - if (offset < 0 || length < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // Check for buffer overflow - size_t offsetSize = static_cast(offset); - size_t lengthSize = static_cast(length); + BufferBinding targetPacked = FromGLenum(target); - if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || - offsetSize + lengthSize > static_cast(buffer->getMapLength())) + if (!context->skipValidation() && + !ValidateFlushMappedBufferRangeEXT(context, targetPacked, offset, length)) { - context->recordError(Error(GL_INVALID_VALUE)); return; } - // We do not currently support a non-trivial implementation of FlushMappedBufferRange + context->flushMappedBufferRange(targetPacked, offset, length); } } @@ -1087,7 +953,7 @@ void GL_APIENTRY InsertEventMarkerEXT(GLsizei length, const char *marker) { // 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")); + context->handleError(InvalidOperation() << "Extension not enabled"); return; } @@ -1112,7 +978,7 @@ void GL_APIENTRY PushGroupMarkerEXT(GLsizei length, const char *marker) { // 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")); + context->handleError(InvalidOperation() << "Extension not enabled"); return; } @@ -1146,7 +1012,7 @@ void GL_APIENTRY PopGroupMarkerEXT() { // 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")); + context->handleError(InvalidOperation() << "Extension not enabled"); return; } @@ -1161,18 +1027,17 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglIma Context *context = GetValidGlobalContext(); if (context) { - egl::Display *display = egl::GetGlobalDisplay(); egl::Image *imageObject = reinterpret_cast(image); - if (!ValidateEGLImageTargetTexture2DOES(context, display, target, imageObject)) + if (!ValidateEGLImageTargetTexture2DOES(context, target, imageObject)) { return; } Texture *texture = context->getTargetTexture(target); - Error error = texture->setEGLImageTarget(target, imageObject); + Error error = texture->setEGLImageTarget(context, target, imageObject); if (error.isError()) { - context->recordError(error); + context->handleError(error); return; } } @@ -1186,18 +1051,17 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target Context *context = GetValidGlobalContext(); if (context) { - egl::Display *display = egl::GetGlobalDisplay(); egl::Image *imageObject = reinterpret_cast(image); - if (!ValidateEGLImageTargetRenderbufferStorageOES(context, display, target, imageObject)) + if (!ValidateEGLImageTargetRenderbufferStorageOES(context, target, imageObject)) { return; } - Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - Error error = renderbuffer->setStorageEGLImageTarget(imageObject); + Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); + Error error = renderbuffer->setStorageEGLImageTarget(context, imageObject); if (error.isError()) { - context->recordError(error); + context->handleError(error); return; } } @@ -1210,7 +1074,7 @@ void GL_APIENTRY BindVertexArrayOES(GLuint array) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateBindVertexArrayOES(context, array)) + if (!context->skipValidation() && !ValidateBindVertexArrayOES(context, array)) { return; } @@ -1226,18 +1090,12 @@ void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arrays) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateDeleteVertexArraysOES(context, n)) + if (!context->skipValidation() && !ValidateDeleteVertexArraysOES(context, n, arrays)) { return; } - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - if (arrays[arrayIndex] != 0) - { - context->deleteVertexArray(arrays[arrayIndex]); - } - } + context->deleteVertexArrays(n, arrays); } } @@ -1248,15 +1106,12 @@ void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateGenVertexArraysOES(context, n)) + if (!context->skipValidation() && !ValidateGenVertexArraysOES(context, n, arrays)) { return; } - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - arrays[arrayIndex] = context->createVertexArray(); - } + context->genVertexArrays(n, arrays); } } @@ -1267,19 +1122,12 @@ GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidateIsVertexArrayOES(context)) - { - return GL_FALSE; - } - - if (array == 0) + if (!context->skipValidation() && !ValidateIsVertexArrayOES(context, array)) { return GL_FALSE; } - VertexArray *vao = context->getVertexArray(array); - - return (vao != nullptr ? GL_TRUE : GL_FALSE); + return context->isVertexArray(array); } return GL_FALSE; @@ -1305,9 +1153,7 @@ void GL_APIENTRY DebugMessageControlKHR(GLenum source, return; } - std::vector idVector(ids, ids + count); - context->getState().getDebug().setMessageControl( - source, type, severity, std::move(idVector), (enabled != GL_FALSE)); + context->debugMessageControl(source, type, severity, count, ids, enabled); } } @@ -1331,8 +1177,7 @@ void GL_APIENTRY DebugMessageInsertKHR(GLenum source, return; } - std::string msg(buf, (length > 0) ? static_cast(length) : strlen(buf)); - context->getState().getDebug().insertMessage(source, type, id, severity, std::move(msg)); + context->debugMessageInsert(source, type, id, severity, length, buf); } } @@ -1349,7 +1194,7 @@ void GL_APIENTRY DebugMessageCallbackKHR(GLDEBUGPROCKHR callback, const void *us return; } - context->getState().getDebug().setCallback(callback, userParam); + context->debugMessageCallback(callback, userParam); } } @@ -1377,8 +1222,8 @@ GLuint GL_APIENTRY GetDebugMessageLogKHR(GLuint count, return 0; } - return static_cast(context->getState().getDebug().getMessages( - count, bufSize, sources, types, ids, severities, lengths, messageLog)); + return context->getDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, + messageLog); } return 0; @@ -1400,7 +1245,7 @@ void GL_APIENTRY PushDebugGroupKHR(GLenum source, GLuint id, GLsizei length, con } std::string msg(message, (length > 0) ? static_cast(length) : strlen(message)); - context->getState().getDebug().pushGroup(source, id, std::move(msg)); + context->pushDebugGroup(source, id, length, message); } } @@ -1416,7 +1261,7 @@ void GL_APIENTRY PopDebugGroupKHR(void) return; } - context->getState().getDebug().popGroup(); + context->popDebugGroup(); } } @@ -1435,11 +1280,7 @@ void GL_APIENTRY ObjectLabelKHR(GLenum identifier, GLuint name, GLsizei length, return; } - LabeledObject *object = context->getLabeledObject(identifier, name); - ASSERT(object != nullptr); - - std::string lbl(label, (length > 0) ? static_cast(length) : strlen(label)); - object->setLabel(lbl); + context->objectLabel(identifier, name, length, label); } } @@ -1459,14 +1300,7 @@ GetObjectLabelKHR(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *leng 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); + context->getObjectLabel(identifier, name, bufSize, length, label); } } @@ -1483,11 +1317,7 @@ void GL_APIENTRY ObjectPtrLabelKHR(const void *ptr, GLsizei length, const GLchar return; } - LabeledObject *object = context->getLabeledObjectFromPtr(ptr); - ASSERT(object != nullptr); - - std::string lbl(label, (length > 0) ? static_cast(length) : strlen(label)); - object->setLabel(lbl); + context->objectPtrLabel(ptr, length, label); } } @@ -1509,14 +1339,7 @@ void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr, 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); + context->getObjectPtrLabel(ptr, bufSize, length, label); } } @@ -1535,4 +1358,2201 @@ void GL_APIENTRY GetPointervKHR(GLenum pname, void **params) context->getPointerv(pname, params); } } + +ANGLE_EXPORT void GL_APIENTRY BindUniformLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name) +{ + EVENT("(GLuint program = %u, GLint location = %d, const GLchar *name = 0x%0.8p)", program, + location, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateBindUniformLocationCHROMIUM(context, program, location, name)) + { + return; + } + + context->bindUniformLocation(program, location, name); + } +} + +ANGLE_EXPORT void GL_APIENTRY CoverageModulationCHROMIUM(GLenum components) +{ + EVENT("(GLenum components = %u)", components); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateCoverageModulationCHROMIUM(context, components)) + { + return; + } + context->setCoverageModulation(components); + } +} + +// CHROMIUM_path_rendering +ANGLE_EXPORT void GL_APIENTRY MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat *matrix) +{ + EVENT("(GLenum matrixMode = %u)", matrixMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateMatrix(context, matrixMode, matrix)) + { + return; + } + context->loadPathRenderingMatrix(matrixMode, matrix); + } +} + +ANGLE_EXPORT void GL_APIENTRY MatrixLoadIdentityCHROMIUM(GLenum matrixMode) +{ + EVENT("(GLenum matrixMode = %u)", matrixMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateMatrixMode(context, matrixMode)) + { + return; + } + context->loadPathRenderingIdentityMatrix(matrixMode); + } +} + +ANGLE_EXPORT GLuint GL_APIENTRY GenPathsCHROMIUM(GLsizei range) +{ + EVENT("(GLsizei range = %d)", range); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateGenPaths(context, range)) + { + return 0; + } + return context->createPaths(range); + } + return 0; } + +ANGLE_EXPORT void GL_APIENTRY DeletePathsCHROMIUM(GLuint first, GLsizei range) +{ + EVENT("(GLuint first = %u, GLsizei range = %d)", first, range); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateDeletePaths(context, first, range)) + { + return; + } + context->deletePaths(first, range); + } +} + +ANGLE_EXPORT GLboolean GL_APIENTRY IsPathCHROMIUM(GLuint path) +{ + EVENT("(GLuint path = %u)", path); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateIsPath(context)) + { + return GL_FALSE; + } + return context->hasPathData(path); + } + return GL_FALSE; +} + +ANGLE_EXPORT void GL_APIENTRY PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + EVENT( + "(GLuint path = %u, GLsizei numCommands = %d, commands = %p, " + "GLsizei numCoords = %d, GLenum coordType = %u, void* coords = %p)", + path, numCommands, commands, numCoords, coordType, coords); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation()) + { + if (!ValidatePathCommands(context, path, numCommands, commands, numCoords, coordType, + coords)) + { + return; + } + } + context->setPathCommands(path, numCommands, commands, numCoords, coordType, coords); + } +} + +ANGLE_EXPORT void GL_APIENTRY PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) +{ + EVENT("(GLuint path = %u, GLenum pname = %u, GLfloat value = %f)", path, pname, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateSetPathParameter(context, path, pname, value)) + { + return; + } + context->setPathParameterf(path, pname, value); + } +} + +ANGLE_EXPORT void GL_APIENTRY PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) +{ + PathParameterfCHROMIUM(path, pname, static_cast(value)); +} + +ANGLE_EXPORT void GL_APIENTRY GetPathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat *value) +{ + EVENT("(GLuint path = %u, GLenum pname = %u)", path, pname); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateGetPathParameter(context, path, pname, value)) + { + return; + } + context->getPathParameterfv(path, pname, value); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetPathParameteriCHROMIUM(GLuint path, GLenum pname, GLint *value) +{ + GLfloat val = 0.0f; + GetPathParameterfCHROMIUM(path, pname, value != nullptr ? &val : nullptr); + if (value) + *value = static_cast(val); +} + +ANGLE_EXPORT void GL_APIENTRY PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum func = %u, GLint ref = %d, GLuint mask = %u)", func, ref, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidatePathStencilFunc(context, func, ref, mask)) + { + return; + } + context->setPathStencilFunc(func, ref, mask); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask) +{ + EVENT("(GLuint path = %u, GLenum fillMode = %u, GLuint mask = %u)", path, fillMode, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateStencilFillPath(context, path, fillMode, mask)) + { + return; + } + context->stencilFillPath(path, fillMode, mask); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask) +{ + EVENT("(GLuint path = %u, GLint ference = %d, GLuint mask = %u)", path, reference, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilStrokePath(context, path, reference, mask)) + { + return; + } + context->stencilStrokePath(path, reference, mask); + } +} + +ANGLE_EXPORT void GL_APIENTRY CoverFillPathCHROMIUM(GLuint path, GLenum coverMode) +{ + EVENT("(GLuint path = %u, GLenum coverMode = %u)", path, coverMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateCoverPath(context, path, coverMode)) + { + return; + } + context->coverFillPath(path, coverMode); + } +} + +ANGLE_EXPORT void GL_APIENTRY CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) +{ + EVENT("(GLuint path = %u, GLenum coverMode = %u)", path, coverMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateCoverPath(context, path, coverMode)) + { + return; + } + context->coverStrokePath(path, coverMode); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + EVENT("(GLuint path = %u, GLenum fillMode = %u, GLuint mask = %u, GLenum coverMode = %u)", path, + fillMode, mask, coverMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilThenCoverFillPath(context, path, fillMode, mask, coverMode)) + { + return; + } + context->stencilThenCoverFillPath(path, fillMode, mask, coverMode); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + EVENT("(GLuint path = %u, GLint reference = %d, GLuint mask = %u, GLenum coverMode = %u)", path, + reference, mask, coverMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilThenCoverStrokePath(context, path, reference, mask, coverMode)) + { + return; + } + context->stencilThenCoverStrokePath(path, reference, mask, coverMode); + } +} + +ANGLE_EXPORT void GL_APIENTRY CoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %d, GLenum pathNameType = %u, const void *paths = %p " + "GLuint pathBase = %u, GLenum coverMode = %u, GLenum transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, coverMode, transformType, transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCoverFillPathInstanced(context, numPaths, pathNameType, paths, pathBase, + coverMode, transformType, transformValues)) + { + return; + } + context->coverFillPathInstanced(numPaths, pathNameType, paths, pathBase, coverMode, + transformType, transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY CoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %d, GLenum pathNameType = %u, const void *paths = %p " + "GLuint pathBase = %u, GLenum coverMode = %u, GLenum transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, coverMode, transformType, transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCoverStrokePathInstanced(context, numPaths, pathNameType, paths, pathBase, + coverMode, transformType, transformValues)) + { + return; + } + context->coverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, coverMode, + transformType, transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %u, GLenum pathNameType = %u, const void *paths = %p " + "GLuint pathBase = %u, GLint reference = %d GLuint mask = %u GLenum transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, reference, mask, transformType, transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilStrokePathInstanced(context, numPaths, pathNameType, paths, pathBase, + reference, mask, transformType, transformValues)) + { + return; + } + context->stencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase, reference, + mask, transformType, transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY StencilFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %u, GLenum pathNameType = %u const void *paths = %p " + "GLuint pathBase = %u, GLenum fillMode = %u, GLuint mask = %u, GLenum transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, fillMode, mask, transformType, transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilFillPathInstanced(context, numPaths, pathNameType, paths, pathBase, + fillMode, mask, transformType, transformValues)) + { + return; + } + context->stencilFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode, mask, + transformType, transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY +StencilThenCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %u, GLenum pathNameType = %u const void *paths = %p " + "GLuint pathBase = %u, GLenum coverMode = %u, GLuint mask = %u, GLenum transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, coverMode, mask, transformType, transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilThenCoverFillPathInstanced(context, numPaths, pathNameType, paths, + pathBase, fillMode, mask, coverMode, + transformType, transformValues)) + { + return; + } + context->stencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, + fillMode, mask, coverMode, transformType, + transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY +StencilThenCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + EVENT( + "(GLsizei numPaths = %u, GLenum pathNameType = %u, const void *paths = %p " + "GLuint pathBase = %u GLenum coverMode = %u GLint reference = %d GLuint mask = %u GLenum " + "transformType = %u " + "const GLfloat *transformValues = %p)", + numPaths, pathNameType, paths, pathBase, coverMode, reference, mask, transformType, + transformValues); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateStencilThenCoverStrokePathInstanced(context, numPaths, pathNameType, paths, + pathBase, reference, mask, coverMode, + transformType, transformValues)) + { + return; + } + context->stencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, + reference, mask, coverMode, transformType, + transformValues); + } +} + +ANGLE_EXPORT void GL_APIENTRY BindFragmentInputLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name) +{ + EVENT("(GLuint program = %u, GLint location = %d, const GLchar *name = %p)", program, location, + name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateBindFragmentInputLocation(context, program, location, name)) + { + return; + } + context->bindFragmentInputLocation(program, location, name); + } +} + +ANGLE_EXPORT void GL_APIENTRY ProgramPathFragmentInputGenCHROMIUM(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + EVENT( + "(GLuint program = %u, GLint location %d, GLenum genMode = %u, GLint components = %d, " + "const GLfloat * coeffs = %p)", + program, location, genMode, components, coeffs); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateProgramPathFragmentInputGen(context, program, location, genMode, components, + coeffs)) + { + return; + } + context->programPathFragmentInputGen(program, location, genMode, components, coeffs); + } +} + +ANGLE_EXPORT void GL_APIENTRY CopyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + EVENT( + "(GLuint sourceId = %u, GLint sourceLevel = %d, GLenum destTarget = 0x%X, GLuint destId = " + "%u, GLint destLevel = %d, GLint internalFormat = 0x%X, GLenum destType = " + "0x%X, GLboolean unpackFlipY = %u, GLboolean unpackPremultiplyAlpha = %u, GLboolean " + "unpackUnmultiplyAlpha = %u)", + sourceId, sourceLevel, destTarget, destId, destLevel, internalFormat, destType, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCopyTextureCHROMIUM(context, sourceId, sourceLevel, destTarget, destId, + destLevel, internalFormat, destType, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)) + { + return; + } + + context->copyTextureCHROMIUM(sourceId, sourceLevel, destTarget, destId, destLevel, + internalFormat, destType, unpackFlipY, unpackPremultiplyAlpha, + unpackUnmultiplyAlpha); + } +} + +ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha) +{ + EVENT( + "(GLuint sourceId = %u, GLint sourceLevel = %d, GLenum destTarget = 0x%X, GLuint destId = " + "%u, GLint destLevel = %d, GLint xoffset = " + "%d, GLint yoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = " + "%d, GLboolean unpackPremultiplyAlpha = %u, GLboolean unpackUnmultiplyAlpha = %u)", + sourceId, sourceLevel, destTarget, destId, destLevel, xoffset, yoffset, x, y, width, height, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCopySubTextureCHROMIUM( + context, sourceId, sourceLevel, destTarget, destId, destLevel, xoffset, yoffset, x, + y, width, height, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)) + { + return; + } + + context->copySubTextureCHROMIUM(sourceId, sourceLevel, destTarget, destId, destLevel, + xoffset, yoffset, x, y, width, height, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha); + } +} + +ANGLE_EXPORT void GL_APIENTRY CompressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId) +{ + EVENT("(GLuint sourceId = %u, GLuint destId = %u)", sourceId, destId); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCompressedCopyTextureCHROMIUM(context, sourceId, destId)) + { + return; + } + + context->compressedCopyTextureCHROMIUM(sourceId, destId); + } +} + +ANGLE_EXPORT void GL_APIENTRY RequestExtensionANGLE(const GLchar *name) +{ + EVENT("(const GLchar *name = %p)", name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateRequestExtensionANGLE(context, name)) + { + return; + } + + context->requestExtension(name); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetBooleanvRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLboolean *params) +{ + EVENT( + "(GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLboolean* params " + "= 0x%0.8p)", + pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams)) + { + return; + } + + context->getBooleanv(pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetBufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + + GLsizei numParams = 0; + if (!ValidateGetBufferParameterivRobustANGLE(context, targetPacked, pname, bufSize, + &numParams, params)) + { + return; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(targetPacked); + QueryBufferParameteriv(buffer, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetFloatvRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLfloat* params = " + "0x%0.8p)", + pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams)) + { + return; + } + + context->getFloatv(pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetFramebufferAttachmentParameterivRobustANGLE(GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = " + "%d, GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)", + target, attachment, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetFramebufferAttachmentParameterivRobustANGLE(context, target, attachment, + pname, bufSize, &numParams)) + { + return; + } + + const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target); + QueryFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetIntegervRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *data) +{ + EVENT( + "(GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLint* params = " + "0x%0.8p)", + pname, bufSize, length, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams)) + { + return; + } + + context->getIntegerv(pname, data); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetProgramivRobustANGLE(GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %d, GLenum pname = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint* params = 0x%0.8p)", + program, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetProgramivRobustANGLE(context, program, pname, bufSize, &numParams)) + { + return; + } + + Program *programObject = context->getProgram(program); + QueryProgramiv(context, programObject, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + target, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetRenderbufferParameterivRobustANGLE(context, target, pname, bufSize, + &numParams, params)) + { + return; + } + + Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); + QueryRenderbufferiv(context, renderbuffer, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY +GetShaderivRobustANGLE(GLuint shader, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params) +{ + EVENT( + "(GLuint shader = %d, GLenum pname = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint* params = 0x%0.8p)", + shader, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetShaderivRobustANGLE(context, shader, pname, bufSize, &numParams, params)) + { + return; + } + + Shader *shaderObject = context->getShader(shader); + QueryShaderiv(context, shaderObject, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetTexParameterfvRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLfloat* params = 0x%0.8p)", + target, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetTexParameterfvRobustANGLE(context, target, pname, bufSize, &numParams, + params)) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + QueryTexParameterfv(texture, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetTexParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLfloat* params = 0x%0.8p)", + target, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetTexParameterivRobustANGLE(context, target, pname, bufSize, &numParams, + params)) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + QueryTexParameteriv(texture, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetUniformfvRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLfloat* params = 0x%0.8p)", + program, location, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetUniformfvRobustANGLE(context, program, location, bufSize, &writeLength, + params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformfv(context, location, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetUniformivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + program, location, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetUniformivRobustANGLE(context, program, location, bufSize, &writeLength, + params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformiv(context, location, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribfvRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLuint index = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLfloat* params = 0x%0.8p)", + index, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetVertexAttribfvRobustANGLE(context, index, pname, bufSize, &writeLength, + params)) + { + return; + } + + context->getVertexAttribfv(index, pname, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint index = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint* params = 0x%0.8p)", + index, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetVertexAttribivRobustANGLE(context, index, pname, bufSize, &writeLength, + params)) + { + return; + } + + context->getVertexAttribiv(index, pname, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribPointervRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer) +{ + EVENT( + "(GLuint index = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "void** pointer = 0x%0.8p)", + index, pname, bufSize, length, pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetVertexAttribPointervRobustANGLE(context, index, pname, bufSize, + &writeLength, pointer)) + { + return; + } + + context->getVertexAttribPointerv(index, pname, pointer); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY ReadPixelsRobustANGLE(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels) +{ + EVENT( + "(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLsizei* columns = 0x%0.8p, GLsizei* rows = 0x%0.8p, void* pixels = 0x%0.8p)", + x, y, width, height, format, type, bufSize, length, columns, rows, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + GLsizei writeColumns = 0; + GLsizei writeRows = 0; + if (!ValidateReadPixelsRobustANGLE(context, x, y, width, height, format, type, bufSize, + &writeLength, &writeColumns, &writeRows, pixels)) + { + return; + } + + context->readPixels(x, y, width, height, format, type, pixels); + + SetRobustLengthParam(length, writeLength); + SetRobustLengthParam(columns, writeColumns); + SetRobustLengthParam(rows, writeRows); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexImage2DRobustANGLE(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " + "GLsizei height = %d, GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, GLsizei " + "bufSize = %d, const void* pixels = 0x%0.8p)", + target, level, internalformat, width, height, border, format, type, bufSize, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexImage2DRobust(context, target, level, internalformat, width, height, border, + format, type, bufSize, pixels)) + { + return; + } + + context->texImage2D(target, level, internalformat, width, height, border, format, type, + pixels); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexParameterfvRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLfloat* params = " + "0x%0.8p)", + target, pname, bufSize, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexParameterfvRobustANGLE(context, target, pname, bufSize, params)) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + SetTexParameterfv(context, texture, pname, params); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLfloat* params = " + "0x%0.8p)", + target, pname, bufSize, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexParameterivRobustANGLE(context, target, pname, bufSize, params)) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + SetTexParameteriv(context, texture, pname, params); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexSubImage2DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " + "GLsizei bufsize = %d, const void* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, type, bufSize, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexSubImage2DRobustANGLE(context, target, level, xoffset, yoffset, width, + height, format, type, bufSize, pixels)) + { + return; + } + + context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, + pixels); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexImage3DRobustANGLE(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, " + "GLenum type = 0x%X, GLsizei bufsize = %d, const void* pixels = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, format, type, bufSize, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexImage3DRobustANGLE(context, target, level, internalformat, width, height, + depth, border, format, type, bufSize, pixels)) + { + return; + } + + context->texImage3D(target, level, internalformat, width, height, depth, border, format, + type, pixels); + } +} + +ANGLE_EXPORT void GL_APIENTRY TexSubImage3DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufsize = %d, const void* pixels = " + "0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, + pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexSubImage3DRobustANGLE(context, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, bufSize, pixels)) + { + return; + } + + context->texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, pixels); + } +} + +void GL_APIENTRY CompressedTexImage2DRobustANGLE(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, " + "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, GLsizei dataSize = %d, " + "const GLvoid* data = 0x%0.8p)", + target, level, internalformat, width, height, border, imageSize, dataSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCompressedTexImage2DRobustANGLE(context, target, level, internalformat, width, + height, border, imageSize, dataSize, data)) + { + return; + } + + context->compressedTexImage2D(target, level, internalformat, width, height, border, + imageSize, data); + } +} + +void GL_APIENTRY CompressedTexSubImage2DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, " + "GLsizei imageSize = %d, GLsizei dataSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, imageSize, dataSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateCompressedTexSubImage2DRobustANGLE( + context, target, level, xoffset, yoffset, width, + height, format, imageSize, dataSize, data)) + { + return; + } + + context->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + imageSize, data); + } +} + +void GL_APIENTRY CompressedTexImage3DRobustANGLE(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, " + "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " + "GLsizei dataSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, imageSize, dataSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && !ValidateCompressedTexImage3DRobustANGLE( + context, target, level, internalformat, width, height, + depth, border, imageSize, dataSize, data)) + { + return; + } + + context->compressedTexImage3D(target, level, internalformat, width, height, depth, border, + imageSize, data); + } +} + +void GL_APIENTRY CompressedTexSubImage3DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLsizei imageSize = %d, GLsizei dataSize = %d, const GLvoid* data = " + "0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, dataSize, + data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateCompressedTexSubImage3DRobustANGLE(context, target, level, xoffset, yoffset, + zoffset, width, height, depth, format, + imageSize, dataSize, data)) + { + return; + } + + context->compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, + depth, format, imageSize, data); + } +} + +ANGLE_EXPORT void GL_APIENTRY +GetQueryivRobustANGLE(GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + target, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetQueryivRobustANGLE(context, target, pname, bufSize, &numParams, params)) + { + return; + } + + context->getQueryiv(target, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuivRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLuint id = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint* params = 0x%0.8p)", + id, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetQueryObjectuivRobustANGLE(context, id, pname, bufSize, &numParams, params)) + { + return; + } + + context->getQueryObjectuiv(id, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetBufferPointervRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, void** params = 0x%0.8p)", + target, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + + GLsizei numParams = 0; + if (!ValidateGetBufferPointervRobustANGLE(context, targetPacked, pname, bufSize, &numParams, + params)) + { + return; + } + + context->getBufferPointerv(targetPacked, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY +GetIntegeri_vRobustANGLE(GLenum target, GLuint index, GLsizei bufSize, GLsizei *length, GLint *data) +{ + EVENT( + "(GLenum target = 0x%X, GLuint index = %u, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* data = 0x%0.8p)", + target, index, bufSize, length, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetIntegeri_vRobustANGLE(context, target, index, bufSize, &numParams, data)) + { + return; + } + + context->getIntegeri_v(target, index, data); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetInternalformativRobustANGLE(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize " + "= %d, GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)", + target, internalformat, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetInternalFormativRobustANGLE(context, target, internalformat, pname, bufSize, + &numParams, params)) + { + return; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + QueryInternalFormativ(formatCaps, pname, bufSize, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint index = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint* params = 0x%0.8p)", + index, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetVertexAttribIivRobustANGLE(context, index, pname, bufSize, &writeLength, + params)) + { + return; + } + + context->getVertexAttribIiv(index, pname, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIuivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLuint index = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLuint* params = 0x%0.8p)", + index, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetVertexAttribIuivRobustANGLE(context, index, pname, bufSize, &writeLength, + params)) + { + return; + } + + context->getVertexAttribIuiv(index, pname, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetUniformuivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLuint* params = 0x%0.8p)", + program, location, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetUniformuivRobustANGLE(context, program, location, bufSize, &writeLength, + params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformuiv(context, location, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockivRobustANGLE(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLsizei bufsize " + "= %d, GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)", + program, uniformBlockIndex, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + if (!ValidateGetActiveUniformBlockivRobustANGLE(context, program, uniformBlockIndex, pname, + bufSize, &writeLength, params)) + { + return; + } + + const Program *programObject = context->getProgram(program); + QueryActiveUniformBlockiv(programObject, uniformBlockIndex, pname, params); + SetRobustLengthParam(length, writeLength); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetInteger64vRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *data) +{ + EVENT( + "(GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLint64* params = " + "0x%0.8p)", + pname, bufSize, length, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_INT_64_ANGLEX) + { + context->getInteger64v(pname, data); + } + else + { + CastStateValues(context, nativeType, pname, numParams, data); + } + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetInteger64i_vRobustANGLE(GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data) +{ + EVENT( + "(GLenum target = 0x%X, GLuint index = %u, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint64* data = 0x%0.8p)", + target, index, bufSize, length, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetInteger64i_vRobustANGLE(context, target, index, bufSize, &numParams, data)) + { + return; + } + + context->getInteger64i_v(target, index, data); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteri64vRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", target, pname, + bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + + GLsizei numParams = 0; + if (!ValidateGetBufferParameteri64vRobustANGLE(context, targetPacked, pname, bufSize, + &numParams, params)) + { + return; + } + + Buffer *buffer = context->getGLState().getTargetBuffer(targetPacked); + QueryBufferParameteri64v(buffer, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY SamplerParameterivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *param) +{ + EVENT( + "(GLuint sampler = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLint* params = " + "0x%0.8p)", + sampler, pname, bufSize, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateSamplerParameterivRobustANGLE(context, sampler, pname, bufSize, param)) + { + return; + } + + context->samplerParameteriv(sampler, pname, param); + } +} + +ANGLE_EXPORT void GL_APIENTRY SamplerParameterfvRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *param) +{ + EVENT( + "(GLuint sampler = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLfloat* params = " + "0x%0.8p)", + sampler, pname, bufSize, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateSamplerParameterfvRobustANGLE(context, sampler, pname, bufSize, param)) + { + return; + } + + context->samplerParameterfv(sampler, pname, param); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint sampler = %u, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + sampler, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetSamplerParameterivRobustANGLE(context, sampler, pname, bufSize, &numParams, + params)) + { + return; + } + + context->getSamplerParameteriv(sampler, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterfvRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLuint sample = %ur, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLfloat* params = 0x%0.8p)", + sampler, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetSamplerParameterfvRobustANGLE(context, sampler, pname, bufSize, &numParams, + params)) + { + return; + } + + context->getSamplerParameterfv(sampler, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetFramebufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + target, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetProgramInterfaceivRobustANGLE(GLuint program, + GLenum programInterface, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLenum programInterface = 0x%X, GLenum pname = 0x%X, GLsizei " + "bufsize = %d, GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)", + program, programInterface, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetBooleani_vRobustANGLE(GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data) +{ + EVENT( + "(GLenum target = 0x%X, GLuint index = %u, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLboolean* data = 0x%0.8p)", + target, index, bufSize, length, data); + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetBooleani_vRobustANGLE(context, target, index, bufSize, &numParams, data)) + { + return; + } + + context->getBooleani_v(target, index, data); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetMultisamplefvRobustANGLE(GLenum pname, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLfloat *val) +{ + EVENT( + "(GLenum pname = 0x%X, GLuint index = %u, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLfloat* val = 0x%0.8p)", + pname, index, bufSize, length, val); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameterivRobustANGLE(GLenum target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, " + "GLsizei* length = 0x%0.8p, GLint* params = 0x%0.8p)", + target, level, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameterfvRobustANGLE(GLenum target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, " + "GLsizei* length = 0x%0.8p, GLfloat* params = 0x%0.8p)", + target, level, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetPointervRobustANGLERobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params) +{ + EVENT( + "(GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, void **params = " + "0x%0.8p)", + pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY ReadnPixelsRobustANGLE(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data) +{ + EVENT( + "(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLsizei* columns = 0x%0.8p, GLsizei* rows = 0x%0.8p, void *data = 0x%0.8p)", + x, y, width, height, format, type, bufSize, length, columns, rows, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei writeLength = 0; + GLsizei writeColumns = 0; + GLsizei writeRows = 0; + if (!ValidateReadnPixelsRobustANGLE(context, x, y, width, height, format, type, bufSize, + &writeLength, &writeColumns, &writeRows, data)) + { + return; + } + + context->readPixels(x, y, width, height, format, type, data); + + SetRobustLengthParam(length, writeLength); + SetRobustLengthParam(columns, writeColumns); + SetRobustLengthParam(rows, writeRows); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetnUniformfvRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLfloat* params = 0x%0.8p)", + program, location, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetnUniformivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %d, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint* params = 0x%0.8p)", + program, location, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetnUniformuivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLuint* params = 0x%0.8p)", + program, location, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY TexParameterIivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLint *params = " + "0x%0.8p)", + target, pname, bufSize, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY TexParameterIuivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLuint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLuint *params = " + "0x%0.8p)", + target, pname, bufSize, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetTexParameterIivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint *params = 0x%0.8p)", + target, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetTexParameterIuivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLuint *params = 0x%0.8p)", + target, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY SamplerParameterIivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *param) +{ + EVENT( + "(GLuint sampler = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLint *param = " + "0x%0.8p)", + sampler, pname, bufSize, param); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY SamplerParameterIuivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLuint *param) +{ + EVENT( + "(GLuint sampler = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, const GLuint *param = " + "0x%0.8p)", + sampler, pname, bufSize, param); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterIivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint sampler = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLint *params = 0x%0.8p)", + sampler, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterIuivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params) +{ + EVENT( + "(GLuint sampler = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = " + "0x%0.8p, GLuint *params = 0x%0.8p)", + sampler, pname, bufSize, length, params); + UNIMPLEMENTED(); +} + +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectivRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint id = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLuint *params = 0x%0.8p)", + id, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetQueryObjectivRobustANGLE(context, id, pname, bufSize, &numParams, params)) + { + return; + } + + context->getQueryObjectiv(id, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetQueryObjecti64vRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params) +{ + EVENT( + "(GLuint id = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLint64 *params = 0x%0.8p)", + id, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetQueryObjecti64vRobustANGLE(context, id, pname, bufSize, &numParams, params)) + { + return; + } + + context->getQueryObjecti64v(id, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params) +{ + EVENT( + "(GLuint id = %d, GLenum pname = 0x%X, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, " + "GLuint64 *params = 0x%0.8p)", + id, pname, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLsizei numParams = 0; + if (!ValidateGetQueryObjectui64vRobustANGLE(context, id, pname, bufSize, &numParams, + params)) + { + return; + } + + context->getQueryObjectui64v(id, pname, params); + SetRobustLengthParam(length, numParams); + } +} + +GL_APICALL void GL_APIENTRY FramebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, " + "GLint baseViewIndex = %d, GLsizei numViews = %d)", + target, attachment, texture, level, baseViewIndex, numViews); + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateFramebufferTextureMultiviewLayeredANGLE(context, target, attachment, texture, + level, baseViewIndex, numViews)) + { + return; + } + context->framebufferTextureMultiviewLayeredANGLE(target, attachment, texture, level, + baseViewIndex, numViews); + } +} + +GL_APICALL void GL_APIENTRY FramebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, " + "GLsizei numViews = %d, GLsizei* viewportOffsets = 0x%0.8p)", + target, attachment, texture, level, numViews, viewportOffsets); + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->skipValidation() && + !ValidateFramebufferTextureMultiviewSideBySideANGLE( + context, target, attachment, texture, level, numViews, viewportOffsets)) + { + return; + } + context->framebufferTextureMultiviewSideBySideANGLE(target, attachment, texture, level, + numViews, viewportOffsets); + } +} + +} // gl 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 a2fb9c5e80..2a3fa607cf 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 @@ -17,17 +17,32 @@ namespace gl { // GL_ANGLE_framebuffer_blit -ANGLE_EXPORT void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +ANGLE_EXPORT void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter); // GL_ANGLE_framebuffer_multisample -ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +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); +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); +ANGLE_EXPORT void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint *fences); +ANGLE_EXPORT void GL_APIENTRY GenFencesNV(GLsizei n, GLuint *fences); ANGLE_EXPORT GLboolean GL_APIENTRY IsFenceNV(GLuint fence); ANGLE_EXPORT GLboolean GL_APIENTRY TestFenceNV(GLuint fence); ANGLE_EXPORT void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params); @@ -35,16 +50,36 @@ ANGLE_EXPORT void GL_APIENTRY FinishFenceNV(GLuint fence); ANGLE_EXPORT void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition); // GL_ANGLE_translated_shader_source -ANGLE_EXPORT void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); +ANGLE_EXPORT void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source); // GL_EXT_texture_storage -ANGLE_EXPORT void GL_APIENTRY TexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY TexStorage2DEXT(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height); // GL_EXT_robustness ANGLE_EXPORT GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void); -ANGLE_EXPORT void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -ANGLE_EXPORT void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params); -ANGLE_EXPORT void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params); +ANGLE_EXPORT void GL_APIENTRY ReadnPixelsEXT(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + void *data); +ANGLE_EXPORT void GL_APIENTRY GetnUniformfvEXT(GLuint program, + GLint location, + GLsizei bufSize, + float *params); +ANGLE_EXPORT void GL_APIENTRY GetnUniformivEXT(GLuint program, + GLint location, + GLsizei bufSize, + GLint *params); // GL_EXT_occlusion_query_boolean ANGLE_EXPORT void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint *ids); @@ -65,22 +100,41 @@ ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vEXT(GLuint id, GLenum pname, GL ANGLE_EXPORT void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs); // GL_ANGLE_instanced_arrays -ANGLE_EXPORT void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount); -ANGLE_EXPORT void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +ANGLE_EXPORT void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount); +ANGLE_EXPORT void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount); ANGLE_EXPORT void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor); // GL_OES_get_program_binary -ANGLE_EXPORT void GL_APIENTRY GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -ANGLE_EXPORT void GL_APIENTRY ProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); +ANGLE_EXPORT void GL_APIENTRY GetProgramBinaryOES(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary); +ANGLE_EXPORT void GL_APIENTRY ProgramBinaryOES(GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length); // GL_OES_mapbuffer ANGLE_EXPORT void *GL_APIENTRY MapBufferOES(GLenum target, GLenum access); ANGLE_EXPORT GLboolean GL_APIENTRY UnmapBufferOES(GLenum target); -ANGLE_EXPORT void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, GLvoid **params); +ANGLE_EXPORT void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, void **params); // GL_EXT_map_buffer_range -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); +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); @@ -140,6 +194,524 @@ ANGLE_EXPORT void GL_APIENTRY GetObjectPtrLabelKHR(const void *ptr, GLsizei *length, GLchar *label); ANGLE_EXPORT void GL_APIENTRY GetPointervKHR(GLenum pname, void **params); -} -#endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_ +// GL_CHROMIUM_bind_uniform_location +ANGLE_EXPORT void GL_APIENTRY BindUniformLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name); + +// GL_CHROMIUM_framebuffer_mixed_samples +ANGLE_EXPORT void GL_APIENTRY MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat *matrix); +ANGLE_EXPORT void GL_APIENTRY MatrixLoadIdentityCHROMIUM(GLenum matrixMode); + +ANGLE_EXPORT void GL_APIENTRY CoverageModulationCHROMIUM(GLenum components); + +// GL_CHROMIUM_path_rendering +ANGLE_EXPORT GLuint GL_APIENTRY GenPathsCHROMIUM(GLsizei chromium); +ANGLE_EXPORT void GL_APIENTRY DeletePathsCHROMIUM(GLuint first, GLsizei range); +ANGLE_EXPORT GLboolean GL_APIENTRY IsPathCHROMIUM(GLuint path); +ANGLE_EXPORT void GL_APIENTRY PathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords); +ANGLE_EXPORT void GL_APIENTRY PathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value); +ANGLE_EXPORT void GL_APIENTRY PathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value); +ANGLE_EXPORT void GL_APIENTRY GetPathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY GetPathParameteriCHROMIUM(GLuint path, GLenum pname, GLint *value); +ANGLE_EXPORT void GL_APIENTRY PathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY CoverFillPathCHROMIUM(GLuint path, GLenum coverMode); +ANGLE_EXPORT void GL_APIENTRY CoverStrokePathCHROMIUM(GLuint path, GLenum coverMode); +ANGLE_EXPORT void GL_APIENTRY StencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode); +ANGLE_EXPORT void GL_APIENTRY StencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode); +ANGLE_EXPORT void GL_APIENTRY CoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY CoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY StencilFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBAse, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY StencilStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY +StencilThenCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY +StencilThenCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues); +ANGLE_EXPORT void GL_APIENTRY BindFragmentInputLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY ProgramPathFragmentInputGenCHROMIUM(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs); + +// GL_CHROMIUM_copy_texture +ANGLE_EXPORT void GL_APIENTRY CopyTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint internalFormat, + GLenum destType, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + +ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId, + GLint sourceLevel, + GLenum destTarget, + GLuint destId, + GLint destLevel, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpackFlipY, + GLboolean unpackPremultiplyAlpha, + GLboolean unpackUnmultiplyAlpha); + +// GL_CHROMIUM_copy_compressed_texture +ANGLE_EXPORT void GL_APIENTRY CompressedCopyTextureCHROMIUM(GLuint sourceId, GLuint destId); + +// GL_ANGLE_request_extension +ANGLE_EXPORT void GL_APIENTRY RequestExtensionANGLE(const GLchar *name); + +// GL_ANGLE_robust_client_memory +ANGLE_EXPORT void GL_APIENTRY GetBooleanvRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLboolean *data); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetFloatvRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *data); +ANGLE_EXPORT void GL_APIENTRY GetFramebufferAttachmentParameterivRobustANGLE(GLenum target, + GLenum attachment, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetIntegervRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *data); +ANGLE_EXPORT void GL_APIENTRY GetProgramivRobustANGLE(GLuint program, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetShaderivRobustANGLE(GLuint shader, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterfvRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetUniformfvRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetUniformivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribfvRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribPointervRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **pointer); +ANGLE_EXPORT void GL_APIENTRY ReadPixelsRobustANGLE(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *pixels); +ANGLE_EXPORT void GL_APIENTRY TexImage2DRobustANGLE(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY TexParameterfvRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY TexParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params); +ANGLE_EXPORT void GL_APIENTRY TexSubImage2DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); + +ANGLE_EXPORT void GL_APIENTRY TexImage3DRobustANGLE(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY TexSubImage3DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + GLsizei bufSize, + const void *pixels); + +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage2DRobustANGLE(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage2DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage3DRobustANGLE(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage3DRobustANGLE(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + GLsizei dataSize, + const GLvoid *data); + +ANGLE_EXPORT void GL_APIENTRY +GetQueryivRobustANGLE(GLenum target, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuivRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY GetBufferPointervRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params); +ANGLE_EXPORT void GL_APIENTRY GetIntegeri_vRobustANGLE(GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint *data); +ANGLE_EXPORT void GL_APIENTRY GetInternalformativRobustANGLE(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIuivRobustANGLE(GLuint index, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY GetUniformuivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockivRobustANGLE(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetInteger64vRobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *data); +ANGLE_EXPORT void GL_APIENTRY GetInteger64i_vRobustANGLE(GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLint64 *data); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteri64vRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterfvRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLfloat *param); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterfvRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); + +ANGLE_EXPORT void GL_APIENTRY GetFramebufferParameterivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetProgramInterfaceivRobustANGLE(GLuint program, + GLenum programInterface, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetBooleani_vRobustANGLE(GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data); +ANGLE_EXPORT void GL_APIENTRY GetMultisamplefvRobustANGLE(GLenum pname, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLfloat *val); +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameterivRobustANGLE(GLenum target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameterfvRobustANGLE(GLenum target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); + +ANGLE_EXPORT void GL_APIENTRY GetPointervRobustANGLERobustANGLE(GLenum pname, + GLsizei bufSize, + GLsizei *length, + void **params); +ANGLE_EXPORT void GL_APIENTRY ReadnPixelsRobustANGLE(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + GLsizei *length, + GLsizei *columns, + GLsizei *rows, + void *data); +ANGLE_EXPORT void GL_APIENTRY GetnUniformfvRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY GetnUniformivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetnUniformuivRobustANGLE(GLuint program, + GLint location, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY TexParameterIivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLint *params); +ANGLE_EXPORT void GL_APIENTRY TexParameterIuivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + const GLuint *params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterIivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterIuivRobustANGLE(GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterIivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLint *param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterIuivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + const GLuint *param); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterIivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterIuivRobustANGLE(GLuint sampler, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectivRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjecti64vRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint64 *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vRobustANGLE(GLuint id, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLuint64 *params); + +// GL_ANGLE_multiview +ANGLE_EXPORT void GL_APIENTRY FramebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews); +ANGLE_EXPORT void GL_APIENTRY +FramebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets); +} // namespace gl + +#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 deleted file mode 100644 index 856129aa07..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp +++ /dev/null @@ -1,3057 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_3_0.cpp : Implements the GLES 3.0 entry points. - -#include "libGLESv2/entry_points_gles_3_0.h" -#include "libGLESv2/entry_points_gles_2_0_ext.h" -#include "libGLESv2/global_state.h" - -#include "libANGLE/formatutils.h" -#include "libANGLE/Buffer.h" -#include "libANGLE/Context.h" -#include "libANGLE/Error.h" -#include "libANGLE/Fence.h" -#include "libANGLE/Framebuffer.h" -#include "libANGLE/Query.h" -#include "libANGLE/VertexArray.h" - -#include "libANGLE/validationES.h" -#include "libANGLE/validationES3.h" -#include "libANGLE/queryconversions.h" - -#include "common/debug.h" - -namespace gl -{ - -void GL_APIENTRY ReadBuffer(GLenum mode) -{ - EVENT("(GLenum mode = 0x%X)", mode); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && !ValidateReadBuffer(context, mode)) - { - return; - } - - context->readBuffer(mode); - } -} - -void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) -{ - EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, " - "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - IndexRange indexRange; - if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange)) - { - return; - } - if (indexRange.end > end || indexRange.start < start) - { - // GL spec says that behavior in this case is undefined - generating an error is fine. - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // As long as index validation is done, it doesn't matter whether the context receives a drawElements or - // 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->drawRangeElements(mode, start, end, count, type, indices, indexRange); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " - "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, " - "GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", - target, level, internalformat, width, height, depth, border, format, type, pixels); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - 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(context, target, level, internalformat, size, format, type, - reinterpret_cast(pixels)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " - "GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", - target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImage3DParameters(context, target, level, GL_NONE, false, true, xoffset, - yoffset, zoffset, width, height, depth, 0, format, - type, pixels)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0 || depth == 0) - { - return; - } - - Box area(xoffset, yoffset, zoffset, width, height, depth); - Texture *texture = context->getTargetTexture(target); - Error error = texture->setSubImage(context, target, level, area, format, type, - reinterpret_cast(pixels)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", - target, level, xoffset, yoffset, zoffset, x, y, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateCopyTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, x, y, - width, height)) - { - return; - } - - context->copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); - } -} - -void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " - "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " - "const GLvoid* data = 0x%0.8p)", - target, level, internalformat, width, height, depth, border, imageSize, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - 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(context, target, level, internalformat, size, imageSize, - reinterpret_cast(data)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) -{ - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " - "GLenum format = 0x%X, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", - target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const InternalFormat &formatInfo = GetInternalFormatInfo(format); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!data) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImage3DParameters(context, target, level, GL_NONE, true, true, 0, 0, 0, - width, height, depth, 0, GL_NONE, GL_NONE, data)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0) - { - return; - } - - Box area(xoffset, yoffset, zoffset, width, height, depth); - Texture *texture = context->getTargetTexture(target); - Error error = - texture->setCompressedSubImage(context, target, level, area, format, imageSize, - reinterpret_cast(data)); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids) -{ - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGenQueries(context, n, ids)) - { - return; - } - - for (GLsizei i = 0; i < n; i++) - { - ids[i] = context->createQuery(); - } - } -} - -void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids) -{ - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateDeleteQueries(context, n, ids)) - { - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteQuery(ids[i]); - } - } -} - -GLboolean GL_APIENTRY IsQuery(GLuint id) -{ - EVENT("(GLuint id = %u)", id); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; - } - - return GL_FALSE; -} - -void GL_APIENTRY BeginQuery(GLenum target, GLuint id) -{ - EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateBeginQuery(context, target, id)) - { - return; - } - - Error error = context->beginQuery(target, id); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY EndQuery(GLenum target) -{ - EVENT("(GLenum target = 0x%X)", target); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateEndQuery(context, target)) - { - return; - } - - Error error = context->endQuery(target); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY GetQueryiv(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 (!ValidateGetQueryiv(context, target, pname, params)) - { - return; - } - - context->getQueryiv(target, pname, params); - } -} - -void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) -{ - EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGetQueryObjectuiv(context, id, pname, params)) - { - return; - } - - Error error = context->getQueryObjectuiv(id, pname, params); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -GLboolean GL_APIENTRY UnmapBuffer(GLenum target) -{ - EVENT("(GLenum target = 0x%X)", target); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return UnmapBufferOES(target); - } - - return GL_FALSE; -} - -void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - GetBufferPointervOES(target, pname, params); - } -} - -void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs) -{ - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && !ValidateDrawBuffers(context, n, bufs)) - { - return; - } - - context->drawBuffers(n, bufs); - } -} - -void GL_APIENTRY UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x3, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix2x3fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x2, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix3x2fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x4, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix2x4fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x2, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix4x2fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x4, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix3x4fv(location, count, transpose, value); - } -} - -void GL_APIENTRY UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x3, location, count, transpose)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniformMatrix4x3fv(location, count, transpose, value); - } -} - -void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) -{ - EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, GLint dstX0 = %d, " - "GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, GLbitfield mask = 0x%X, GLenum filter = 0x%X)", - srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateBlitFramebuffer(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, - dstY1, mask, filter)) - { - return; - } - - context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, - filter); - } -} - -void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, samples, internalformat, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3RenderbufferStorageParameters(context, target, samples, internalformat, width, height)) - { - return; - } - - Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - renderbuffer->setStorageMultisample(samples, internalformat, width, height); - } -} - -void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) -{ - EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)", - target, attachment, texture, level, layer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateFramebufferTextureLayer(context, target, attachment, texture, level, layer)) - { - return; - } - - context->framebufferTextureLayer(target, attachment, texture, level, layer); - } -} - -GLvoid *GL_APIENTRY MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) -{ - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", - target, offset, length, access); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - return MapBufferRangeEXT(target, offset, length, access); - } - - return NULL; -} - -void GL_APIENTRY FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) -{ - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - FlushMappedBufferRangeEXT(target, offset, length); - } -} - -void GL_APIENTRY BindVertexArray(GLuint array) -{ - EVENT("(GLuint array = %u)", array); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateBindVertexArray(context, array)) - { - return; - } - - context->bindVertexArray(array); - } -} - -void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint* arrays) -{ - EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateDeleteVertexArrays(context, n)) - { - return; - } - - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - if (arrays[arrayIndex] != 0) - { - context->deleteVertexArray(arrays[arrayIndex]); - } - } - } -} - -void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint* arrays) -{ - EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGenVertexArrays(context, n)) - { - return; - } - - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - arrays[arrayIndex] = context->createVertexArray(); - } - } -} - -GLboolean GL_APIENTRY IsVertexArray(GLuint array) -{ - EVENT("(GLuint array = %u)", array); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateIsVertexArray(context)) - { - return GL_FALSE; - } - - if (array == 0) - { - return GL_FALSE; - } - - VertexArray *vao = context->getVertexArray(array); - - return (vao != NULL ? GL_TRUE : GL_FALSE); - } - - return GL_FALSE; -} - -void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint* data) -{ - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)", - target, index, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_BINDING: - if (index >= caps.maxCombinedUniformBlocks) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (!(context->getIndexedIntegerv(target, index, data))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (numParams == 0) - { - return; // it is known that pname is valid, but there are no parameters to return - } - - if (nativeType == GL_INT_64_ANGLEX) - { - GLint64 minIntValue = static_cast(std::numeric_limits::min()); - GLint64 maxIntValue = static_cast(std::numeric_limits::max()); - GLint64 *int64Params = new GLint64[numParams]; - - context->getIndexedInteger64v(target, index, int64Params); - - for (unsigned int i = 0; i < numParams; ++i) - { - GLint64 clampedValue = std::max(std::min(int64Params[i], maxIntValue), minIntValue); - data[i] = static_cast(clampedValue); - } - - delete [] int64Params; - } - else - { - UNREACHABLE(); - } - } - } -} - -void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode) -{ - EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (primitiveMode) - { - case GL_TRIANGLES: - case GL_LINES: - case GL_POINTS: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - if (transformFeedback->isActive()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (transformFeedback->isPaused()) - { - transformFeedback->resume(); - } - else - { - transformFeedback->begin(primitiveMode); - } - } -} - -void GL_APIENTRY EndTransformFeedback(void) -{ - EVENT("(void)"); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - if (!transformFeedback->isActive()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - transformFeedback->end(); - } -} - -void GL_APIENTRY BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) -{ - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)", - target, index, buffer, offset, size); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (buffer != 0 && size <= 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - { - // size and offset must be a multiple of 4 - if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - // 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->isActive()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size); - context->bindGenericTransformFeedbackBuffer(buffer); - break; - } - - case GL_UNIFORM_BUFFER: - - // it is an error to bind an offset not a multiple of the alignment - if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->bindIndexedUniformBuffer(buffer, index, offset, size); - context->bindGenericUniformBuffer(buffer); - break; - - default: - UNREACHABLE(); - } - } -} - -void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer) -{ - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", - target, index, buffer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK_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->isActive()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0); - context->bindGenericTransformFeedbackBuffer(buffer); - break; - } - case GL_UNIFORM_BUFFER: - context->bindIndexedUniformBuffer(buffer, index, 0, 0); - context->bindGenericUniformBuffer(buffer); - break; - - default: - UNREACHABLE(); - } - } -} - -void GL_APIENTRY TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) -{ - EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)", - program, count, varyings, bufferMode); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - const Caps &caps = context->getCaps(); - switch (bufferMode) - { - case GL_INTERLEAVED_ATTRIBS: - break; - case GL_SEPARATE_ATTRIBS: - if (static_cast(count) > caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); - } -} - -void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) -{ - EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, " - "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", - program, index, bufSize, length, size, type, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (bufSize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return; - } - - if (index >= static_cast(programObject->getTransformFeedbackVaryingCount())) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); - } -} - -void GL_APIENTRY VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) -{ - EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)", - index, size, type, stride, pointer); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (size < 1 || size > 4) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (type) - { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_INT_2_10_10_10_REV: - case GL_UNSIGNED_INT_2_10_10_10_REV: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (stride < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // [OpenGL ES 3.0.2] Section 2.8 page 24: - // An INVALID_OPERATION error is generated when a non-zero vertex array object - // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, - // and the pointer argument is not NULL. - if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && pointer != NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, false, true, - stride, pointer); - } -} - -void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) -{ - EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - index, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.IntValues[i]; - } - } - else - { - const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); - *params = QuerySingleVertexAttributeParameter(attribState, pname); - } - } -} - -void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) -{ - EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)", - index, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (!ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.UnsignedIntValues[i]; - } - } - else - { - const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); - *params = QuerySingleVertexAttributeParameter(attribState, pname); - } - } -} - -void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) -{ - EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", - index, x, y, z, w); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLint vals[4] = { x, y, z, w }; - context->getState().setVertexAttribi(index, vals); - } -} - -void GL_APIENTRY VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) -{ - EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", - index, x, y, z, w); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - GLuint vals[4] = { x, y, z, w }; - context->getState().setVertexAttribu(index, vals); - } -} - -void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint* v) -{ - EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribi(index, v); - } -} - -void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint* v) -{ - EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribu(index, v); - } -} - -void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint* params) -{ - EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)", - program, location, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGetUniformuiv(context, program, location, params)) - { - return; - } - - Program *programObject = context->getProgram(program); - ASSERT(programObject); - - programObject->getUniformuiv(location, params); - } -} - -GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name) -{ - EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", - program, name); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return -1; - } - - if (program == 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return -1; - } - - Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return -1; - } - - return programObject->getFragDataLocation(name); - } - - return 0; -} - -void GL_APIENTRY Uniform1ui(GLint location, GLuint v0) -{ - Uniform1uiv(location, 1, &v0); -} - -void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1) -{ - const GLuint xy[] = { v0, v1 }; - Uniform2uiv(location, 1, xy); -} - -void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) -{ - const GLuint xyz[] = { v0, v1, v2 }; - Uniform3uiv(location, 1, xyz); -} - -void GL_APIENTRY Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) -{ - const GLuint xyzw[] = { v0, v1, v2, v3 }; - Uniform4uiv(location, 1, xyzw); -} - -void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform1uiv(location, count, value); - } -} - -void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC2, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform2uiv(location, count, value); - } -} - -void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)", - location, count, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC3, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform3uiv(location, count, value); - } -} - -void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint* value) -{ - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC4, location, count)) - { - return; - } - - Program *program = context->getState().getProgram(); - program->setUniform4uiv(location, count, value); - } -} - -void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) -{ - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)", - buffer, drawbuffer, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateClearBufferiv(context, buffer, drawbuffer, value)) - { - return; - } - - context->clearBufferiv(buffer, drawbuffer, value); - } -} - -void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) -{ - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)", - buffer, drawbuffer, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateClearBufferuiv(context, buffer, drawbuffer, value)) - { - return; - } - - context->clearBufferuiv(buffer, drawbuffer, value); - } -} - -void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) -{ - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)", - buffer, drawbuffer, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateClearBufferfv(context, buffer, drawbuffer, value)) - { - return; - } - - context->clearBufferfv(buffer, drawbuffer, value); - } -} - -void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) -{ - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)", - buffer, drawbuffer, depth, stencil); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateClearBufferfi(context, buffer, drawbuffer, depth, stencil)) - { - return; - } - - context->clearBufferfi(buffer, drawbuffer, depth, stencil); - } -} - -const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index) -{ - EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return NULL; - } - - if (name != GL_EXTENSIONS) - { - context->recordError(Error(GL_INVALID_ENUM)); - return NULL; - } - - if (index >= context->getExtensionStringCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return NULL; - } - - return reinterpret_cast(context->getExtensionString(index).c_str()); - } - - return NULL; -} - -void GL_APIENTRY CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) -{ - EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)", - readTarget, writeTarget, readOffset, writeOffset, size); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidBufferTarget(context, readTarget) || !ValidBufferTarget(context, writeTarget)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *readBuffer = context->getState().getTargetBuffer(readTarget); - Buffer *writeBuffer = context->getState().getTargetBuffer(writeTarget); - - if (!readBuffer || !writeBuffer) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - // Verify that readBuffer and writeBuffer are not currently mapped - if (readBuffer->isMapped() || writeBuffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (readOffset < 0 || writeOffset < 0 || size < 0 || - static_cast(readOffset + size) > readBuffer->getSize() || - static_cast(writeOffset + size) > writeBuffer->getSize()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (readBuffer == writeBuffer && std::abs(readOffset - writeOffset) < size) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - // if size is zero, the copy is a successful no-op - if (size > 0) - { - Error error = writeBuffer->copyBufferSubData(readBuffer, readOffset, writeOffset, size); - if (error.isError()) - { - context->recordError(error); - return; - } - } - } -} - -void GL_APIENTRY GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) -{ - EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)", - program, uniformCount, uniformNames, uniformIndices); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformCount < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (!programObject->isLinked()) - { - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - uniformIndices[uniformId] = GL_INVALID_INDEX; - } - } - else - { - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]); - } - } - } -} - -void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) -{ - EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - program, uniformCount, uniformIndices, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformCount < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - switch (pname) - { - case GL_UNIFORM_TYPE: - case GL_UNIFORM_SIZE: - case GL_UNIFORM_NAME_LENGTH: - case GL_UNIFORM_BLOCK_INDEX: - case GL_UNIFORM_OFFSET: - case GL_UNIFORM_ARRAY_STRIDE: - case GL_UNIFORM_MATRIX_STRIDE: - case GL_UNIFORM_IS_ROW_MAJOR: - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (uniformCount > programObject->getActiveUniformCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - const GLuint index = uniformIndices[uniformId]; - - if (index >= static_cast(programObject->getActiveUniformCount())) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - } - - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - const GLuint index = uniformIndices[uniformId]; - params[uniformId] = programObject->getActiveUniformi(index, pname); - } - } -} - -GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) -{ - EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_INVALID_INDEX; - } - - Program *programObject = GetValidProgram(context, program); - if (!programObject) - { - return GL_INVALID_INDEX; - } - - return programObject->getUniformBlockIndex(uniformBlockName); - } - - return 0; -} - -void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) -{ - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - program, uniformBlockIndex, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - case GL_UNIFORM_BLOCK_BINDING: - *params = static_cast(programObject->getUniformBlockBinding(uniformBlockIndex)); - break; - - case GL_UNIFORM_BLOCK_DATA_SIZE: - case GL_UNIFORM_BLOCK_NAME_LENGTH: - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: - case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: - case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params); - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) -{ - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)", - program, uniformBlockIndex, bufSize, length, uniformBlockName); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); - } -} - -void GL_APIENTRY UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) -{ - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", - program, uniformBlockIndex, uniformBlockBinding); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Program *programObject = GetValidProgram(context, program); - - if (!programObject) - { - return; - } - - // if never linked, there won't be any uniform blocks - if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); - } -} - -void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) -{ - EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)", - mode, first, count, instanceCount); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateDrawArraysInstanced(context, mode, first, count, instanceCount)) - { - return; - } - - Error error = context->drawArraysInstanced(mode, first, count, instanceCount); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) -{ - EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)", - mode, count, type, indices, instanceCount); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - IndexRange indexRange; - if (!ValidateDrawElementsInstanced(context, mode, count, type, indices, instanceCount, &indexRange)) - { - return; - } - - Error error = - context->drawElementsInstanced(mode, count, type, indices, instanceCount, indexRange); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -GLsync GL_APIENTRY FenceSync_(GLenum condition, GLbitfield flags) -{ - EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return 0; - } - - if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return 0; - } - - if (flags != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return 0; - } - - GLsync fenceSync = context->createFenceSync(); - - FenceSync *fenceSyncObject = context->getFenceSync(fenceSync); - Error error = fenceSyncObject->set(condition, flags); - if (error.isError()) - { - context->deleteFenceSync(fenceSync); - context->recordError(error); - return NULL; - } - - return fenceSync; - } - - return NULL; -} - -GLboolean GL_APIENTRY IsSync(GLsync sync) -{ - EVENT("(GLsync sync = 0x%0.8p)", sync); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return (context->getFenceSync(sync) != NULL); - } - - return GL_FALSE; -} - -void GL_APIENTRY DeleteSync(GLsync sync) -{ - EVENT("(GLsync sync = 0x%0.8p)", sync); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (sync != static_cast(0) && !context->getFenceSync(sync)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->deleteFenceSync(sync); - } -} - -GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) -{ - EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", - sync, flags, timeout); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_WAIT_FAILED; - } - - if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return GL_WAIT_FAILED; - } - - FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(Error(GL_INVALID_VALUE)); - return GL_WAIT_FAILED; - } - - GLenum result = GL_WAIT_FAILED; - Error error = fenceSync->clientWait(flags, timeout, &result); - if (error.isError()) - { - context->recordError(error); - return GL_WAIT_FAILED; - } - - return result; - } - - return GL_FALSE; -} - -void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) -{ - EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", - sync, flags, timeout); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (flags != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - if (timeout != GL_TIMEOUT_IGNORED) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - Error error = fenceSync->serverWait(flags, timeout); - if (error.isError()) - { - context->recordError(error); - } - } -} - -void GL_APIENTRY GetInteger64v(GLenum pname, GLint64* params) -{ - EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", - pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_INT_64_ANGLEX) - { - context->getInteger64v(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } -} - -void GL_APIENTRY GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) -{ - EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)", - sync, pname, bufSize, length, values); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (bufSize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - 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] = static_cast(fenceSync->getFlags()); break; - - case GL_SYNC_STATUS: - { - Error error = fenceSync->getStatus(values); - if (error.isError()) - { - context->recordError(error); - return; - } - break; - } - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64* data) -{ - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)", - target, index, data); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_BINDING: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (!(context->getIndexedInteger64v(target, index, data))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (numParams == 0) - return; // it is known that pname is valid, but there are no parameters to return - - if (nativeType == GL_INT) - { - GLint *intParams = new GLint[numParams]; - - context->getIndexedIntegerv(target, index, intParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - data[i] = static_cast(intParams[i]); - } - - delete [] intParams; - } - else - { - UNREACHABLE(); - } - } - } -} - -void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", - target, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidBufferTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (!ValidBufferParameter(context, pname)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - // A null buffer means that "0" is bound to the requested buffer target - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (pname) - { - case GL_BUFFER_USAGE: - *params = static_cast(buffer->getUsage()); - break; - case GL_BUFFER_SIZE: - *params = buffer->getSize(); - break; - case GL_BUFFER_ACCESS_FLAGS: - *params = static_cast(buffer->getAccessFlags()); - break; - case GL_BUFFER_MAPPED: - *params = static_cast(buffer->isMapped()); - break; - case GL_BUFFER_MAP_OFFSET: - *params = buffer->getMapOffset(); - break; - case GL_BUFFER_MAP_LENGTH: - *params = buffer->getMapLength(); - break; - default: UNREACHABLE(); break; - } - } -} - -void GL_APIENTRY GenSamplers(GLsizei count, GLuint* samplers) -{ - EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < count; i++) - { - samplers[i] = context->createSampler(); - } - } -} - -void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint* samplers) -{ - EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < count; i++) - { - context->deleteSampler(samplers[i]); - } - } -} - -GLboolean GL_APIENTRY IsSampler(GLuint sampler) -{ - EVENT("(GLuint sampler = %u)", sampler); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return context->isSampler(sampler); - } - - return GL_FALSE; -} - -void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler) -{ - EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (sampler != 0 && !context->isSampler(sampler)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (unit >= context->getCaps().maxCombinedTextureImageUnits) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->bindSampler(unit, sampler); - } -} - -void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param) -{ - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!ValidateTexParamParameters(context, pname, param)) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->samplerParameteri(sampler, pname, param); - } -} - -void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) -{ - SamplerParameteri(sampler, pname, *param); -} - -void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) -{ - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!ValidateTexParamParameters(context, pname, static_cast(param))) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - context->samplerParameterf(sampler, pname, param); - } -} - -void GL_APIENTRY SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) -{ - SamplerParameterf(sampler, pname, *param); -} - -void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) -{ - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - *params = context->getSamplerParameteri(sampler, pname); - } -} - -void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) -{ - EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - *params = context->getSamplerParameterf(sampler, pname); - } -} - -void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor) -{ - EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= MAX_VERTEX_ATTRIBS) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - context->setVertexAttribDivisor(index, divisor); - } -} - -void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id) -{ - EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK: - { - // 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->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->isTransformFeedbackGenerated(id)) - { - context->recordError( - Error(GL_INVALID_OPERATION, - "Cannot bind a transform feedback object that does not exist.")); - return; - } - - context->bindTransformFeedback(id); - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) -{ - EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteTransformFeedback(ids[i]); - } - } -} - -void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint* ids) -{ - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - for (int i = 0; i < n; i++) - { - ids[i] = context->createTransformFeedback(); - } - } -} - -GLboolean GL_APIENTRY IsTransformFeedback(GLuint id) -{ - EVENT("(GLuint id = %u)", id); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return 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; -} - -void GL_APIENTRY PauseTransformFeedback(void) -{ - EVENT("(void)"); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - // 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; - } - - transformFeedback->pause(); - } -} - -void GL_APIENTRY ResumeTransformFeedback(void) -{ - EVENT("(void)"); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - // 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; - } - - transformFeedback->resume(); - } -} - -void GL_APIENTRY GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) -{ - EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)", - program, bufSize, length, binaryFormat, binary); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateGetProgramBinary(context, program, bufSize, length, binaryFormat, binary)) - { - return; - } - - Program *programObject = context->getProgram(program); - ASSERT(programObject != nullptr); - - Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) -{ - EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", - program, binaryFormat, binary, length); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateProgramBinary(context, program, binaryFormat, binary, length)) - { - return; - } - - Program *programObject = context->getProgram(program); - ASSERT(programObject != nullptr); - - Error error = programObject->loadBinary(binaryFormat, binary, length); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value) -{ - EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", - program, pname, value); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!ValidateProgramParameter(context, program, pname, value)) - { - return; - } - - 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(); - } - } -} - -void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) -{ - EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)", - target, numAttachments, attachments); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateInvalidateFramebuffer(context, target, numAttachments, attachments)) - { - return; - } - - context->invalidateFramebuffer(target, numAttachments, attachments); - } -} - -void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, " - "GLint y = %d, GLsizei width = %d, GLsizei height = %d)", - target, numAttachments, attachments, x, y, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (!context->skipValidation() && - !ValidateInvalidateFramebuffer(context, target, numAttachments, attachments)) - { - return; - } - - context->invalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); - } -} - -void GL_APIENTRY TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) -{ - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, levels, internalformat, width, height); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3TexStorage2DParameters(context, target, levels, internalformat, width, - height, 1)) - { - return; - } - - Extents size(width, height, 1); - Texture *texture = context->getTargetTexture(target); - Error error = texture->setStorage(target, levels, internalformat, size); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " - "GLsizei height = %d, GLsizei depth = %d)", - target, levels, internalformat, width, height, depth); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3TexStorage3DParameters(context, target, levels, internalformat, width, - height, depth)) - { - return; - } - - Extents size(width, height, depth); - Texture *texture = context->getTargetTexture(target); - Error error = texture->setStorage(target, levels, internalformat, size); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) -{ - EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, " - "GLint* params = 0x%0.8p)", - target, internalformat, pname, bufSize, params); - - Context *context = GetValidGlobalContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return; - } - - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (!formatCaps.renderable) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (target != GL_RENDERBUFFER) - { - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - - if (bufSize < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - case GL_NUM_SAMPLE_COUNTS: - if (bufSize != 0) - { - *params = static_cast(formatCaps.sampleCounts.size()); - } - break; - - case GL_SAMPLES: - { - size_t returnCount = std::min(bufSize, formatCaps.sampleCounts.size()); - auto sampleReverseIt = formatCaps.sampleCounts.rbegin(); - for (size_t sampleIndex = 0; sampleIndex < returnCount; ++sampleIndex) - { - params[sampleIndex] = *sampleReverseIt++;; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return; - } - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h deleted file mode 100644 index 09ca0e4641..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_3_0.h : Defines the GLES 3.0 entry points. - -#ifndef LIBGLESV2_ENTRYPOINTGLES30_H_ -#define LIBGLESV2_ENTRYPOINTGLES30_H_ - -#include -#include - -namespace gl -{ - -ANGLE_EXPORT void GL_APIENTRY ReadBuffer(GLenum mode); -ANGLE_EXPORT void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices); -ANGLE_EXPORT void GL_APIENTRY TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); -ANGLE_EXPORT void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); -ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); -ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); -ANGLE_EXPORT void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids); -ANGLE_EXPORT void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids); -ANGLE_EXPORT GLboolean GL_APIENTRY IsQuery(GLuint id); -ANGLE_EXPORT void GL_APIENTRY BeginQuery(GLenum target, GLuint id); -ANGLE_EXPORT void GL_APIENTRY EndQuery(GLenum target); -ANGLE_EXPORT void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params); -ANGLE_EXPORT GLboolean GL_APIENTRY UnmapBuffer(GLenum target); -ANGLE_EXPORT void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params); -ANGLE_EXPORT void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -ANGLE_EXPORT GLvoid* GL_APIENTRY MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -ANGLE_EXPORT void GL_APIENTRY FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); -ANGLE_EXPORT void GL_APIENTRY BindVertexArray(GLuint array); -ANGLE_EXPORT void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint* arrays); -ANGLE_EXPORT void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint* arrays); -ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArray(GLuint array); -ANGLE_EXPORT void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint* data); -ANGLE_EXPORT void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode); -ANGLE_EXPORT void GL_APIENTRY EndTransformFeedback(void); -ANGLE_EXPORT void GL_APIENTRY BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -ANGLE_EXPORT void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer); -ANGLE_EXPORT void GL_APIENTRY TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode); -ANGLE_EXPORT void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name); -ANGLE_EXPORT void GL_APIENTRY VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer); -ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params); -ANGLE_EXPORT void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); -ANGLE_EXPORT void GL_APIENTRY VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -ANGLE_EXPORT void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint* v); -ANGLE_EXPORT void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint* v); -ANGLE_EXPORT void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint* params); -ANGLE_EXPORT GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name); -ANGLE_EXPORT void GL_APIENTRY Uniform1ui(GLint location, GLuint v0); -ANGLE_EXPORT void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1); -ANGLE_EXPORT void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); -ANGLE_EXPORT void GL_APIENTRY Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -ANGLE_EXPORT void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint* value); -ANGLE_EXPORT void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint* value); -ANGLE_EXPORT void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint* value); -ANGLE_EXPORT void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint* value); -ANGLE_EXPORT void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); -ANGLE_EXPORT void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); -ANGLE_EXPORT void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); -ANGLE_EXPORT void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -ANGLE_EXPORT const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index); -ANGLE_EXPORT void GL_APIENTRY CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -ANGLE_EXPORT void GL_APIENTRY GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices); -ANGLE_EXPORT void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); -ANGLE_EXPORT GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName); -ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); -ANGLE_EXPORT void GL_APIENTRY UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -ANGLE_EXPORT void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); -ANGLE_EXPORT void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount); -ANGLE_EXPORT GLsync GL_APIENTRY FenceSync_(GLenum condition, GLbitfield flags); -ANGLE_EXPORT GLboolean GL_APIENTRY IsSync(GLsync sync); -ANGLE_EXPORT void GL_APIENTRY DeleteSync(GLsync sync); -ANGLE_EXPORT GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); -ANGLE_EXPORT void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); -ANGLE_EXPORT void GL_APIENTRY GetInteger64v(GLenum pname, GLint64* params); -ANGLE_EXPORT void GL_APIENTRY GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); -ANGLE_EXPORT void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64* data); -ANGLE_EXPORT void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params); -ANGLE_EXPORT void GL_APIENTRY GenSamplers(GLsizei count, GLuint* samplers); -ANGLE_EXPORT void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint* samplers); -ANGLE_EXPORT GLboolean GL_APIENTRY IsSampler(GLuint sampler); -ANGLE_EXPORT void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler); -ANGLE_EXPORT void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param); -ANGLE_EXPORT void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param); -ANGLE_EXPORT void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); -ANGLE_EXPORT void GL_APIENTRY SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param); -ANGLE_EXPORT void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params); -ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params); -ANGLE_EXPORT void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor); -ANGLE_EXPORT void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id); -ANGLE_EXPORT void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint* ids); -ANGLE_EXPORT void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint* ids); -ANGLE_EXPORT GLboolean GL_APIENTRY IsTransformFeedback(GLuint id); -ANGLE_EXPORT void GL_APIENTRY PauseTransformFeedback(void); -ANGLE_EXPORT void GL_APIENTRY ResumeTransformFeedback(void); -ANGLE_EXPORT void GL_APIENTRY GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary); -ANGLE_EXPORT void GL_APIENTRY ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length); -ANGLE_EXPORT void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value); -ANGLE_EXPORT void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments); -ANGLE_EXPORT void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -ANGLE_EXPORT void GL_APIENTRY TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -ANGLE_EXPORT void GL_APIENTRY GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params); - -} - -#endif // LIBGLESV2_ENTRYPOINTGLES30_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.cpp new file mode 100644 index 0000000000..439f920bab --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.cpp @@ -0,0 +1,2084 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_3_0_autogen.cpp: +// Defines the GLES 3.0 entry points. + +#include "libANGLE/Context.h" +#include "libANGLE/validationES3.h" +#include "libGLESv2/global_state.h" + +namespace gl +{ +void GL_APIENTRY ReadBuffer(GLenum src) +{ + EVENT("(GLenum src = 0x%X)", src); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(src); + + if (context->skipValidation() || ValidateReadBuffer(context, src)) + { + context->readBuffer(src); + } + } +} + +void GL_APIENTRY DrawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) +{ + EVENT( + "(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type " + "= 0x%X, const void *indices = 0x%0.8p)", + mode, start, end, count, type, indices); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, start, end, count, type, + indices); + + if (context->skipValidation() || + ValidateDrawRangeElements(context, mode, start, end, count, type, indices)) + { + context->drawRangeElements(mode, start, end, count, type, indices); + } + } +} + +void GL_APIENTRY TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, GLenum " + "type = 0x%X, const void *pixels = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, internalformat, width, height, + depth, border, format, type, pixels); + + if (context->skipValidation() || + ValidateTexImage3D(context, target, level, internalformat, width, height, depth, border, + format, type, pixels)) + { + context->texImage3D(target, level, internalformat, width, height, depth, border, format, + type, pixels); + } + } +} + +void GL_APIENTRY TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLint " + "zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLenum format " + "= 0x%X, GLenum type = 0x%X, const void *pixels = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + + if (context->skipValidation() || + ValidateTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, width, height, + depth, format, type, pixels)) + { + context->texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, pixels); + } + } +} + +void GL_APIENTRY CopyTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLint " + "zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, level, xoffset, yoffset, zoffset, x, y, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, xoffset, yoffset, + zoffset, x, y, width, height); + + if (context->skipValidation() || + ValidateCopyTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, x, y, + width, height)) + { + context->copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, + height); + } + } +} + +void GL_APIENTRY CompressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " + "const void *data = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, level, internalformat, width, height, depth, border, imageSize, data); + + if (context->skipValidation() || + ValidateCompressedTexImage3D(context, target, level, internalformat, width, height, + depth, border, imageSize, data)) + { + context->compressedTexImage3D(target, level, internalformat, width, height, depth, + border, imageSize, data); + } + } +} + +void GL_APIENTRY CompressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLint " + "zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLenum format " + "= 0x%X, GLsizei imageSize = %d, const void *data = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, xoffset, yoffset, + zoffset, width, height, depth, + format, imageSize, data); + + if (context->skipValidation() || + ValidateCompressedTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, imageSize, data)) + { + context->compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, + height, depth, format, imageSize, data); + } + } +} + +void GL_APIENTRY GenQueries(GLsizei n, GLuint *ids) +{ + EVENT("(GLsizei n = %d, GLuint *ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, ids); + + if (context->skipValidation() || ValidateGenQueries(context, n, ids)) + { + context->genQueries(n, ids); + } + } +} + +void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint *ids) +{ + EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, ids); + + if (context->skipValidation() || ValidateDeleteQueries(context, n, ids)) + { + context->deleteQueries(n, ids); + } + } +} + +GLboolean GL_APIENTRY IsQuery(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(id); + + if (context->skipValidation() || ValidateIsQuery(context, id)) + { + return context->isQuery(id); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY BeginQuery(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, id); + + if (context->skipValidation() || ValidateBeginQuery(context, target, id)) + { + context->beginQuery(target, id); + } + } +} + +void GL_APIENTRY EndQuery(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target); + + if (context->skipValidation() || ValidateEndQuery(context, target)) + { + context->endQuery(target); + } + } +} + +void GL_APIENTRY GetQueryiv(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) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || ValidateGetQueryiv(context, target, pname, params)) + { + context->getQueryiv(target, pname, params); + } + } +} + +void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) +{ + EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(id, pname, params); + + if (context->skipValidation() || ValidateGetQueryObjectuiv(context, id, pname, params)) + { + context->getQueryObjectuiv(id, pname, params); + } + } +} + +GLboolean GL_APIENTRY UnmapBuffer(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked); + + if (context->skipValidation() || ValidateUnmapBuffer(context, targetPacked)) + { + return context->unmapBuffer(targetPacked); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, void **params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, void **params = 0x%0.8p)", target, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, pname, params); + + if (context->skipValidation() || + ValidateGetBufferPointerv(context, targetPacked, pname, params)) + { + context->getBufferPointerv(targetPacked, pname, params); + } + } +} + +void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum *bufs) +{ + EVENT("(GLsizei n = %d, const GLenum *bufs = 0x%0.8p)", n, bufs); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, bufs); + + if (context->skipValidation() || ValidateDrawBuffers(context, n, bufs)) + { + context->drawBuffers(n, bufs); + } + } +} + +void GL_APIENTRY UniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix2x3fv(context, location, count, transpose, value)) + { + context->uniformMatrix2x3fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix3x2fv(context, location, count, transpose, value)) + { + context->uniformMatrix3x2fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix2x4fv(context, location, count, transpose, value)) + { + context->uniformMatrix2x4fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix4x2fv(context, location, count, transpose, value)) + { + context->uniformMatrix4x2fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix3x4fv(context, location, count, transpose, value)) + { + context->uniformMatrix3x4fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY UniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat *value " + "= 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, transpose, value); + + if (context->skipValidation() || + ValidateUniformMatrix4x3fv(context, location, count, transpose, value)) + { + context->uniformMatrix4x3fv(location, count, transpose, value); + } + } +} + +void GL_APIENTRY BlitFramebuffer(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) +{ + EVENT( + "(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, GLint dstX0 = " + "%d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, GLbitfield mask = 0x%X, GLenum " + "filter = 0x%X)", + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, + dstX1, dstY1, mask, filter); + + if (context->skipValidation() || + ValidateBlitFramebuffer(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter)) + { + context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, + filter); + } + } +} + +void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width " + "= %d, GLsizei height = %d)", + target, samples, internalformat, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, samples, internalformat, width, height); + + if (context->skipValidation() || + ValidateRenderbufferStorageMultisample(context, target, samples, internalformat, width, + height)) + { + context->renderbufferStorageMultisample(target, samples, internalformat, width, height); + } + } +} + +void GL_APIENTRY +FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +{ + EVENT( + "(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, " + "GLint layer = %d)", + target, attachment, texture, level, layer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, attachment, texture, + level, layer); + + if (context->skipValidation() || + ValidateFramebufferTextureLayer(context, target, attachment, texture, level, layer)) + { + context->framebufferTextureLayer(target, attachment, texture, level, layer); + } + } +} + +void *GL_APIENTRY MapBufferRange(GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) +{ + EVENT( + "(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = " + "0x%X)", + target, offset, length, access); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, offset, length, access); + + if (context->skipValidation() || + ValidateMapBufferRange(context, targetPacked, offset, length, access)) + { + return context->mapBufferRange(targetPacked, offset, length, access); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, + length); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, offset, length); + + if (context->skipValidation() || + ValidateFlushMappedBufferRange(context, targetPacked, offset, length)) + { + context->flushMappedBufferRange(targetPacked, offset, length); + } + } +} + +void GL_APIENTRY BindVertexArray(GLuint array) +{ + EVENT("(GLuint array = %u)", array); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(array); + + if (context->skipValidation() || ValidateBindVertexArray(context, array)) + { + context->bindVertexArray(array); + } + } +} + +void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint *arrays) +{ + EVENT("(GLsizei n = %d, const GLuint *arrays = 0x%0.8p)", n, arrays); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, arrays); + + if (context->skipValidation() || ValidateDeleteVertexArrays(context, n, arrays)) + { + context->deleteVertexArrays(n, arrays); + } + } +} + +void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint *arrays) +{ + EVENT("(GLsizei n = %d, GLuint *arrays = 0x%0.8p)", n, arrays); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, arrays); + + if (context->skipValidation() || ValidateGenVertexArrays(context, n, arrays)) + { + context->genVertexArrays(n, arrays); + } + } +} + +GLboolean GL_APIENTRY IsVertexArray(GLuint array) +{ + EVENT("(GLuint array = %u)", array); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(array); + + if (context->skipValidation() || ValidateIsVertexArray(context, array)) + { + return context->isVertexArray(array); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint *data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint *data = 0x%0.8p)", target, index, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, index, data); + + if (context->skipValidation() || ValidateGetIntegeri_v(context, target, index, data)) + { + context->getIntegeri_v(target, index, data); + } + } +} + +void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode) +{ + EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(primitiveMode); + + if (context->skipValidation() || ValidateBeginTransformFeedback(context, primitiveMode)) + { + context->beginTransformFeedback(primitiveMode); + } + } +} + +void GL_APIENTRY EndTransformFeedback() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateEndTransformFeedback(context)) + { + context->endTransformFeedback(); + } + } +} + +void GL_APIENTRY +BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +{ + EVENT( + "(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, " + "GLsizeiptr size = %d)", + target, index, buffer, offset, size); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, index, buffer, offset, + size); + + if (context->skipValidation() || + ValidateBindBufferRange(context, targetPacked, index, buffer, offset, size)) + { + context->bindBufferRange(targetPacked, index, buffer, offset, size); + } + } +} + +void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", target, index, buffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, index, buffer); + + if (context->skipValidation() || + ValidateBindBufferBase(context, targetPacked, index, buffer)) + { + context->bindBufferBase(targetPacked, index, buffer); + } + } +} + +void GL_APIENTRY TransformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) +{ + EVENT( + "(GLuint program = %u, GLsizei count = %d, const GLchar *const*varyings = 0x%0.8p, GLenum " + "bufferMode = 0x%X)", + program, count, varyings, bufferMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, count, varyings, + bufferMode); + + if (context->skipValidation() || + ValidateTransformFeedbackVaryings(context, program, count, varyings, bufferMode)) + { + context->transformFeedbackVaryings(program, count, varyings, bufferMode); + } + } +} + +void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) +{ + EVENT( + "(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, " + "GLsizei *size = 0x%0.8p, GLenum *type = 0x%0.8p, GLchar *name = 0x%0.8p)", + program, index, bufSize, length, size, type, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, index, bufSize, + length, size, type, name); + + if (context->skipValidation() || + ValidateGetTransformFeedbackVarying(context, program, index, bufSize, length, size, + type, name)) + { + context->getTransformFeedbackVarying(program, index, bufSize, length, size, type, name); + } + } +} + +void GL_APIENTRY +VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + EVENT( + "(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const void " + "*pointer = 0x%0.8p)", + index, size, type, stride, pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, size, type, stride, pointer); + + if (context->skipValidation() || + ValidateVertexAttribIPointer(context, index, size, type, stride, pointer)) + { + context->vertexAttribIPointer(index, size, type, stride, pointer); + } + } +} + +void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", index, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, pname, params); + + if (context->skipValidation() || ValidateGetVertexAttribIiv(context, index, pname, params)) + { + context->getVertexAttribIiv(index, pname, params); + } + } +} + +void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", index, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, pname, params); + + if (context->skipValidation() || ValidateGetVertexAttribIuiv(context, index, pname, params)) + { + context->getVertexAttribIuiv(index, pname, params); + } + } +} + +void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", index, x, + y, z, w); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x, y, z, w); + + if (context->skipValidation() || ValidateVertexAttribI4i(context, index, x, y, z, w)) + { + context->vertexAttribI4i(index, x, y, z, w); + } + } +} + +void GL_APIENTRY VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +{ + EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", index, + x, y, z, w); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, x, y, z, w); + + if (context->skipValidation() || ValidateVertexAttribI4ui(context, index, x, y, z, w)) + { + context->vertexAttribI4ui(index, x, y, z, w); + } + } +} + +void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint *v) +{ + EVENT("(GLuint index = %u, const GLint *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttribI4iv(context, index, v)) + { + context->vertexAttribI4iv(index, v); + } + } +} + +void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint *v) +{ + EVENT("(GLuint index = %u, const GLuint *v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, v); + + if (context->skipValidation() || ValidateVertexAttribI4uiv(context, index, v)) + { + context->vertexAttribI4uiv(index, v); + } + } +} + +void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint *params) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLuint *params = 0x%0.8p)", program, location, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, params); + + if (context->skipValidation() || ValidateGetUniformuiv(context, program, location, params)) + { + context->getUniformuiv(program, location, params); + } + } +} + +GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name) +{ + EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, name); + + if (context->skipValidation() || ValidateGetFragDataLocation(context, program, name)) + { + return context->getFragDataLocation(program, name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY Uniform1ui(GLint location, GLuint v0) +{ + EVENT("(GLint location = %d, GLuint v0 = %u)", location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0); + + if (context->skipValidation() || ValidateUniform1ui(context, location, v0)) + { + context->uniform1ui(location, v0); + } + } +} + +void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1) +{ + EVENT("(GLint location = %d, GLuint v0 = %u, GLuint v1 = %u)", location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1); + + if (context->skipValidation() || ValidateUniform2ui(context, location, v0, v1)) + { + context->uniform2ui(location, v0, v1); + } + } +} + +void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + EVENT("(GLint location = %d, GLuint v0 = %u, GLuint v1 = %u, GLuint v2 = %u)", location, v0, v1, + v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2); + + if (context->skipValidation() || ValidateUniform3ui(context, location, v0, v1, v2)) + { + context->uniform3ui(location, v0, v1, v2); + } + } +} + +void GL_APIENTRY Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + EVENT("(GLint location = %d, GLuint v0 = %u, GLuint v1 = %u, GLuint v2 = %u, GLuint v3 = %u)", + location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, v0, v1, v2, v3); + + if (context->skipValidation() || ValidateUniform4ui(context, location, v0, v1, v2, v3)) + { + context->uniform4ui(location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform1uiv(context, location, count, value)) + { + context->uniform1uiv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform2uiv(context, location, count, value)) + { + context->uniform2uiv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform3uiv(context, location, count, value)) + { + context->uniform3uiv(location, count, value); + } + } +} + +void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint *value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint *value = 0x%0.8p)", location, + count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(location, count, value); + + if (context->skipValidation() || ValidateUniform4uiv(context, location, count, value)) + { + context->uniform4uiv(location, count, value); + } + } +} + +void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = 0x%0.8p)", buffer, + drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(buffer, drawbuffer, value); + + if (context->skipValidation() || ValidateClearBufferiv(context, buffer, drawbuffer, value)) + { + context->clearBufferiv(buffer, drawbuffer, value); + } + } +} + +void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = 0x%0.8p)", buffer, + drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(buffer, drawbuffer, value); + + if (context->skipValidation() || ValidateClearBufferuiv(context, buffer, drawbuffer, value)) + { + context->clearBufferuiv(buffer, drawbuffer, value); + } + } +} + +void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = 0x%0.8p)", buffer, + drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(buffer, drawbuffer, value); + + if (context->skipValidation() || ValidateClearBufferfv(context, buffer, drawbuffer, value)) + { + context->clearBufferfv(buffer, drawbuffer, value); + } + } +} + +void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)", + buffer, drawbuffer, depth, stencil); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(buffer, drawbuffer, depth, stencil); + + if (context->skipValidation() || + ValidateClearBufferfi(context, buffer, drawbuffer, depth, stencil)) + { + context->clearBufferfi(buffer, drawbuffer, depth, stencil); + } + } +} + +const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index) +{ + EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(name, index); + + if (context->skipValidation() || ValidateGetStringi(context, name, index)) + { + return context->getStringi(name, index); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY CopyBufferSubData(GLenum readTarget, + GLenum writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) +{ + EVENT( + "(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr " + "writeOffset = %d, GLsizeiptr size = %d)", + readTarget, writeTarget, readOffset, writeOffset, size); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding readTargetPacked = FromGLenum(readTarget); + BufferBinding writeTargetPacked = FromGLenum(writeTarget); + context->gatherParams(readTargetPacked, writeTargetPacked, + readOffset, writeOffset, size); + + if (context->skipValidation() || + ValidateCopyBufferSubData(context, readTargetPacked, writeTargetPacked, readOffset, + writeOffset, size)) + { + context->copyBufferSubData(readTargetPacked, writeTargetPacked, readOffset, writeOffset, + size); + } + } +} + +void GL_APIENTRY GetUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) +{ + EVENT( + "(GLuint program = %u, GLsizei uniformCount = %d, const GLchar *const*uniformNames = " + "0x%0.8p, GLuint *uniformIndices = 0x%0.8p)", + program, uniformCount, uniformNames, uniformIndices); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, uniformCount, uniformNames, + uniformIndices); + + if (context->skipValidation() || + ValidateGetUniformIndices(context, program, uniformCount, uniformNames, uniformIndices)) + { + context->getUniformIndices(program, uniformCount, uniformNames, uniformIndices); + } + } +} + +void GL_APIENTRY GetActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLsizei uniformCount = %d, const GLuint *uniformIndices = 0x%0.8p, " + "GLenum pname = 0x%X, GLint *params = 0x%0.8p)", + program, uniformCount, uniformIndices, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, uniformCount, + uniformIndices, pname, params); + + if (context->skipValidation() || ValidateGetActiveUniformsiv(context, program, uniformCount, + uniformIndices, pname, params)) + { + context->getActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); + } + } +} + +GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) +{ + EVENT("(GLuint program = %u, const GLchar *uniformBlockName = 0x%0.8p)", program, + uniformBlockName); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, uniformBlockName); + + if (context->skipValidation() || + ValidateGetUniformBlockIndex(context, program, uniformBlockName)) + { + return context->getUniformBlockIndex(program, uniformBlockName); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint *params = " + "0x%0.8p)", + program, uniformBlockIndex, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, uniformBlockIndex, + pname, params); + + if (context->skipValidation() || + ValidateGetActiveUniformBlockiv(context, program, uniformBlockIndex, pname, params)) + { + context->getActiveUniformBlockiv(program, uniformBlockIndex, pname, params); + } + } +} + +void GL_APIENTRY GetActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) +{ + EVENT( + "(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei " + "*length = 0x%0.8p, GLchar *uniformBlockName = 0x%0.8p)", + program, uniformBlockIndex, bufSize, length, uniformBlockName); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + program, uniformBlockIndex, bufSize, length, uniformBlockName); + + if (context->skipValidation() || + ValidateGetActiveUniformBlockName(context, program, uniformBlockIndex, bufSize, length, + uniformBlockName)) + { + context->getActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, + uniformBlockName); + } + } +} + +void GL_APIENTRY UniformBlockBinding(GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", + program, uniformBlockIndex, uniformBlockBinding); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, uniformBlockIndex, + uniformBlockBinding); + + if (context->skipValidation() || + ValidateUniformBlockBinding(context, program, uniformBlockIndex, uniformBlockBinding)) + { + context->uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); + } + } +} + +void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instancecount = %d)", + mode, first, count, instancecount); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, first, count, instancecount); + + if (context->skipValidation() || + ValidateDrawArraysInstanced(context, mode, first, count, instancecount)) + { + context->drawArraysInstanced(mode, first, count, instancecount); + } + } +} + +void GL_APIENTRY DrawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instancecount) +{ + EVENT( + "(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = " + "0x%0.8p, GLsizei instancecount = %d)", + mode, count, type, indices, instancecount); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, count, type, indices, + instancecount); + + if (context->skipValidation() || + ValidateDrawElementsInstanced(context, mode, count, type, indices, instancecount)) + { + context->drawElementsInstanced(mode, count, type, indices, instancecount); + } + } +} + +GLsync GL_APIENTRY FenceSync(GLenum condition, GLbitfield flags) +{ + EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(condition, flags); + + if (context->skipValidation() || ValidateFenceSync(context, condition, flags)) + { + return context->fenceSync(condition, flags); + } + } + + return GetDefaultReturnValue(); +} + +GLboolean GL_APIENTRY IsSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sync); + + if (context->skipValidation() || ValidateIsSync(context, sync)) + { + return context->isSync(sync); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY DeleteSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sync); + + if (context->skipValidation() || ValidateDeleteSync(context, sync)) + { + context->deleteSync(sync); + } + } +} + +GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", sync, flags, + timeout); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sync, flags, timeout); + + if (context->skipValidation() || ValidateClientWaitSync(context, sync, flags, timeout)) + { + return context->clientWaitSync(sync, flags, timeout); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", sync, flags, + timeout); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sync, flags, timeout); + + if (context->skipValidation() || ValidateWaitSync(context, sync, flags, timeout)) + { + context->waitSync(sync, flags, timeout); + } + } +} + +void GL_APIENTRY GetInteger64v(GLenum pname, GLint64 *data) +{ + EVENT("(GLenum pname = 0x%X, GLint64 *data = 0x%0.8p)", pname, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, data); + + if (context->skipValidation() || ValidateGetInteger64v(context, pname, data)) + { + context->getInteger64v(pname, data); + } + } +} + +void GL_APIENTRY +GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +{ + EVENT( + "(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = " + "0x%0.8p, GLint *values = 0x%0.8p)", + sync, pname, bufSize, length, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sync, pname, bufSize, length, values); + + if (context->skipValidation() || + ValidateGetSynciv(context, sync, pname, bufSize, length, values)) + { + context->getSynciv(sync, pname, bufSize, length, values); + } + } +} + +void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64 *data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64 *data = 0x%0.8p)", target, index, + data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, index, data); + + if (context->skipValidation() || ValidateGetInteger64i_v(context, target, index, data)) + { + context->getInteger64i_v(target, index, data); + } + } +} + +void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = 0x%0.8p)", target, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + BufferBinding targetPacked = FromGLenum(target); + context->gatherParams(targetPacked, pname, params); + + if (context->skipValidation() || + ValidateGetBufferParameteri64v(context, targetPacked, pname, params)) + { + context->getBufferParameteri64v(targetPacked, pname, params); + } + } +} + +void GL_APIENTRY GenSamplers(GLsizei count, GLuint *samplers) +{ + EVENT("(GLsizei count = %d, GLuint *samplers = 0x%0.8p)", count, samplers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(count, samplers); + + if (context->skipValidation() || ValidateGenSamplers(context, count, samplers)) + { + context->genSamplers(count, samplers); + } + } +} + +void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint *samplers) +{ + EVENT("(GLsizei count = %d, const GLuint *samplers = 0x%0.8p)", count, samplers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(count, samplers); + + if (context->skipValidation() || ValidateDeleteSamplers(context, count, samplers)) + { + context->deleteSamplers(count, samplers); + } + } +} + +GLboolean GL_APIENTRY IsSampler(GLuint sampler) +{ + EVENT("(GLuint sampler = %u)", sampler); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler); + + if (context->skipValidation() || ValidateIsSampler(context, sampler)) + { + return context->isSampler(sampler); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler) +{ + EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(unit, sampler); + + if (context->skipValidation() || ValidateBindSampler(context, unit, sampler)) + { + context->bindSampler(unit, sampler); + } + } +} + +void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, param); + + if (context->skipValidation() || ValidateSamplerParameteri(context, sampler, pname, param)) + { + context->samplerParameteri(sampler, pname, param); + } + } +} + +void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, const GLint *param = 0x%0.8p)", sampler, + pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, param); + + if (context->skipValidation() || ValidateSamplerParameteriv(context, sampler, pname, param)) + { + context->samplerParameteriv(sampler, pname, param); + } + } +} + +void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %f)", sampler, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, param); + + if (context->skipValidation() || ValidateSamplerParameterf(context, sampler, pname, param)) + { + context->samplerParameterf(sampler, pname, param); + } + } +} + +void GL_APIENTRY SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, const GLfloat *param = 0x%0.8p)", sampler, + pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, param); + + if (context->skipValidation() || ValidateSamplerParameterfv(context, sampler, pname, param)) + { + context->samplerParameterfv(sampler, pname, param); + } + } +} + +void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", sampler, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, params); + + if (context->skipValidation() || + ValidateGetSamplerParameteriv(context, sampler, pname, params)) + { + context->getSamplerParameteriv(sampler, pname, params); + } + } +} + +void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat *params = 0x%0.8p)", sampler, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(sampler, pname, params); + + if (context->skipValidation() || + ValidateGetSamplerParameterfv(context, sampler, pname, params)) + { + context->getSamplerParameterfv(sampler, pname, params); + } + } +} + +void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(index, divisor); + + if (context->skipValidation() || ValidateVertexAttribDivisor(context, index, divisor)) + { + context->vertexAttribDivisor(index, divisor); + } + } +} + +void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, id); + + if (context->skipValidation() || ValidateBindTransformFeedback(context, target, id)) + { + context->bindTransformFeedback(target, id); + } + } +} + +void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint *ids) +{ + EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, ids); + + if (context->skipValidation() || ValidateDeleteTransformFeedbacks(context, n, ids)) + { + context->deleteTransformFeedbacks(n, ids); + } + } +} + +void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint *ids) +{ + EVENT("(GLsizei n = %d, GLuint *ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, ids); + + if (context->skipValidation() || ValidateGenTransformFeedbacks(context, n, ids)) + { + context->genTransformFeedbacks(n, ids); + } + } +} + +GLboolean GL_APIENTRY IsTransformFeedback(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(id); + + if (context->skipValidation() || ValidateIsTransformFeedback(context, id)) + { + return context->isTransformFeedback(id); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY PauseTransformFeedback() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidatePauseTransformFeedback(context)) + { + context->pauseTransformFeedback(); + } + } +} + +void GL_APIENTRY ResumeTransformFeedback() +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(); + + if (context->skipValidation() || ValidateResumeTransformFeedback(context)) + { + context->resumeTransformFeedback(); + } + } +} + +void GL_APIENTRY GetProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + EVENT( + "(GLuint program = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLenum " + "*binaryFormat = 0x%0.8p, void *binary = 0x%0.8p)", + program, bufSize, length, binaryFormat, binary); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, bufSize, length, binaryFormat, + binary); + + if (context->skipValidation() || + ValidateGetProgramBinary(context, program, bufSize, length, binaryFormat, binary)) + { + context->getProgramBinary(program, bufSize, length, binaryFormat, binary); + } + } +} + +void GL_APIENTRY ProgramBinary(GLuint program, + GLenum binaryFormat, + const void *binary, + GLsizei length) +{ + EVENT( + "(GLuint program = %u, GLenum binaryFormat = 0x%X, const void *binary = 0x%0.8p, GLsizei " + "length = %d)", + program, binaryFormat, binary, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, binaryFormat, binary, length); + + if (context->skipValidation() || + ValidateProgramBinary(context, program, binaryFormat, binary, length)) + { + context->programBinary(program, binaryFormat, binary, length); + } + } +} + +void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value) +{ + EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", program, pname, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, pname, value); + + if (context->skipValidation() || ValidateProgramParameteri(context, program, pname, value)) + { + context->programParameteri(program, pname, value); + } + } +} + +void GL_APIENTRY InvalidateFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = 0x%0.8p)", + target, numAttachments, attachments); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, numAttachments, + attachments); + + if (context->skipValidation() || + ValidateInvalidateFramebuffer(context, target, numAttachments, attachments)) + { + context->invalidateFramebuffer(target, numAttachments, attachments); + } + } +} + +void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = 0x%0.8p, " + "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, numAttachments, attachments, x, y, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, numAttachments, attachments, x, y, width, height); + + if (context->skipValidation() || + ValidateInvalidateSubFramebuffer(context, target, numAttachments, attachments, x, y, + width, height)) + { + context->invalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, + height); + } + } +} + +void GL_APIENTRY +TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, GLsizei height = %d)", + target, levels, internalformat, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, levels, internalformat, width, + height); + + if (context->skipValidation() || + ValidateTexStorage2D(context, target, levels, internalformat, width, height)) + { + context->texStorage2D(target, levels, internalformat, width, height); + } + } +} + +void GL_APIENTRY TexStorage3D(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = " + "%d, GLsizei height = %d, GLsizei depth = %d)", + target, levels, internalformat, width, height, depth); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, levels, internalformat, width, + height, depth); + + if (context->skipValidation() || + ValidateTexStorage3D(context, target, levels, internalformat, width, height, depth)) + { + context->texStorage3D(target, levels, internalformat, width, height, depth); + } + } +} + +void GL_APIENTRY GetInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) +{ + EVENT( + "(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize " + "= %d, GLint *params = 0x%0.8p)", + target, internalformat, pname, bufSize, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, internalformat, pname, + bufSize, params); + + if (context->skipValidation() || + ValidateGetInternalformativ(context, target, internalformat, pname, bufSize, params)) + { + context->getInternalformativ(target, internalformat, pname, bufSize, params); + } + } +} +} // namespace gl diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.h new file mode 100644 index 0000000000..e93dde96ed --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_autogen.h @@ -0,0 +1,284 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_3_0_autogen.h: +// Defines the GLES 3.0 entry points. + +#ifndef LIBGLESV2_ENTRYPOINTSGLES30_AUTOGEN_H_ +#define LIBGLESV2_ENTRYPOINTSGLES30_AUTOGEN_H_ + +#include +#include + +namespace gl +{ +ANGLE_EXPORT void GL_APIENTRY ReadBuffer(GLenum src); +ANGLE_EXPORT void GL_APIENTRY DrawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices); +ANGLE_EXPORT void GL_APIENTRY TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels); +ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height); +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data); +ANGLE_EXPORT void GL_APIENTRY GenQueries(GLsizei n, GLuint *ids); +ANGLE_EXPORT void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint *ids); +ANGLE_EXPORT GLboolean GL_APIENTRY IsQuery(GLuint id); +ANGLE_EXPORT void GL_APIENTRY BeginQuery(GLenum target, GLuint id); +ANGLE_EXPORT void GL_APIENTRY EndQuery(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); +ANGLE_EXPORT GLboolean GL_APIENTRY UnmapBuffer(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, void **params); +ANGLE_EXPORT void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum *bufs); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY BlitFramebuffer(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter); +ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height); +ANGLE_EXPORT void GL_APIENTRY +FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +ANGLE_EXPORT void *GL_APIENTRY MapBufferRange(GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access); +ANGLE_EXPORT void GL_APIENTRY FlushMappedBufferRange(GLenum target, + GLintptr offset, + GLsizeiptr length); +ANGLE_EXPORT void GL_APIENTRY BindVertexArray(GLuint array); +ANGLE_EXPORT void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint *arrays); +ANGLE_EXPORT void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint *arrays); +ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArray(GLuint array); +ANGLE_EXPORT void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint *data); +ANGLE_EXPORT void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode); +ANGLE_EXPORT void GL_APIENTRY EndTransformFeedback(); +ANGLE_EXPORT void GL_APIENTRY +BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +ANGLE_EXPORT void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer); +ANGLE_EXPORT void GL_APIENTRY TransformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode); +ANGLE_EXPORT void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name); +ANGLE_EXPORT void GL_APIENTRY +VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); +ANGLE_EXPORT void GL_APIENTRY +VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint *v); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint *v); +ANGLE_EXPORT void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint *params); +ANGLE_EXPORT GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY Uniform1ui(GLint location, GLuint v0); +ANGLE_EXPORT void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1); +ANGLE_EXPORT void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); +ANGLE_EXPORT void GL_APIENTRY +Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +ANGLE_EXPORT void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferfi(GLenum buffer, + GLint drawbuffer, + GLfloat depth, + GLint stencil); +ANGLE_EXPORT const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index); +ANGLE_EXPORT void GL_APIENTRY CopyBufferSubData(GLenum readTarget, + GLenum writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size); +ANGLE_EXPORT void GL_APIENTRY GetUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params); +ANGLE_EXPORT GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, + const GLchar *uniformBlockName); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName); +ANGLE_EXPORT void GL_APIENTRY UniformBlockBinding(GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding); +ANGLE_EXPORT void GL_APIENTRY DrawArraysInstanced(GLenum mode, + GLint first, + GLsizei count, + GLsizei instancecount); +ANGLE_EXPORT void GL_APIENTRY DrawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instancecount); +ANGLE_EXPORT GLsync GL_APIENTRY FenceSync(GLenum condition, GLbitfield flags); +ANGLE_EXPORT GLboolean GL_APIENTRY IsSync(GLsync sync); +ANGLE_EXPORT void GL_APIENTRY DeleteSync(GLsync sync); +ANGLE_EXPORT GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +ANGLE_EXPORT void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +ANGLE_EXPORT void GL_APIENTRY GetInteger64v(GLenum pname, GLint64 *data); +ANGLE_EXPORT void GL_APIENTRY +GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +ANGLE_EXPORT void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64 *data); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); +ANGLE_EXPORT void GL_APIENTRY GenSamplers(GLsizei count, GLuint *samplers); +ANGLE_EXPORT void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint *samplers); +ANGLE_EXPORT GLboolean GL_APIENTRY IsSampler(GLuint sampler); +ANGLE_EXPORT void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler); +ANGLE_EXPORT void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterfv(GLuint sampler, + GLenum pname, + const GLfloat *param); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor); +ANGLE_EXPORT void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id); +ANGLE_EXPORT void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint *ids); +ANGLE_EXPORT void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint *ids); +ANGLE_EXPORT GLboolean GL_APIENTRY IsTransformFeedback(GLuint id); +ANGLE_EXPORT void GL_APIENTRY PauseTransformFeedback(); +ANGLE_EXPORT void GL_APIENTRY ResumeTransformFeedback(); +ANGLE_EXPORT void GL_APIENTRY GetProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary); +ANGLE_EXPORT void GL_APIENTRY ProgramBinary(GLuint program, + GLenum binaryFormat, + const void *binary, + GLsizei length); +ANGLE_EXPORT void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value); +ANGLE_EXPORT void GL_APIENTRY InvalidateFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments); +ANGLE_EXPORT void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height); +ANGLE_EXPORT void GL_APIENTRY +TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY TexStorage3D(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth); +ANGLE_EXPORT void GL_APIENTRY GetInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params); +} // namespace gl + +#endif // LIBGLESV2_ENTRYPOINTSGLES30_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp deleted file mode 100644 index 6f6983fd91..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_3_0_ext.cpp : Implements the GLES 3.0 extension entry points. - -#include "libGLESv2/entry_points_gles_3_0_ext.h" -#include "libGLESv2/global_state.h" - -namespace gl -{ -} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h deleted file mode 100644 index fec4c1298a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright(c) 2014 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// entry_points_gles_3_0_ext.h : Defines the GLES 3.0 extension entry points. - -#ifndef LIBGLESV2_ENTRYPOINTGLES30EXT_H_ -#define LIBGLESV2_ENTRYPOINTGLES30EXT_H_ - -#include -#include -#include - -namespace gl -{ - -// No GLES 3.0 extensions yet - -} - -#endif // LIBGLESV2_ENTRYPOINTGLES30EXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.cpp new file mode 100644 index 0000000000..5d836872d6 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.cpp @@ -0,0 +1,1430 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_3_1_autogen.cpp: +// Defines the GLES 3.1 entry points. + +#include "libANGLE/Context.h" +#include "libANGLE/validationES31.h" +#include "libGLESv2/global_state.h" + +namespace gl +{ +void GL_APIENTRY DispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) +{ + EVENT("(GLuint num_groups_x = %u, GLuint num_groups_y = %u, GLuint num_groups_z = %u)", + num_groups_x, num_groups_y, num_groups_z); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(num_groups_x, num_groups_y, + num_groups_z); + + if (context->skipValidation() || + ValidateDispatchCompute(context, num_groups_x, num_groups_y, num_groups_z)) + { + context->dispatchCompute(num_groups_x, num_groups_y, num_groups_z); + } + } +} + +void GL_APIENTRY DispatchComputeIndirect(GLintptr indirect) +{ + EVENT("(GLintptr indirect = %d)", indirect); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(indirect); + + if (context->skipValidation() || ValidateDispatchComputeIndirect(context, indirect)) + { + context->dispatchComputeIndirect(indirect); + } + } +} + +void GL_APIENTRY DrawArraysIndirect(GLenum mode, const void *indirect) +{ + EVENT("(GLenum mode = 0x%X, const void *indirect = 0x%0.8p)", mode, indirect); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, indirect); + + if (context->skipValidation() || ValidateDrawArraysIndirect(context, mode, indirect)) + { + context->drawArraysIndirect(mode, indirect); + } + } +} + +void GL_APIENTRY DrawElementsIndirect(GLenum mode, GLenum type, const void *indirect) +{ + EVENT("(GLenum mode = 0x%X, GLenum type = 0x%X, const void *indirect = 0x%0.8p)", mode, type, + indirect); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(mode, type, indirect); + + if (context->skipValidation() || + ValidateDrawElementsIndirect(context, mode, type, indirect)) + { + context->drawElementsIndirect(mode, type, indirect); + } + } +} + +void GL_APIENTRY FramebufferParameteri(GLenum target, GLenum pname, GLint param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, pname, param); + + if (context->skipValidation() || + ValidateFramebufferParameteri(context, target, pname, param)) + { + context->framebufferParameteri(target, pname, param); + } + } +} + +void GL_APIENTRY GetFramebufferParameteriv(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) + { + context->gatherParams(target, pname, params); + + if (context->skipValidation() || + ValidateGetFramebufferParameteriv(context, target, pname, params)) + { + context->getFramebufferParameteriv(target, pname, params); + } + } +} + +void GL_APIENTRY GetProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLenum programInterface = 0x%X, GLenum pname = 0x%X, GLint *params " + "= 0x%0.8p)", + program, programInterface, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, programInterface, pname, + params); + + if (context->skipValidation() || + ValidateGetProgramInterfaceiv(context, program, programInterface, pname, params)) + { + context->getProgramInterfaceiv(program, programInterface, pname, params); + } + } +} + +GLuint GL_APIENTRY GetProgramResourceIndex(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + EVENT("(GLuint program = %u, GLenum programInterface = 0x%X, const GLchar *name = 0x%0.8p)", + program, programInterface, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, programInterface, name); + + if (context->skipValidation() || + ValidateGetProgramResourceIndex(context, program, programInterface, name)) + { + return context->getProgramResourceIndex(program, programInterface, name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + EVENT( + "(GLuint program = %u, GLenum programInterface = 0x%X, GLuint index = %u, GLsizei bufSize " + "= %d, GLsizei *length = 0x%0.8p, GLchar *name = 0x%0.8p)", + program, programInterface, index, bufSize, length, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, programInterface, index, + bufSize, length, name); + + if (context->skipValidation() || + ValidateGetProgramResourceName(context, program, programInterface, index, bufSize, + length, name)) + { + context->getProgramResourceName(program, programInterface, index, bufSize, length, + name); + } + } +} + +void GL_APIENTRY GetProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + EVENT( + "(GLuint program = %u, GLenum programInterface = 0x%X, GLuint index = %u, GLsizei " + "propCount = %d, const GLenum *props = 0x%0.8p, GLsizei bufSize = %d, GLsizei *length = " + "0x%0.8p, GLint *params = 0x%0.8p)", + program, programInterface, index, propCount, props, bufSize, length, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + program, programInterface, index, propCount, props, bufSize, length, params); + + if (context->skipValidation() || + ValidateGetProgramResourceiv(context, program, programInterface, index, propCount, + props, bufSize, length, params)) + { + context->getProgramResourceiv(program, programInterface, index, propCount, props, + bufSize, length, params); + } + } +} + +GLint GL_APIENTRY GetProgramResourceLocation(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + EVENT("(GLuint program = %u, GLenum programInterface = 0x%X, const GLchar *name = 0x%0.8p)", + program, programInterface, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, programInterface, + name); + + if (context->skipValidation() || + ValidateGetProgramResourceLocation(context, program, programInterface, name)) + { + return context->getProgramResourceLocation(program, programInterface, name); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) +{ + EVENT("(GLuint pipeline = %u, GLbitfield stages = 0x%X, GLuint program = %u)", pipeline, stages, + program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline, stages, program); + + if (context->skipValidation() || + ValidateUseProgramStages(context, pipeline, stages, program)) + { + context->useProgramStages(pipeline, stages, program); + } + } +} + +void GL_APIENTRY ActiveShaderProgram(GLuint pipeline, GLuint program) +{ + EVENT("(GLuint pipeline = %u, GLuint program = %u)", pipeline, program); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline, program); + + if (context->skipValidation() || ValidateActiveShaderProgram(context, pipeline, program)) + { + context->activeShaderProgram(pipeline, program); + } + } +} + +GLuint GL_APIENTRY CreateShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings) +{ + EVENT("(GLenum type = 0x%X, GLsizei count = %d, const GLchar *const*strings = 0x%0.8p)", type, + count, strings); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(type, count, strings); + + if (context->skipValidation() || + ValidateCreateShaderProgramv(context, type, count, strings)) + { + return context->createShaderProgramv(type, count, strings); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY BindProgramPipeline(GLuint pipeline) +{ + EVENT("(GLuint pipeline = %u)", pipeline); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline); + + if (context->skipValidation() || ValidateBindProgramPipeline(context, pipeline)) + { + context->bindProgramPipeline(pipeline); + } + } +} + +void GL_APIENTRY DeleteProgramPipelines(GLsizei n, const GLuint *pipelines) +{ + EVENT("(GLsizei n = %d, const GLuint *pipelines = 0x%0.8p)", n, pipelines); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, pipelines); + + if (context->skipValidation() || ValidateDeleteProgramPipelines(context, n, pipelines)) + { + context->deleteProgramPipelines(n, pipelines); + } + } +} + +void GL_APIENTRY GenProgramPipelines(GLsizei n, GLuint *pipelines) +{ + EVENT("(GLsizei n = %d, GLuint *pipelines = 0x%0.8p)", n, pipelines); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(n, pipelines); + + if (context->skipValidation() || ValidateGenProgramPipelines(context, n, pipelines)) + { + context->genProgramPipelines(n, pipelines); + } + } +} + +GLboolean GL_APIENTRY IsProgramPipeline(GLuint pipeline) +{ + EVENT("(GLuint pipeline = %u)", pipeline); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline); + + if (context->skipValidation() || ValidateIsProgramPipeline(context, pipeline)) + { + return context->isProgramPipeline(pipeline); + } + } + + return GetDefaultReturnValue(); +} + +void GL_APIENTRY GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params) +{ + EVENT("(GLuint pipeline = %u, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", pipeline, pname, + params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline, pname, params); + + if (context->skipValidation() || + ValidateGetProgramPipelineiv(context, pipeline, pname, params)) + { + context->getProgramPipelineiv(pipeline, pname, params); + } + } +} + +void GL_APIENTRY ProgramUniform1i(GLuint program, GLint location, GLint v0) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLint v0 = %d)", program, location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0); + + if (context->skipValidation() || ValidateProgramUniform1i(context, program, location, v0)) + { + context->programUniform1i(program, location, v0); + } + } +} + +void GL_APIENTRY ProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLint v0 = %d, GLint v1 = %d)", program, + location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1); + + if (context->skipValidation() || + ValidateProgramUniform2i(context, program, location, v0, v1)) + { + context->programUniform2i(program, location, v0, v1); + } + } +} + +void GL_APIENTRY ProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLint v0 = %d, GLint v1 = %d, GLint v2 = %d)", + program, location, v0, v1, v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2); + + if (context->skipValidation() || + ValidateProgramUniform3i(context, program, location, v0, v1, v2)) + { + context->programUniform3i(program, location, v0, v1, v2); + } + } +} + +void GL_APIENTRY +ProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLint v0 = %d, GLint v1 = %d, GLint v2 = %d, " + "GLint v3 = %d)", + program, location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2, v3); + + if (context->skipValidation() || + ValidateProgramUniform4i(context, program, location, v0, v1, v2, v3)) + { + context->programUniform4i(program, location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY ProgramUniform1ui(GLuint program, GLint location, GLuint v0) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLuint v0 = %u)", program, location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0); + + if (context->skipValidation() || ValidateProgramUniform1ui(context, program, location, v0)) + { + context->programUniform1ui(program, location, v0); + } + } +} + +void GL_APIENTRY ProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLuint v0 = %u, GLuint v1 = %u)", program, + location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1); + + if (context->skipValidation() || + ValidateProgramUniform2ui(context, program, location, v0, v1)) + { + context->programUniform2ui(program, location, v0, v1); + } + } +} + +void GL_APIENTRY ProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLuint v0 = %u, GLuint v1 = %u, GLuint v2 = " + "%u)", + program, location, v0, v1, v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2); + + if (context->skipValidation() || + ValidateProgramUniform3ui(context, program, location, v0, v1, v2)) + { + context->programUniform3ui(program, location, v0, v1, v2); + } + } +} + +void GL_APIENTRY +ProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLuint v0 = %u, GLuint v1 = %u, GLuint v2 = " + "%u, GLuint v3 = %u)", + program, location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2, v3); + + if (context->skipValidation() || + ValidateProgramUniform4ui(context, program, location, v0, v1, v2, v3)) + { + context->programUniform4ui(program, location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY ProgramUniform1f(GLuint program, GLint location, GLfloat v0) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLfloat v0 = %f)", program, location, v0); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0); + + if (context->skipValidation() || ValidateProgramUniform1f(context, program, location, v0)) + { + context->programUniform1f(program, location, v0); + } + } +} + +void GL_APIENTRY ProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f)", program, + location, v0, v1); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1); + + if (context->skipValidation() || + ValidateProgramUniform2f(context, program, location, v0, v1)) + { + context->programUniform2f(program, location, v0, v1); + } + } +} + +void GL_APIENTRY +ProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f, GLfloat v2 = " + "%f)", + program, location, v0, v1, v2); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2); + + if (context->skipValidation() || + ValidateProgramUniform3f(context, program, location, v0, v1, v2)) + { + context->programUniform3f(program, location, v0, v1, v2); + } + } +} + +void GL_APIENTRY +ProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLfloat v0 = %f, GLfloat v1 = %f, GLfloat v2 = " + "%f, GLfloat v3 = %f)", + program, location, v0, v1, v2, v3); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, v0, v1, v2, v3); + + if (context->skipValidation() || + ValidateProgramUniform4f(context, program, location, v0, v1, v2, v3)) + { + context->programUniform4f(program, location, v0, v1, v2, v3); + } + } +} + +void GL_APIENTRY ProgramUniform1iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform1iv(context, program, location, count, value)) + { + context->programUniform1iv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform2iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform2iv(context, program, location, count, value)) + { + context->programUniform2iv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform3iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform3iv(context, program, location, count, value)) + { + context->programUniform3iv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform4iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform4iv(context, program, location, count, value)) + { + context->programUniform4iv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform1uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLuint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform1uiv(context, program, location, count, value)) + { + context->programUniform1uiv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform2uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLuint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform2uiv(context, program, location, count, value)) + { + context->programUniform2uiv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform3uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLuint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform3uiv(context, program, location, count, value)) + { + context->programUniform3uiv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform4uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLuint *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform4uiv(context, program, location, count, value)) + { + context->programUniform4uiv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform1fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLfloat *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform1fv(context, program, location, count, value)) + { + context->programUniform1fv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform2fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLfloat *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform2fv(context, program, location, count, value)) + { + context->programUniform2fv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform3fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLfloat *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform3fv(context, program, location, count, value)) + { + context->programUniform3fv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniform4fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, const GLfloat *value = " + "0x%0.8p)", + program, location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, value); + + if (context->skipValidation() || + ValidateProgramUniform4fv(context, program, location, count, value)) + { + context->programUniform4fv(program, location, count, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix2fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix2fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix3fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix3fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix4fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix4fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix2x3fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix2x3fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix3x2fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix3x2fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix2x4fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix2x4fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix4x2fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix4x2fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix3x4fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix3x4fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ProgramUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + EVENT( + "(GLuint program = %u, GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, " + "const GLfloat *value = 0x%0.8p)", + program, location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(program, location, count, + transpose, value); + + if (context->skipValidation() || + ValidateProgramUniformMatrix4x3fv(context, program, location, count, transpose, value)) + { + context->programUniformMatrix4x3fv(program, location, count, transpose, value); + } + } +} + +void GL_APIENTRY ValidateProgramPipeline(GLuint pipeline) +{ + EVENT("(GLuint pipeline = %u)", pipeline); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline); + + if (context->skipValidation() || ValidateValidateProgramPipeline(context, pipeline)) + { + context->validateProgramPipeline(pipeline); + } + } +} + +void GL_APIENTRY GetProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + EVENT( + "(GLuint pipeline = %u, GLsizei bufSize = %d, GLsizei *length = 0x%0.8p, GLchar *infoLog = " + "0x%0.8p)", + pipeline, bufSize, length, infoLog); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pipeline, bufSize, length, + infoLog); + + if (context->skipValidation() || + ValidateGetProgramPipelineInfoLog(context, pipeline, bufSize, length, infoLog)) + { + context->getProgramPipelineInfoLog(pipeline, bufSize, length, infoLog); + } + } +} + +void GL_APIENTRY BindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + EVENT( + "(GLuint unit = %u, GLuint texture = %u, GLint level = %d, GLboolean layered = %u, GLint " + "layer = %d, GLenum access = 0x%X, GLenum format = 0x%X)", + unit, texture, level, layered, layer, access, format); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(unit, texture, level, layered, layer, + access, format); + + if (context->skipValidation() || + ValidateBindImageTexture(context, unit, texture, level, layered, layer, access, format)) + { + context->bindImageTexture(unit, texture, level, layered, layer, access, format); + } + } +} + +void GL_APIENTRY GetBooleani_v(GLenum target, GLuint index, GLboolean *data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLboolean *data = 0x%0.8p)", target, index, + data); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, index, data); + + if (context->skipValidation() || ValidateGetBooleani_v(context, target, index, data)) + { + context->getBooleani_v(target, index, data); + } + } +} + +void GL_APIENTRY MemoryBarrier(GLbitfield barriers) +{ + EVENT("(GLbitfield barriers = 0x%X)", barriers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(barriers); + + if (context->skipValidation() || ValidateMemoryBarrier(context, barriers)) + { + context->memoryBarrier(barriers); + } + } +} + +void GL_APIENTRY MemoryBarrierByRegion(GLbitfield barriers) +{ + EVENT("(GLbitfield barriers = 0x%X)", barriers); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(barriers); + + if (context->skipValidation() || ValidateMemoryBarrierByRegion(context, barriers)) + { + context->memoryBarrierByRegion(barriers); + } + } +} + +void GL_APIENTRY TexStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations) +{ + EVENT( + "(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width " + "= %d, GLsizei height = %d, GLboolean fixedsamplelocations = %u)", + target, samples, internalformat, width, height, fixedsamplelocations); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams( + target, samples, internalformat, width, height, fixedsamplelocations); + + if (context->skipValidation() || + ValidateTexStorage2DMultisample(context, target, samples, internalformat, width, height, + fixedsamplelocations)) + { + context->texStorage2DMultisample(target, samples, internalformat, width, height, + fixedsamplelocations); + } + } +} + +void GL_APIENTRY GetMultisamplefv(GLenum pname, GLuint index, GLfloat *val) +{ + EVENT("(GLenum pname = 0x%X, GLuint index = %u, GLfloat *val = 0x%0.8p)", pname, index, val); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(pname, index, val); + + if (context->skipValidation() || ValidateGetMultisamplefv(context, pname, index, val)) + { + context->getMultisamplefv(pname, index, val); + } + } +} + +void GL_APIENTRY SampleMaski(GLuint maskNumber, GLbitfield mask) +{ + EVENT("(GLuint maskNumber = %u, GLbitfield mask = 0x%X)", maskNumber, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(maskNumber, mask); + + if (context->skipValidation() || ValidateSampleMaski(context, maskNumber, mask)) + { + context->sampleMaski(maskNumber, mask); + } + } +} + +void GL_APIENTRY GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", + target, level, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, pname, params); + + if (context->skipValidation() || + ValidateGetTexLevelParameteriv(context, target, level, pname, params)) + { + context->getTexLevelParameteriv(target, level, pname, params); + } + } +} + +void GL_APIENTRY GetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + EVENT( + "(GLenum target = 0x%X, GLint level = %d, GLenum pname = 0x%X, GLfloat *params = 0x%0.8p)", + target, level, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(target, level, pname, params); + + if (context->skipValidation() || + ValidateGetTexLevelParameterfv(context, target, level, pname, params)) + { + context->getTexLevelParameterfv(target, level, pname, params); + } + } +} + +void GL_APIENTRY BindVertexBuffer(GLuint bindingindex, + GLuint buffer, + GLintptr offset, + GLsizei stride) +{ + EVENT( + "(GLuint bindingindex = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizei stride = %d)", + bindingindex, buffer, offset, stride); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(bindingindex, buffer, offset, stride); + + if (context->skipValidation() || + ValidateBindVertexBuffer(context, bindingindex, buffer, offset, stride)) + { + context->bindVertexBuffer(bindingindex, buffer, offset, stride); + } + } +} + +void GL_APIENTRY VertexAttribFormat(GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset) +{ + EVENT( + "(GLuint attribindex = %u, GLint size = %d, GLenum type = 0x%X, GLboolean normalized = %u, " + "GLuint relativeoffset = %u)", + attribindex, size, type, normalized, relativeoffset); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(attribindex, size, type, normalized, + relativeoffset); + + if (context->skipValidation() || + ValidateVertexAttribFormat(context, attribindex, size, type, normalized, + relativeoffset)) + { + context->vertexAttribFormat(attribindex, size, type, normalized, relativeoffset); + } + } +} + +void GL_APIENTRY VertexAttribIFormat(GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset) +{ + EVENT( + "(GLuint attribindex = %u, GLint size = %d, GLenum type = 0x%X, GLuint relativeoffset = " + "%u)", + attribindex, size, type, relativeoffset); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(attribindex, size, type, + relativeoffset); + + if (context->skipValidation() || + ValidateVertexAttribIFormat(context, attribindex, size, type, relativeoffset)) + { + context->vertexAttribIFormat(attribindex, size, type, relativeoffset); + } + } +} + +void GL_APIENTRY VertexAttribBinding(GLuint attribindex, GLuint bindingindex) +{ + EVENT("(GLuint attribindex = %u, GLuint bindingindex = %u)", attribindex, bindingindex); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(attribindex, bindingindex); + + if (context->skipValidation() || + ValidateVertexAttribBinding(context, attribindex, bindingindex)) + { + context->vertexAttribBinding(attribindex, bindingindex); + } + } +} + +void GL_APIENTRY VertexBindingDivisor(GLuint bindingindex, GLuint divisor) +{ + EVENT("(GLuint bindingindex = %u, GLuint divisor = %u)", bindingindex, divisor); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->gatherParams(bindingindex, divisor); + + if (context->skipValidation() || + ValidateVertexBindingDivisor(context, bindingindex, divisor)) + { + context->vertexBindingDivisor(bindingindex, divisor); + } + } +} +} // namespace gl diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.h new file mode 100644 index 0000000000..e11d5a10bf --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_1_autogen.h @@ -0,0 +1,228 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_entry_points.py using data from gl.xml. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// entry_points_gles_3_1_autogen.h: +// Defines the GLES 3.1 entry points. + +#ifndef LIBGLESV2_ENTRYPOINTSGLES31_AUTOGEN_H_ +#define LIBGLESV2_ENTRYPOINTSGLES31_AUTOGEN_H_ + +#include +#include + +#include "common/platform.h" + +namespace gl +{ +ANGLE_EXPORT void GL_APIENTRY DispatchCompute(GLuint num_groups_x, + GLuint num_groups_y, + GLuint num_groups_z); +ANGLE_EXPORT void GL_APIENTRY DispatchComputeIndirect(GLintptr indirect); +ANGLE_EXPORT void GL_APIENTRY DrawArraysIndirect(GLenum mode, const void *indirect); +ANGLE_EXPORT void GL_APIENTRY DrawElementsIndirect(GLenum mode, GLenum type, const void *indirect); +ANGLE_EXPORT void GL_APIENTRY FramebufferParameteri(GLenum target, GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params); +ANGLE_EXPORT GLuint GL_APIENTRY GetProgramResourceIndex(GLuint program, + GLenum programInterface, + const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name); +ANGLE_EXPORT void GL_APIENTRY GetProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params); +ANGLE_EXPORT GLint GL_APIENTRY GetProgramResourceLocation(GLuint program, + GLenum programInterface, + const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program); +ANGLE_EXPORT void GL_APIENTRY ActiveShaderProgram(GLuint pipeline, GLuint program); +ANGLE_EXPORT GLuint GL_APIENTRY CreateShaderProgramv(GLenum type, + GLsizei count, + const GLchar *const *strings); +ANGLE_EXPORT void GL_APIENTRY BindProgramPipeline(GLuint pipeline); +ANGLE_EXPORT void GL_APIENTRY DeleteProgramPipelines(GLsizei n, const GLuint *pipelines); +ANGLE_EXPORT void GL_APIENTRY GenProgramPipelines(GLsizei n, GLuint *pipelines); +ANGLE_EXPORT GLboolean GL_APIENTRY IsProgramPipeline(GLuint pipeline); +ANGLE_EXPORT void GL_APIENTRY GetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1i(GLuint program, GLint location, GLint v0); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1ui(GLuint program, GLint location, GLuint v0); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2ui(GLuint program, + GLint location, + GLuint v0, + GLuint v1); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1f(GLuint program, GLint location, GLfloat v0); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2f(GLuint program, + GLint location, + GLfloat v0, + GLfloat v1); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +ANGLE_EXPORT void GL_APIENTRY +ProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform3iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform4iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform3uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform4uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform1fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform2fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform3fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniform4fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ProgramUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); +ANGLE_EXPORT void GL_APIENTRY ValidateProgramPipeline(GLuint pipeline); +ANGLE_EXPORT void GL_APIENTRY GetProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog); +ANGLE_EXPORT void GL_APIENTRY BindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format); +ANGLE_EXPORT void GL_APIENTRY GetBooleani_v(GLenum target, GLuint index, GLboolean *data); +ANGLE_EXPORT void GL_APIENTRY MemoryBarrier(GLbitfield barriers); +ANGLE_EXPORT void GL_APIENTRY MemoryBarrierByRegion(GLbitfield barriers); +ANGLE_EXPORT void GL_APIENTRY TexStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); +ANGLE_EXPORT void GL_APIENTRY GetMultisamplefv(GLenum pname, GLuint index, GLfloat *val); +ANGLE_EXPORT void GL_APIENTRY SampleMaski(GLuint maskNumber, GLbitfield mask); +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameteriv(GLenum target, + GLint level, + GLenum pname, + GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetTexLevelParameterfv(GLenum target, + GLint level, + GLenum pname, + GLfloat *params); +ANGLE_EXPORT void GL_APIENTRY BindVertexBuffer(GLuint bindingindex, + GLuint buffer, + GLintptr offset, + GLsizei stride); +ANGLE_EXPORT void GL_APIENTRY VertexAttribFormat(GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset); +ANGLE_EXPORT void GL_APIENTRY VertexAttribIFormat(GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset); +ANGLE_EXPORT void GL_APIENTRY VertexAttribBinding(GLuint attribindex, GLuint bindingindex); +ANGLE_EXPORT void GL_APIENTRY VertexBindingDivisor(GLuint bindingindex, GLuint divisor); +} // namespace gl + +#endif // LIBGLESV2_ENTRYPOINTSGLES31_AUTOGEN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp index b99c3e1ca9..c5f3dfe4e1 100644 --- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp +++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp @@ -8,229 +8,141 @@ #include "libGLESv2/global_state.h" -#include "libANGLE/Context.h" -#include "libANGLE/Error.h" - #include "common/debug.h" #include "common/platform.h" #include "common/tls.h" -namespace -{ - -static TLSIndex currentTLS = TLS_INVALID_INDEX; - -struct Current -{ - EGLint error; - EGLenum API; - egl::Display *display; - egl::Surface *drawSurface; - egl::Surface *readSurface; - gl::Context *context; -}; - -Current *AllocateCurrent() -{ - ASSERT(currentTLS != TLS_INVALID_INDEX); - if (currentTLS == TLS_INVALID_INDEX) - { - return NULL; - } - - Current *current = new Current(); - current->error = EGL_SUCCESS; - current->API = EGL_OPENGL_ES_API; - current->display = reinterpret_cast(EGL_NO_DISPLAY); - current->drawSurface = reinterpret_cast(EGL_NO_SURFACE); - current->readSurface = reinterpret_cast(EGL_NO_SURFACE); - current->context = reinterpret_cast(EGL_NO_CONTEXT); - - if (!SetTLSValue(currentTLS, current)) - { - ERR("Could not set thread local storage."); - return NULL; - } +#include "libANGLE/Thread.h" - return current; -} - -Current *GetCurrentData() +namespace gl { - // Create a TLS index if one has not been created for this DLL - if (currentTLS == TLS_INVALID_INDEX) - { - currentTLS = CreateTLSIndex(); - } - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - - // ANGLE issue 488: when the dll is loaded after thread initialization, - // thread local storage (current) might not exist yet. - return (current ? current : AllocateCurrent()); -} - -#ifdef ANGLE_PLATFORM_WINDOWS - -void DeallocateCurrent() +Context *GetGlobalContext() { - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - SafeDelete(current); - SetTLSValue(currentTLS, NULL); + egl::Thread *thread = egl::GetCurrentThread(); + return thread->getContext(); } -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) +Context *GetValidGlobalContext() { - switch (reason) - { - case DLL_PROCESS_ATTACH: - currentTLS = CreateTLSIndex(); - if (currentTLS == TLS_INVALID_INDEX) - { - return FALSE; - } - AllocateCurrent(); - break; - - case DLL_THREAD_ATTACH: - AllocateCurrent(); - break; - - case DLL_THREAD_DETACH: - DeallocateCurrent(); - break; - - case DLL_PROCESS_DETACH: - DeallocateCurrent(); - if (currentTLS != TLS_INVALID_INDEX) - { - DestroyTLSIndex(currentTLS); - currentTLS = TLS_INVALID_INDEX; - } - break; - } - - return TRUE; + egl::Thread *thread = egl::GetCurrentThread(); + return thread->getValidContext(); } -#endif -} +} // namespace gl -namespace gl +namespace egl { -Context *GetGlobalContext() +namespace { - Current *current = GetCurrentData(); - return current->context; -} +static TLSIndex threadTLS = TLS_INVALID_INDEX; -Context *GetValidGlobalContext() +Thread *AllocateCurrentThread() { - gl::Context *context = GetGlobalContext(); - if (context) + ASSERT(threadTLS != TLS_INVALID_INDEX); + if (threadTLS == TLS_INVALID_INDEX) { - if (context->isContextLost()) - { - context->recordError(gl::Error(GL_OUT_OF_MEMORY, "Context has been lost.")); - return nullptr; - } - else - { - return context; - } + return nullptr; + } + + Thread *thread = new Thread(); + if (!SetTLSValue(threadTLS, thread)) + { + ERR() << "Could not set thread local storage."; + return nullptr; } - return nullptr; -} + return thread; } -namespace egl -{ +} // anonymous namespace -void SetGlobalError(const Error &error) +Thread *GetCurrentThread() { - Current *current = GetCurrentData(); - - current->error = error.getCode(); -} + // Create a TLS index if one has not been created for this DLL + if (threadTLS == TLS_INVALID_INDEX) + { + threadTLS = CreateTLSIndex(); + } -EGLint GetGlobalError() -{ - Current *current = GetCurrentData(); + Thread *current = static_cast(GetTLSValue(threadTLS)); - return current->error; + // ANGLE issue 488: when the dll is loaded after thread initialization, + // thread local storage (current) might not exist yet. + return (current ? current : AllocateCurrentThread()); } -EGLenum GetGlobalAPI() -{ - Current *current = GetCurrentData(); - - return current->API; -} +} // namespace egl -void SetGlobalAPI(EGLenum API) +#ifdef ANGLE_PLATFORM_WINDOWS +namespace egl { - Current *current = GetCurrentData(); - - current->API = API; -} -void SetGlobalDisplay(Display *dpy) +namespace { - Current *current = GetCurrentData(); - - current->display = dpy; -} -Display *GetGlobalDisplay() +bool DeallocateCurrentThread() { - Current *current = GetCurrentData(); - - return current->display; + Thread *thread = static_cast(GetTLSValue(threadTLS)); + SafeDelete(thread); + return SetTLSValue(threadTLS, nullptr); } -void SetGlobalDrawSurface(Surface *surface) +bool InitializeProcess() { - Current *current = GetCurrentData(); + threadTLS = CreateTLSIndex(); + if (threadTLS == TLS_INVALID_INDEX) + { + return false; + } - current->drawSurface = surface; + return AllocateCurrentThread() != nullptr; } -Surface *GetGlobalDrawSurface() +bool TerminateProcess() { - Current *current = GetCurrentData(); + if (!DeallocateCurrentThread()) + { + return false; + } - return current->drawSurface; -} + if (threadTLS != TLS_INVALID_INDEX) + { + TLSIndex tlsCopy = threadTLS; + threadTLS = TLS_INVALID_INDEX; -void SetGlobalReadSurface(Surface *surface) -{ - Current *current = GetCurrentData(); + if (!DestroyTLSIndex(tlsCopy)) + { + return false; + } + } - current->readSurface = surface; + return true; } -Surface *GetGlobalReadSurface() -{ - Current *current = GetCurrentData(); +} // anonymous namespace - return current->readSurface; -} +} // namespace egl -void SetGlobalContext(gl::Context *context) +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) { - Current *current = GetCurrentData(); + switch (reason) + { + case DLL_PROCESS_ATTACH: + return static_cast(egl::InitializeProcess()); - current->context = context; -} + case DLL_THREAD_ATTACH: + return static_cast(egl::AllocateCurrentThread() != nullptr); -gl::Context *GetGlobalContext() -{ - Current *current = GetCurrentData(); + case DLL_THREAD_DETACH: + return static_cast(egl::DeallocateCurrentThread()); - return current->context; -} + case DLL_PROCESS_DETACH: + return static_cast(egl::TerminateProcess()); + } + return TRUE; } +#endif // ANGLE_PLATFORM_WINDOWS diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.h b/src/3rdparty/angle/src/libGLESv2/global_state.h index db202539cb..3e3740c90e 100644 --- a/src/3rdparty/angle/src/libGLESv2/global_state.h +++ b/src/3rdparty/angle/src/libGLESv2/global_state.h @@ -9,8 +9,6 @@ #ifndef LIBGLESV2_GLOBALSTATE_H_ #define LIBGLESV2_GLOBALSTATE_H_ -#include - namespace gl { class Context; @@ -18,32 +16,14 @@ class Context; Context *GetGlobalContext(); Context *GetValidGlobalContext(); -} +} // namespace gl namespace egl { -class Error; -class Display; -class Surface; - -void SetGlobalError(const Error &error); -EGLint GetGlobalError(); - -void SetGlobalAPI(EGLenum API); -EGLenum GetGlobalAPI(); - -void SetGlobalDisplay(Display *dpy); -Display *GetGlobalDisplay(); - -void SetGlobalDrawSurface(Surface *surface); -Surface *GetGlobalDrawSurface(); - -void SetGlobalReadSurface(Surface *surface); -Surface *GetGlobalReadSurface(); +class Thread; -void SetGlobalContext(gl::Context *context); -gl::Context *GetGlobalContext(); +Thread *GetCurrentThread(); -} +} // namespace egl #endif // LIBGLESV2_GLOBALSTATE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp index 42b749f373..ffd78a2ac0 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -6,14 +6,14 @@ // libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. -#include "libGLESv2/entry_points_gles_2_0.h" +#include "libGLESv2/entry_points_gles_2_0_autogen.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_autogen.h" +#include "libGLESv2/entry_points_gles_3_1_autogen.h" #include "common/event_tracer.h" -extern "C" -{ +extern "C" { void GL_APIENTRY glActiveTexture(GLenum texture) { @@ -25,7 +25,7 @@ void GL_APIENTRY glAttachShader(GLuint program, GLuint shader) return gl::AttachShader(program, shader); } -void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) { return gl::BindAttribLocation(program, index, name); } @@ -75,12 +75,12 @@ void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlp return gl::BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); } -void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) { return gl::BufferData(target, size, data, usage); } -void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { return gl::BufferSubData(target, offset, size, data); } @@ -120,22 +120,53 @@ void GL_APIENTRY glCompileShader(GLuint shader) return gl::CompileShader(shader); } -void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void *data) { - return gl::CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); + return gl::CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, + data); } -void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void *data) { - return gl::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); + return gl::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + imageSize, data); } -void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +void GL_APIENTRY glCopyTexImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border) { return gl::CopyTexImage2D(target, level, internalformat, x, y, width, height, border); } -void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glCopyTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { return gl::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); } @@ -155,12 +186,12 @@ void GL_APIENTRY glCullFace(GLenum mode) return gl::CullFace(mode); } -void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers) +void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint *buffers) { return gl::DeleteBuffers(n, buffers); } -void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) { return gl::DeleteFramebuffers(n, framebuffers); } @@ -170,7 +201,7 @@ void GL_APIENTRY glDeleteProgram(GLuint program) return gl::DeleteProgram(program); } -void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) { return gl::DeleteRenderbuffers(n, renderbuffers); } @@ -180,7 +211,7 @@ void GL_APIENTRY glDeleteShader(GLuint shader) return gl::DeleteShader(shader); } -void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures) +void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint *textures) { return gl::DeleteTextures(n, textures); } @@ -220,7 +251,7 @@ void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) return gl::DrawArrays(mode, first, count); } -void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) { return gl::DrawElements(mode, count, type, indices); } @@ -245,12 +276,19 @@ void GL_APIENTRY glFlush(void) return gl::Flush(); } -void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) { return gl::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); } -void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +void GL_APIENTRY glFramebufferTexture2D(GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level) { return gl::FramebufferTexture2D(target, attachment, textarget, texture, level); } @@ -260,7 +298,7 @@ void GL_APIENTRY glFrontFace(GLenum mode) return gl::FrontFace(mode); } -void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers) +void GL_APIENTRY glGenBuffers(GLsizei n, GLuint *buffers) { return gl::GenBuffers(n, buffers); } @@ -270,47 +308,62 @@ void GL_APIENTRY glGenerateMipmap(GLenum target) return gl::GenerateMipmap(target); } -void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers) +void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint *framebuffers) { return gl::GenFramebuffers(n, framebuffers); } -void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) { return gl::GenRenderbuffers(n, renderbuffers); } -void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures) +void GL_APIENTRY glGenTextures(GLsizei n, GLuint *textures) { return gl::GenTextures(n, textures); } -void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +void GL_APIENTRY glGetActiveAttrib(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) { return gl::GetActiveAttrib(program, index, bufsize, length, size, type, name); } -void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +void GL_APIENTRY glGetActiveUniform(GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei *length, + GLint *size, + GLenum *type, + GLchar *name) { return gl::GetActiveUniform(program, index, bufsize, length, size, type, name); } -void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +void GL_APIENTRY glGetAttachedShaders(GLuint program, + GLsizei maxcount, + GLsizei *count, + GLuint *shaders) { return gl::GetAttachedShaders(program, maxcount, count, shaders); } -GLint GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name) +GLint GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar *name) { return gl::GetAttribLocation(program, name); } -void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params) +void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean *params) { return gl::GetBooleanv(pname, params); } -void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params) { return gl::GetBufferParameteriv(target, pname, params); } @@ -320,97 +373,109 @@ GLenum GL_APIENTRY glGetError(void) return gl::GetError(); } -void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params) +void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat *params) { return gl::GetFloatv(pname, params); } -void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, + GLenum attachment, + GLenum pname, + GLint *params) { return gl::GetFramebufferAttachmentParameteriv(target, attachment, pname, params); } -void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params) +void GL_APIENTRY glGetIntegerv(GLenum pname, GLint *params) { return gl::GetIntegerv(pname, params); } -void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params) +void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint *params) { return gl::GetProgramiv(program, pname, params); } -void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void GL_APIENTRY glGetProgramInfoLog(GLuint program, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) { return gl::GetProgramInfoLog(program, bufsize, length, infolog); } -void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) { return gl::GetRenderbufferParameteriv(target, pname, params); } -void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint *params) { return gl::GetShaderiv(shader, pname, params); } -void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void GL_APIENTRY glGetShaderInfoLog(GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *infolog) { return gl::GetShaderInfoLog(shader, bufsize, length, infolog); } -void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, + GLenum precisiontype, + GLint *range, + GLint *precision) { return gl::GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); } -void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) { return gl::GetShaderSource(shader, bufsize, length, source); } -const GLubyte* GL_APIENTRY glGetString(GLenum name) +const GLubyte *GL_APIENTRY glGetString(GLenum name) { return gl::GetString(name); } -void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) { return gl::GetTexParameterfv(target, pname, params); } -void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint *params) { return gl::GetTexParameteriv(target, pname, params); } -void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params) +void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat *params) { return gl::GetUniformfv(program, location, params); } -void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params) +void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint *params) { return gl::GetUniformiv(program, location, params); } -GLint GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name) +GLint GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar *name) { return gl::GetUniformLocation(program, name); } -void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) { return gl::GetVertexAttribfv(index, pname, params); } -void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) { return gl::GetVertexAttribiv(index, pname, params); } -void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer) { return gl::GetVertexAttribPointerv(index, pname, pointer); } @@ -475,7 +540,13 @@ void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units) return gl::PolygonOffset(factor, units); } -void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +void GL_APIENTRY glReadPixels(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void *pixels) { return gl::ReadPixels(x, y, width, height, format, type, pixels); } @@ -485,7 +556,10 @@ void GL_APIENTRY glReleaseShaderCompiler(void) return gl::ReleaseShaderCompiler(); } -void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorage(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height) { return gl::RenderbufferStorage(target, internalformat, width, height); } @@ -500,12 +574,19 @@ void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) return gl::Scissor(x, y, width, height); } -void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +void GL_APIENTRY glShaderBinary(GLsizei n, + const GLuint *shaders, + GLenum binaryformat, + const void *binary, + GLsizei length) { return gl::ShaderBinary(n, shaders, binaryformat, binary, length); } -void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) +void GL_APIENTRY glShaderSource(GLuint shader, + GLsizei count, + const GLchar *const *string, + const GLint *length) { return gl::ShaderSource(shader, count, string, length); } @@ -540,9 +621,18 @@ void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLe return gl::StencilOpSeparate(face, fail, zfail, zpass); } -void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +void GL_APIENTRY glTexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels) { - return gl::TexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + return gl::TexImage2D(target, level, internalformat, width, height, border, format, type, + pixels); } void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) @@ -550,7 +640,7 @@ void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) return gl::TexParameterf(target, pname, param); } -void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) { return gl::TexParameterfv(target, pname, params); } @@ -560,12 +650,20 @@ void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) return gl::TexParameteri(target, pname, param); } -void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint *params) { return gl::TexParameteriv(target, pname, params); } -void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +void GL_APIENTRY glTexSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void *pixels) { return gl::TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); } @@ -575,7 +673,7 @@ void GL_APIENTRY glUniform1f(GLint location, GLfloat x) return gl::Uniform1f(location, x); } -void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat *v) { return gl::Uniform1fv(location, count, v); } @@ -585,7 +683,7 @@ void GL_APIENTRY glUniform1i(GLint location, GLint x) return gl::Uniform1i(location, x); } -void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint *v) { return gl::Uniform1iv(location, count, v); } @@ -595,7 +693,7 @@ void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y) return gl::Uniform2f(location, x, y); } -void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat *v) { return gl::Uniform2fv(location, count, v); } @@ -605,7 +703,7 @@ void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y) return gl::Uniform2i(location, x, y); } -void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint *v) { return gl::Uniform2iv(location, count, v); } @@ -615,7 +713,7 @@ void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) return gl::Uniform3f(location, x, y, z); } -void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat *v) { return gl::Uniform3fv(location, count, v); } @@ -625,7 +723,7 @@ void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z) return gl::Uniform3i(location, x, y, z); } -void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint *v) { return gl::Uniform3iv(location, count, v); } @@ -635,7 +733,7 @@ void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GL return gl::Uniform4f(location, x, y, z, w); } -void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat *v) { return gl::Uniform4fv(location, count, v); } @@ -645,22 +743,31 @@ void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) return gl::Uniform4i(location, x, y, z, w); } -void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint *v) { return gl::Uniform4iv(location, count, v); } -void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix2fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix3fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix4fv(location, count, transpose, value); } @@ -680,7 +787,7 @@ void GL_APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x) return gl::VertexAttrib1f(indx, x); } -void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values) +void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat *values) { return gl::VertexAttrib1fv(indx, values); } @@ -690,7 +797,7 @@ void GL_APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) return gl::VertexAttrib2f(indx, x, y); } -void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values) +void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat *values) { return gl::VertexAttrib2fv(indx, values); } @@ -700,7 +807,7 @@ void GL_APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) return gl::VertexAttrib3f(indx, x, y, z); } -void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values) +void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat *values) { return gl::VertexAttrib3fv(indx, values); } @@ -710,12 +817,17 @@ void GL_APIENTRY glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, return gl::VertexAttrib4f(indx, x, y, z, w); } -void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values) +void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat *values) { return gl::VertexAttrib4fv(indx, values); } -void GL_APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +void GL_APIENTRY glVertexAttribPointer(GLuint indx, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void *ptr) { return gl::VertexAttribPointer(indx, size, type, normalized, stride, ptr); } @@ -730,42 +842,96 @@ void GL_APIENTRY glReadBuffer(GLenum mode) return gl::ReadBuffer(mode); } -void GL_APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) +void GL_APIENTRY glDrawRangeElements(GLenum mode, + GLuint start, + GLuint end, + GLsizei count, + GLenum type, + const void *indices) { return gl::DrawRangeElements(mode, start, end, count, type, indices); } -void GL_APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) -{ - return gl::TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); -} - -void GL_APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) -{ - return gl::TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); -} - -void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glTexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *pixels) +{ + return gl::TexImage3D(target, level, internalformat, width, height, depth, border, format, type, + pixels); +} + +void GL_APIENTRY glTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void *pixels) +{ + return gl::TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, + type, pixels); +} + +void GL_APIENTRY glCopyTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { return gl::CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); } -void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexImage3D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLsizei imageSize, + const void *data) { - return gl::CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); + return gl::CompressedTexImage3D(target, level, internalformat, width, height, depth, border, + imageSize, data); } -void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLsizei imageSize, + const void *data) { - return gl::CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); + return gl::CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, + depth, format, imageSize, data); } -void GL_APIENTRY glGenQueries(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenQueries(GLsizei n, GLuint *ids) { return gl::GenQueries(n, ids); } -void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint* ids) +void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint *ids) { return gl::DeleteQueries(n, ids); } @@ -785,12 +951,12 @@ void GL_APIENTRY glEndQuery(GLenum target) return gl::EndQuery(target); } -void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint *params) { return gl::GetQueryiv(target, pname, params); } -void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) +void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) { return gl::GetQueryObjectuiv(id, pname, params); } @@ -800,62 +966,101 @@ GLboolean GL_APIENTRY glUnmapBuffer(GLenum target) return gl::UnmapBuffer(target); } -void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) +void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void **params) { return gl::GetBufferPointerv(target, pname, params); } -void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum* bufs) +void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum *bufs) { return gl::DrawBuffers(n, bufs); } -void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix2x3fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix3x2fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix2x4fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4x2fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix4x2fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3x4fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix3x4fv(location, count, transpose, value); } -void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4x3fv(GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) { return gl::UniformMatrix4x3fv(location, count, transpose, value); } -void GL_APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +void GL_APIENTRY glBlitFramebuffer(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) { - return gl::BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + return gl::BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, + filter); } -void GL_APIENTRY glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorageMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) { return gl::RenderbufferStorageMultisample(target, samples, internalformat, width, height); } -void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +void GL_APIENTRY glFramebufferTextureLayer(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint layer) { return gl::FramebufferTextureLayer(target, attachment, texture, level, layer); } -GLvoid* GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +void *GL_APIENTRY glMapBufferRange(GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { return gl::MapBufferRange(target, offset, length, access); } @@ -870,12 +1075,12 @@ void GL_APIENTRY glBindVertexArray(GLuint array) return gl::BindVertexArray(array); } -void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint* arrays) +void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint *arrays) { return gl::DeleteVertexArrays(n, arrays); } -void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint* arrays) +void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint *arrays) { return gl::GenVertexArrays(n, arrays); } @@ -885,7 +1090,7 @@ GLboolean GL_APIENTRY glIsVertexArray(GLuint array) return gl::IsVertexArray(array); } -void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint* data) +void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint *data) { return gl::GetIntegeri_v(target, index, data); } @@ -900,7 +1105,8 @@ void GL_APIENTRY glEndTransformFeedback(void) return gl::EndTransformFeedback(); } -void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +void GL_APIENTRY +glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { return gl::BindBufferRange(target, index, buffer, offset, size); } @@ -910,27 +1116,37 @@ void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer) return gl::BindBufferBase(target, index, buffer); } -void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) +void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, + GLsizei count, + const GLchar *const *varyings, + GLenum bufferMode) { return gl::TransformFeedbackVaryings(program, count, varyings, bufferMode); } -void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) +void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLsizei *size, + GLenum *type, + GLchar *name) { return gl::GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name); } -void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) +void GL_APIENTRY +glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) { return gl::VertexAttribIPointer(index, size, type, stride, pointer); } -void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) +void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params) { return gl::GetVertexAttribIiv(index, pname, params); } -void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) +void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params) { return gl::GetVertexAttribIuiv(index, pname, params); } @@ -945,17 +1161,17 @@ void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, return gl::VertexAttribI4ui(index, x, y, z, w); } -void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint* v) +void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint *v) { return gl::VertexAttribI4iv(index, v); } -void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint* v) +void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint *v) { return gl::VertexAttribI4uiv(index, v); } -void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint* params) +void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint *params) { return gl::GetUniformuiv(program, location, params); } @@ -985,37 +1201,37 @@ void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, G return gl::Uniform4ui(location, v0, v1, v2, v3); } -void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint *value) { return gl::Uniform1uiv(location, count, value); } -void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint *value) { return gl::Uniform2uiv(location, count, value); } -void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint *value) { return gl::Uniform3uiv(location, count, value); } -void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint *value) { return gl::Uniform4uiv(location, count, value); } -void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) +void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value) { return gl::ClearBufferiv(buffer, drawbuffer, value); } -void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) +void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) { return gl::ClearBufferuiv(buffer, drawbuffer, value); } -void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) +void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) { return gl::ClearBufferfv(buffer, drawbuffer, value); } @@ -1025,59 +1241,87 @@ void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, return gl::ClearBufferfi(buffer, drawbuffer, depth, stencil); } -const GLubyte* GL_APIENTRY glGetStringi(GLenum name, GLuint index) +const GLubyte *GL_APIENTRY glGetStringi(GLenum name, GLuint index) { return gl::GetStringi(name, index); } -void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) +void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, + GLenum writeTarget, + GLintptr readOffset, + GLintptr writeOffset, + GLsizeiptr size) { return gl::CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); } -void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) +void GL_APIENTRY glGetUniformIndices(GLuint program, + GLsizei uniformCount, + const GLchar *const *uniformNames, + GLuint *uniformIndices) { return gl::GetUniformIndices(program, uniformCount, uniformNames, uniformIndices); } -void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) +void GL_APIENTRY glGetActiveUniformsiv(GLuint program, + GLsizei uniformCount, + const GLuint *uniformIndices, + GLenum pname, + GLint *params) { return gl::GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); } -GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) +GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) { return gl::GetUniformBlockIndex(program, uniformBlockName); } -void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) +void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, + GLuint uniformBlockIndex, + GLenum pname, + GLint *params) { return gl::GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params); } -void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) +void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, + GLsizei *length, + GLchar *uniformBlockName) { - return gl::GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName); + return gl::GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, + uniformBlockName); } -void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +void GL_APIENTRY glUniformBlockBinding(GLuint program, + GLuint uniformBlockIndex, + GLuint uniformBlockBinding) { return gl::UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); } -void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +void GL_APIENTRY glDrawArraysInstanced(GLenum mode, + GLint first, + GLsizei count, + GLsizei instanceCount) { return gl::DrawArraysInstanced(mode, first, count, instanceCount); } -void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) +void GL_APIENTRY glDrawElementsInstanced(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei instanceCount) { return gl::DrawElementsInstanced(mode, count, type, indices, instanceCount); } GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags) { - return gl::FenceSync_(condition, flags); + return gl::FenceSync(condition, flags); } GLboolean GL_APIENTRY glIsSync(GLsync sync) @@ -1100,32 +1344,33 @@ void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) return gl::WaitSync(sync, flags, timeout); } -void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64* params) +void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64 *params) { return gl::GetInteger64v(pname, params); } -void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) +void GL_APIENTRY +glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { return gl::GetSynciv(sync, pname, bufSize, length, values); } -void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) +void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data) { return gl::GetInteger64i_v(target, index, data); } -void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) +void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) { return gl::GetBufferParameteri64v(target, pname, params); } -void GL_APIENTRY glGenSamplers(GLsizei count, GLuint* samplers) +void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers) { return gl::GenSamplers(count, samplers); } -void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint* samplers) +void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint *samplers) { return gl::DeleteSamplers(count, samplers); } @@ -1145,7 +1390,7 @@ void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) return gl::SamplerParameteri(sampler, pname, param); } -void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) +void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param) { return gl::SamplerParameteriv(sampler, pname, param); } @@ -1155,17 +1400,17 @@ void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param return gl::SamplerParameterf(sampler, pname, param); } -void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) +void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param) { return gl::SamplerParameterfv(sampler, pname, param); } -void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) +void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params) { return gl::GetSamplerParameteriv(sampler, pname, params); } -void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params) { return gl::GetSamplerParameterfv(sampler, pname, params); } @@ -1180,12 +1425,12 @@ void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id) return gl::BindTransformFeedback(target, id); } -void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids) { return gl::DeleteTransformFeedbacks(n, ids); } -void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint *ids) { return gl::GenTransformFeedbacks(n, ids); } @@ -1205,12 +1450,19 @@ void GL_APIENTRY glResumeTransformFeedback(void) return gl::ResumeTransformFeedback(); } -void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +void GL_APIENTRY glGetProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) { return gl::GetProgramBinary(program, bufSize, length, binaryFormat, binary); } -void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) +void GL_APIENTRY glProgramBinary(GLuint program, + GLenum binaryFormat, + const void *binary, + GLsizei length) { return gl::ProgramBinary(program, binaryFormat, binary, length); } @@ -1220,52 +1472,86 @@ void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value) return gl::ProgramParameteri(program, pname, value); } -void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +void GL_APIENTRY glInvalidateFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments) { return gl::InvalidateFramebuffer(target, numAttachments, attachments); } -void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { return gl::InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); } -void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY +glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { return gl::TexStorage2D(target, levels, internalformat, width, height); } -void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +void GL_APIENTRY glTexStorage3D(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLsizei depth) { return gl::TexStorage3D(target, levels, internalformat, width, height, depth); } -void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +void GL_APIENTRY glGetInternalformativ(GLenum target, + GLenum internalformat, + GLenum pname, + GLsizei bufSize, + GLint *params) { return gl::GetInternalformativ(target, internalformat, pname, bufSize, params); } -void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter) { - return gl::BlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + return gl::BlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, + filter); } -void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height) { return gl::RenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height); } -void GL_APIENTRY glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) +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) +void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint *fences) { return gl::DeleteFencesNV(n, fences); } -void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences) +void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint *fences) { return gl::GenFencesNV(n, fences); } @@ -1295,12 +1581,19 @@ void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition) return gl::SetFenceNV(fence, condition); } -void GL_APIENTRY glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) +void GL_APIENTRY glGetTranslatedShaderSourceANGLE(GLuint shader, + GLsizei bufsize, + GLsizei *length, + GLchar *source) { return gl::GetTranslatedShaderSourceANGLE(shader, bufsize, length, source); } -void GL_APIENTRY glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glTexStorage2DEXT(GLenum target, + GLsizei levels, + GLenum internalformat, + GLsizei width, + GLsizei height) { return gl::TexStorage2DEXT(target, levels, internalformat, width, height); } @@ -1310,7 +1603,14 @@ GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void) return gl::GetGraphicsResetStatusEXT(); } -void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) +void GL_APIENTRY glReadnPixelsEXT(GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLsizei bufSize, + void *data) { return gl::ReadnPixelsEXT(x, y, width, height, format, type, bufSize, data); } @@ -1385,12 +1685,19 @@ void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) return gl::DrawBuffersEXT(n, bufs); } -void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) { return gl::DrawArraysInstancedANGLE(mode, first, count, primcount); } -void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) +void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, + GLsizei count, + GLenum type, + const void *indices, + GLsizei primcount) { return gl::DrawElementsInstancedANGLE(mode, count, type, indices, primcount); } @@ -1400,17 +1707,24 @@ void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) return gl::VertexAttribDivisorANGLE(index, divisor); } -void GL_APIENTRY glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) +void GL_APIENTRY glGetProgramBinaryOES(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) { return gl::GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary); } -void GL_APIENTRY glProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length) +void GL_APIENTRY glProgramBinaryOES(GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) { return gl::ProgramBinaryOES(program, binaryFormat, binary, length); } -void* GL_APIENTRY glMapBufferOES(GLenum target, GLenum access) +void *GL_APIENTRY glMapBufferOES(GLenum target, GLenum access) { return gl::MapBufferOES(target, access); } @@ -1420,12 +1734,15 @@ GLboolean GL_APIENTRY glUnmapBufferOES(GLenum target) return gl::UnmapBufferOES(target); } -void GL_APIENTRY glGetBufferPointervOES(GLenum target, GLenum pname, GLvoid **params) +void GL_APIENTRY glGetBufferPointervOES(GLenum target, GLenum pname, void **params) { return gl::GetBufferPointervOES(target, pname, params); } -void* GL_APIENTRY glMapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +void *GL_APIENTRY glMapBufferRangeEXT(GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { return gl::MapBufferRangeEXT(target, offset, length, access); } @@ -1562,4 +1879,697 @@ void GL_APIENTRY glGetPointervKHR(GLenum pname, void **params) { return gl::GetPointervKHR(pname, params); } + +void GL_APIENTRY glBindUniformLocationCHROMIUM(GLuint program, GLint location, const GLchar *name) +{ + return gl::BindUniformLocationCHROMIUM(program, location, name); +} + +void GL_APIENTRY glCoverageModulationCHROMIUM(GLenum components) +{ + return gl::CoverageModulationCHROMIUM(components); +} + +// CHROMIUM_path_rendendering +void GL_APIENTRY glMatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat *matrix) +{ + gl::MatrixLoadfCHROMIUM(matrixMode, matrix); +} + +void GL_APIENTRY glMatrixLoadIdentityCHROMIUM(GLenum matrixMode) +{ + gl::MatrixLoadIdentityCHROMIUM(matrixMode); +} + +GLuint GL_APIENTRY glGenPathsCHROMIUM(GLsizei range) +{ + return gl::GenPathsCHROMIUM(range); +} + +void GL_APIENTRY glDeletePathsCHROMIUM(GLuint first, GLsizei range) +{ + gl::DeletePathsCHROMIUM(first, range); +} + +GLboolean GL_APIENTRY glIsPathCHROMIUM(GLuint path) +{ + return gl::IsPathCHROMIUM(path); +} + +void GL_APIENTRY glPathCommandsCHROMIUM(GLuint path, + GLsizei numCommands, + const GLubyte *commands, + GLsizei numCoords, + GLenum coordType, + const void *coords) +{ + gl::PathCommandsCHROMIUM(path, numCommands, commands, numCoords, coordType, coords); +} + +void GL_APIENTRY glPathParameterfCHROMIUM(GLuint path, GLenum pname, GLfloat value) +{ + gl::PathParameterfCHROMIUM(path, pname, value); +} + +void GL_APIENTRY glPathParameteriCHROMIUM(GLuint path, GLenum pname, GLint value) +{ + gl::PathParameteriCHROMIUM(path, pname, value); +} + +void GL_APIENTRY glGetPathParameterfvCHROMIUM(GLuint path, GLenum pname, GLfloat *value) +{ + gl::GetPathParameterfCHROMIUM(path, pname, value); +} + +void GL_APIENTRY glGetPathParameterivCHROMIUM(GLuint path, GLenum pname, GLint *value) +{ + gl::GetPathParameteriCHROMIUM(path, pname, value); +} + +void GL_APIENTRY glPathStencilFuncCHROMIUM(GLenum func, GLint ref, GLuint mask) +{ + gl::PathStencilFuncCHROMIUM(func, ref, mask); +} + +void GL_APIENTRY glStencilFillPathCHROMIUM(GLuint path, GLenum fillMode, GLuint mask) +{ + gl::StencilFillPathCHROMIUM(path, fillMode, mask); +} + +void GL_APIENTRY glStencilStrokePathCHROMIUM(GLuint path, GLint reference, GLuint mask) +{ + gl::StencilStrokePathCHROMIUM(path, reference, mask); +} + +void GL_APIENTRY glCoverFillPathCHROMIUM(GLuint path, GLenum coverMode) +{ + gl::CoverFillPathCHROMIUM(path, coverMode); +} + +void GL_APIENTRY glCoverStrokePathCHROMIUM(GLuint path, GLenum coverMode) +{ + gl::CoverStrokePathCHROMIUM(path, coverMode); +} + +void GL_APIENTRY glStencilThenCoverFillPathCHROMIUM(GLuint path, + GLenum fillMode, + GLuint mask, + GLenum coverMode) +{ + gl::StencilThenCoverFillPathCHROMIUM(path, fillMode, mask, coverMode); +} + +void GL_APIENTRY glStencilThenCoverStrokePathCHROMIUM(GLuint path, + GLint reference, + GLuint mask, + GLenum coverMode) +{ + gl::StencilThenCoverStrokePathCHROMIUM(path, reference, mask, coverMode); +} + +void GL_APIENTRY glCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::CoverFillPathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, coverMode, + transformType, transformValues); +} + +void GL_APIENTRY glCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::CoverStrokePathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, coverMode, + transformType, transformValues); +} + +void GL_APIENTRY glStencilFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::StencilFillPathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, fillMode, mask, + transformType, transformValues); +} + +void GL_APIENTRY glStencilStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::StencilStrokePathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, reference, mask, + transformType, transformValues); +} + +void GL_APIENTRY glStencilThenCoverFillPathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::StencilThenCoverFillPathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, fillMode, + mask, coverMode, transformType, transformValues); +} + +void GL_APIENTRY glStencilThenCoverStrokePathInstancedCHROMIUM(GLsizei numPaths, + GLenum pathNameType, + const void *paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat *transformValues) +{ + gl::StencilThenCoverStrokePathInstancedCHROMIUM(numPaths, pathNameType, paths, pathBase, + reference, mask, coverMode, transformType, + transformValues); +} + +void GL_APIENTRY glBindFragmentInputLocationCHROMIUM(GLuint program, + GLint location, + const GLchar *name) +{ + gl::BindFragmentInputLocationCHROMIUM(program, location, name); +} + +void GL_APIENTRY glProgramPathFragmentInputGenCHROMIUM(GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat *coeffs) +{ + gl::ProgramPathFragmentInputGenCHROMIUM(program, location, genMode, components, coeffs); +} + +// GLES 3.1 +void GL_APIENTRY glDispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) +{ + gl::DispatchCompute(numGroupsX, numGroupsY, numGroupsZ); +} + +void GL_APIENTRY glDispatchComputeIndirect(GLintptr indirect) +{ + gl::DispatchComputeIndirect(indirect); +} + +void GL_APIENTRY glDrawArraysIndirect(GLenum mode, const void *indirect) +{ + gl::DrawArraysIndirect(mode, indirect); +} + +void GL_APIENTRY glDrawElementsIndirect(GLenum mode, GLenum type, const void *indirect) +{ + gl::DrawElementsIndirect(mode, type, indirect); +} + +void GL_APIENTRY glFramebufferParameteri(GLenum target, GLenum pname, GLint param) +{ + gl::FramebufferParameteri(target, pname, param); +} + +void GL_APIENTRY glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ + gl::GetFramebufferParameteriv(target, pname, params); +} + +void GL_APIENTRY glGetProgramInterfaceiv(GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + gl::GetProgramInterfaceiv(program, programInterface, pname, params); +} + +GLuint GL_APIENTRY glGetProgramResourceIndex(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + return gl::GetProgramResourceIndex(program, programInterface, name); +} + +void GL_APIENTRY glGetProgramResourceName(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + gl::GetProgramResourceName(program, programInterface, index, bufSize, length, name); +} + +void GL_APIENTRY glGetProgramResourceiv(GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + gl::GetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, + params); +} + +GLint GL_APIENTRY glGetProgramResourceLocation(GLuint program, + GLenum programInterface, + const GLchar *name) +{ + return gl::GetProgramResourceLocation(program, programInterface, name); +} + +void GL_APIENTRY glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) +{ + gl::UseProgramStages(pipeline, stages, program); +} + +void GL_APIENTRY glActiveShaderProgram(GLuint pipeline, GLuint program) +{ + gl::ActiveShaderProgram(pipeline, program); +} + +GLuint GL_APIENTRY glCreateShaderProgramv(GLenum type, GLsizei count, const GLchar *const *strings) +{ + return gl::CreateShaderProgramv(type, count, strings); +} + +void GL_APIENTRY glBindProgramPipeline(GLuint pipeline) +{ + gl::BindProgramPipeline(pipeline); +} + +void GL_APIENTRY glDeleteProgramPipelines(GLsizei n, const GLuint *pipelines) +{ + gl::DeleteProgramPipelines(n, pipelines); +} + +void GL_APIENTRY glGenProgramPipelines(GLsizei n, GLuint *pipelines) +{ + gl::GenProgramPipelines(n, pipelines); +} + +GLboolean GL_APIENTRY glIsProgramPipeline(GLuint pipeline) +{ + return gl::IsProgramPipeline(pipeline); +} + +void GL_APIENTRY glGetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params) +{ + gl::GetProgramPipelineiv(pipeline, pname, params); +} + +void GL_APIENTRY glProgramUniform1i(GLuint program, GLint location, GLint v0) +{ + gl::ProgramUniform1i(program, location, v0); +} + +void GL_APIENTRY glProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1) +{ + gl::ProgramUniform2i(program, location, v0, v1); } + +void GL_APIENTRY glProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +{ + gl::ProgramUniform3i(program, location, v0, v1, v2); +} + +void GL_APIENTRY +glProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + gl::ProgramUniform4i(program, location, v0, v1, v2, v3); +} + +void GL_APIENTRY glProgramUniform1ui(GLuint program, GLint location, GLuint v0) +{ + gl::ProgramUniform1ui(program, location, v0); +} + +void GL_APIENTRY glProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1) +{ + gl::ProgramUniform2ui(program, location, v0, v1); +} + +void GL_APIENTRY +glProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + gl::ProgramUniform3ui(program, location, v0, v1, v2); +} + +void GL_APIENTRY +glProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + gl::ProgramUniform4ui(program, location, v0, v1, v2, v3); +} + +void GL_APIENTRY glProgramUniform1f(GLuint program, GLint location, GLfloat v0) +{ + gl::ProgramUniform1f(program, location, v0); +} + +void GL_APIENTRY glProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1) +{ + gl::ProgramUniform2f(program, location, v0, v1); +} + +void GL_APIENTRY +glProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + gl::ProgramUniform3f(program, location, v0, v1, v2); +} + +void GL_APIENTRY +glProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + gl::ProgramUniform4f(program, location, v0, v1, v2, v3); +} + +void GL_APIENTRY glProgramUniform1iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + gl::ProgramUniform1iv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform2iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + gl::ProgramUniform2iv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform3iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + gl::ProgramUniform3iv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform4iv(GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + gl::ProgramUniform4iv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform1uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + gl::ProgramUniform1uiv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform2uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + gl::ProgramUniform2uiv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform3uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + gl::ProgramUniform3uiv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform4uiv(GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + gl::ProgramUniform4uiv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform1fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + gl::ProgramUniform1fv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform2fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + gl::ProgramUniform2fv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform3fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + gl::ProgramUniform3fv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniform4fv(GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + gl::ProgramUniform4fv(program, location, count, value); +} + +void GL_APIENTRY glProgramUniformMatrix2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix2fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix3fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix4fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix2x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix2x3fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix3x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix3x2fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix2x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix2x4fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix4x2fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix4x2fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix3x4fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix3x4fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glProgramUniformMatrix4x3fv(GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + gl::ProgramUniformMatrix4x3fv(program, location, count, transpose, value); +} + +void GL_APIENTRY glValidateProgramPipeline(GLuint pipeline) +{ + gl::ValidateProgramPipeline(pipeline); +} + +void GL_APIENTRY glGetProgramPipelineInfoLog(GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + gl::GetProgramPipelineInfoLog(pipeline, bufSize, length, infoLog); +} + +void GL_APIENTRY glBindImageTexture(GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + gl::BindImageTexture(unit, texture, level, layered, layer, access, format); +} + +void GL_APIENTRY glGetBooleani_v(GLenum target, GLuint index, GLboolean *data) +{ + gl::GetBooleani_v(target, index, data); +} + +void GL_APIENTRY glMemoryBarrier(GLbitfield barriers) +{ + gl::MemoryBarrier(barriers); +} + +void GL_APIENTRY glMemoryBarrierByRegion(GLbitfield barriers) +{ + gl::MemoryBarrierByRegion(barriers); +} + +void GL_APIENTRY glTexStorage2DMultisample(GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations) +{ + gl::TexStorage2DMultisample(target, samples, internalformat, width, height, + fixedsamplelocations); +} + +void GL_APIENTRY glGetMultisamplefv(GLenum pname, GLuint index, GLfloat *val) +{ + gl::GetMultisamplefv(pname, index, val); +} + +void GL_APIENTRY glSampleMaski(GLuint maskNumber, GLbitfield mask) +{ + gl::SampleMaski(maskNumber, mask); +} + +void GL_APIENTRY glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + gl::GetTexLevelParameteriv(target, level, pname, params); +} + +void GL_APIENTRY glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + gl::GetTexLevelParameterfv(target, level, pname, params); +} + +void GL_APIENTRY glBindVertexBuffer(GLuint bindingindex, + GLuint buffer, + GLintptr offset, + GLsizei stride) +{ + gl::BindVertexBuffer(bindingindex, buffer, offset, stride); +} + +void GL_APIENTRY glVertexAttribFormat(GLuint attribindex, + GLint size, + GLenum type, + GLboolean normalized, + GLuint relativeoffset) +{ + gl::VertexAttribFormat(attribindex, size, type, normalized, relativeoffset); +} + +void GL_APIENTRY glVertexAttribIFormat(GLuint attribindex, + GLint size, + GLenum type, + GLuint relativeoffset) +{ + gl::VertexAttribIFormat(attribindex, size, type, relativeoffset); +} + +void GL_APIENTRY glVertexAttribBinding(GLuint attribindex, GLuint bindingindex) +{ + gl::VertexAttribBinding(attribindex, bindingindex); +} + +void GL_APIENTRY glVertexBindingDivisor(GLuint bindingindex, GLuint divisor) +{ + gl::VertexBindingDivisor(bindingindex, divisor); +} + +void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLint baseViewIndex, + GLsizei numViews) +{ + gl::FramebufferTextureMultiviewLayeredANGLE(target, attachment, texture, level, baseViewIndex, + numViews); +} + +void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLE(GLenum target, + GLenum attachment, + GLuint texture, + GLint level, + GLsizei numViews, + const GLint *viewportOffsets) +{ + gl::FramebufferTextureMultiviewSideBySideANGLE(target, attachment, texture, level, numViews, + viewportOffsets); +} + +void GL_APIENTRY glRequestExtensionANGLE(const GLchar *name) +{ + gl::RequestExtensionANGLE(name); +} + +} // extern "C" diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def index 0aebb6c864..2ff4cc0579 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -202,6 +202,38 @@ EXPORTS glGetQueryObjectivEXT @315 glGetQueryObjecti64vEXT @316 glGetQueryObjectui64vEXT @317 + glBindUniformLocationCHROMIUM @318 + glCoverageModulationCHROMIUM @319 + + glMatrixLoadfCHROMIUM @320 + glMatrixLoadIdentityCHROMIUM @321 + glGenPathsCHROMIUM @322 + glDeletePathsCHROMIUM @323 + glIsPathCHROMIUM @324 + glPathCommandsCHROMIUM @325 + glPathParameterfCHROMIUM @326 + glPathParameteriCHROMIUM @327 + glGetPathParameterfvCHROMIUM @328 + glGetPathParameterivCHROMIUM @329 + glPathStencilFuncCHROMIUM @330 + glStencilFillPathCHROMIUM @331 + glStencilStrokePathCHROMIUM @332 + glCoverFillPathCHROMIUM @333 + glCoverStrokePathCHROMIUM @334 + glStencilThenCoverFillPathCHROMIUM @335 + glStencilThenCoverStrokePathCHROMIUM @336 + glCoverFillPathInstancedCHROMIUM @337 + glCoverStrokePathInstancedCHROMIUM @338 + glStencilStrokePathInstancedCHROMIUM @339 + glStencilFillPathInstancedCHROMIUM @340 + glStencilThenCoverFillPathInstancedCHROMIUM @341 + glStencilThenCoverStrokePathInstancedCHROMIUM @342 + glBindFragmentInputLocationCHROMIUM @343 + glProgramPathFragmentInputGenCHROMIUM @344 + + glFramebufferTextureMultiviewLayeredANGLE @413 + glFramebufferTextureMultiviewSideBySideANGLE @414 + glRequestExtensionANGLE @415 ; GLES 3.0 Functions glReadBuffer @180 @@ -309,7 +341,72 @@ EXPORTS glTexStorage3D @282 glGetInternalformativ @283 - ; ANGLE Platform Implementation - ANGLEPlatformCurrent @290 - ANGLEPlatformInitialize @291 - ANGLEPlatformShutdown @292 + ; GLES 3.1 Functions + glDispatchCompute @345 + glDispatchComputeIndirect @346 + glDrawArraysIndirect @347 + glDrawElementsIndirect @348 + glFramebufferParameteri @349 + glGetFramebufferParameteriv @350 + glGetProgramInterfaceiv @351 + glGetProgramResourceIndex @352 + glGetProgramResourceName @353 + glGetProgramResourceiv @354 + glGetProgramResourceLocation @355 + glUseProgramStages @356 + glActiveShaderProgram @357 + glCreateShaderProgramv @358 + glBindProgramPipeline @359 + glDeleteProgramPipelines @360 + glGenProgramPipelines @361 + glIsProgramPipeline @362 + glGetProgramPipelineiv @363 + glProgramUniform1i @364 + glProgramUniform2i @365 + glProgramUniform3i @366 + glProgramUniform4i @367 + glProgramUniform1ui @368 + glProgramUniform2ui @369 + glProgramUniform3ui @370 + glProgramUniform4ui @371 + glProgramUniform1f @372 + glProgramUniform2f @373 + glProgramUniform3f @374 + glProgramUniform4f @375 + glProgramUniform1iv @376 + glProgramUniform2iv @377 + glProgramUniform3iv @378 + glProgramUniform4iv @379 + glProgramUniform1uiv @380 + glProgramUniform2uiv @381 + glProgramUniform3uiv @382 + glProgramUniform4uiv @383 + glProgramUniform1fv @384 + glProgramUniform2fv @385 + glProgramUniform3fv @386 + glProgramUniform4fv @387 + glProgramUniformMatrix2fv @388 + glProgramUniformMatrix3fv @389 + glProgramUniformMatrix4fv @390 + glProgramUniformMatrix2x3fv @391 + glProgramUniformMatrix3x2fv @392 + glProgramUniformMatrix2x4fv @393 + glProgramUniformMatrix4x2fv @394 + glProgramUniformMatrix3x4fv @395 + glProgramUniformMatrix4x3fv @396 + glValidateProgramPipeline @397 + glGetProgramPipelineInfoLog @398 + glBindImageTexture @399 + glGetBooleani_v @400 + glMemoryBarrier @401 + glMemoryBarrierByRegion @402 + glTexStorage2DMultisample @403 + glGetMultisamplefv @404 + glSampleMaski @405 + glGetTexLevelParameteriv @406 + glGetTexLevelParameterfv @407 + glBindVertexBuffer @408 + glVertexAttribFormat @409 + glVertexAttribIFormat @410 + glVertexAttribBinding @411 + glVertexBindingDivisor @412 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def index db17bb487b..2ff4cc0579 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def @@ -1,316 +1,412 @@ LIBRARY libGLESv2 EXPORTS - glActiveTexture@4 @1 - glAttachShader@8 @2 - glBindAttribLocation@12 @3 - glBindBuffer@8 @4 - glBindFramebuffer@8 @5 - glBindRenderbuffer@8 @6 - glBindTexture@8 @7 - glBlendColor@16 @8 - glBlendEquation@4 @9 - glBlendEquationSeparate@8 @10 - glBlendFunc@8 @11 - glBlendFuncSeparate@16 @12 - glBufferData@16 @13 - glBufferSubData@16 @14 - glCheckFramebufferStatus@4 @15 - glClear@4 @16 - glClearColor@16 @17 - glClearDepthf@4 @18 - glClearStencil@4 @19 - glColorMask@16 @20 - glCompileShader@4 @21 - glCompressedTexImage2D@32 @22 - glCompressedTexSubImage2D@36 @23 - glCopyTexImage2D@32 @24 - glCopyTexSubImage2D@32 @25 - glCreateProgram@0 @26 - glCreateShader@4 @27 - glCullFace@4 @28 - glDeleteBuffers@8 @29 - glDeleteFramebuffers@8 @30 - glDeleteProgram@4 @32 - glDeleteRenderbuffers@8 @33 - glDeleteShader@4 @34 - glDeleteTextures@8 @31 - glDepthFunc@4 @36 - glDepthMask@4 @37 - glDepthRangef@8 @38 - glDetachShader@8 @35 - glDisable@4 @39 - glDisableVertexAttribArray@4 @40 - glDrawArrays@12 @41 - glDrawElements@16 @42 - glEnable@4 @43 - glEnableVertexAttribArray@4 @44 - glFinish@0 @45 - glFlush@0 @46 - glFramebufferRenderbuffer@16 @47 - glFramebufferTexture2D@20 @48 - glFrontFace@4 @49 - glGenBuffers@8 @50 - glGenFramebuffers@8 @52 - glGenRenderbuffers@8 @53 - glGenTextures@8 @54 - glGenerateMipmap@4 @51 - glGetActiveAttrib@28 @55 - glGetActiveUniform@28 @56 - glGetAttachedShaders@16 @57 - glGetAttribLocation@8 @58 - glGetBooleanv@8 @59 - glGetBufferParameteriv@12 @60 - glGetError@0 @61 - glGetFloatv@8 @62 - glGetFramebufferAttachmentParameteriv@16 @63 - glGetIntegerv@8 @64 - glGetProgramInfoLog@16 @66 - glGetProgramiv@12 @65 - glGetRenderbufferParameteriv@12 @67 - glGetShaderInfoLog@16 @69 - glGetShaderPrecisionFormat@16 @70 - glGetShaderSource@16 @71 - glGetShaderiv@12 @68 - glGetString@4 @72 - glGetTexParameterfv@12 @73 - glGetTexParameteriv@12 @74 - glGetUniformLocation@8 @77 - glGetUniformfv@12 @75 - glGetUniformiv@12 @76 - glGetVertexAttribPointerv@12 @80 - glGetVertexAttribfv@12 @78 - glGetVertexAttribiv@12 @79 - glHint@8 @81 - glIsBuffer@4 @82 - glIsEnabled@4 @83 - glIsFramebuffer@4 @84 - glIsProgram@4 @85 - glIsRenderbuffer@4 @86 - glIsShader@4 @87 - glIsTexture@4 @88 - glLineWidth@4 @89 - glLinkProgram@4 @90 - glPixelStorei@8 @91 - glPolygonOffset@8 @92 - glReadPixels@28 @93 - glReleaseShaderCompiler@0 @94 - glRenderbufferStorage@16 @95 - glSampleCoverage@8 @96 - glScissor@16 @97 - glShaderBinary@20 @98 - glShaderSource@16 @99 - glStencilFunc@12 @100 - glStencilFuncSeparate@16 @101 - glStencilMask@4 @102 - glStencilMaskSeparate@8 @103 - glStencilOp@12 @104 - glStencilOpSeparate@16 @105 - glTexImage2D@36 @106 - glTexParameterf@12 @107 - glTexParameterfv@12 @108 - glTexParameteri@12 @109 - glTexParameteriv@12 @110 - glTexSubImage2D@36 @111 - glUniform1f@8 @112 - glUniform1fv@12 @113 - glUniform1i@8 @114 - glUniform1iv@12 @115 - glUniform2f@12 @116 - glUniform2fv@12 @117 - glUniform2i@12 @118 - glUniform2iv@12 @119 - glUniform3f@16 @120 - glUniform3fv@12 @121 - glUniform3i@16 @122 - glUniform3iv@12 @123 - glUniform4f@20 @124 - glUniform4fv@12 @125 - glUniform4i@20 @126 - glUniform4iv@12 @127 - glUniformMatrix2fv@16 @128 - glUniformMatrix3fv@16 @129 - glUniformMatrix4fv@16 @130 - glUseProgram@4 @131 - glValidateProgram@4 @132 - glVertexAttrib1f@8 @133 - glVertexAttrib1fv@8 @134 - glVertexAttrib2f@12 @135 - glVertexAttrib2fv@8 @136 - glVertexAttrib3f@16 @137 - glVertexAttrib3fv@8 @138 - glVertexAttrib4f@20 @139 - glVertexAttrib4fv@8 @140 - glVertexAttribPointer@24 @141 - glViewport@16 @142 + glActiveTexture @1 + glAttachShader @2 + glBindAttribLocation @3 + glBindBuffer @4 + glBindFramebuffer @5 + glBindRenderbuffer @6 + glBindTexture @7 + glBlendColor @8 + glBlendEquation @9 + glBlendEquationSeparate @10 + glBlendFunc @11 + glBlendFuncSeparate @12 + glBufferData @13 + glBufferSubData @14 + glCheckFramebufferStatus @15 + glClear @16 + glClearColor @17 + glClearDepthf @18 + glClearStencil @19 + glColorMask @20 + glCompileShader @21 + glCompressedTexImage2D @22 + glCompressedTexSubImage2D @23 + glCopyTexImage2D @24 + glCopyTexSubImage2D @25 + glCreateProgram @26 + glCreateShader @27 + glCullFace @28 + glDeleteBuffers @29 + glDeleteFramebuffers @30 + glDeleteProgram @32 + glDeleteRenderbuffers @33 + glDeleteShader @34 + glDeleteTextures @31 + glDepthFunc @36 + glDepthMask @37 + glDepthRangef @38 + glDetachShader @35 + glDisable @39 + glDisableVertexAttribArray @40 + glDrawArrays @41 + glDrawElements @42 + glEnable @43 + glEnableVertexAttribArray @44 + glFinish @45 + glFlush @46 + glFramebufferRenderbuffer @47 + glFramebufferTexture2D @48 + glFrontFace @49 + glGenBuffers @50 + glGenFramebuffers @52 + glGenRenderbuffers @53 + glGenTextures @54 + glGenerateMipmap @51 + glGetActiveAttrib @55 + glGetActiveUniform @56 + glGetAttachedShaders @57 + glGetAttribLocation @58 + glGetBooleanv @59 + glGetBufferParameteriv @60 + glGetError @61 + glGetFloatv @62 + glGetFramebufferAttachmentParameteriv @63 + glGetIntegerv @64 + glGetProgramInfoLog @66 + glGetProgramiv @65 + glGetRenderbufferParameteriv @67 + glGetShaderInfoLog @69 + glGetShaderPrecisionFormat @70 + glGetShaderSource @71 + glGetShaderiv @68 + glGetString @72 + glGetTexParameterfv @73 + glGetTexParameteriv @74 + glGetUniformLocation @77 + glGetUniformfv @75 + glGetUniformiv @76 + glGetVertexAttribPointerv @80 + glGetVertexAttribfv @78 + glGetVertexAttribiv @79 + glHint @81 + glIsBuffer @82 + glIsEnabled @83 + glIsFramebuffer @84 + glIsProgram @85 + glIsRenderbuffer @86 + glIsShader @87 + glIsTexture @88 + glLineWidth @89 + glLinkProgram @90 + glPixelStorei @91 + glPolygonOffset @92 + glReadPixels @93 + glReleaseShaderCompiler @94 + glRenderbufferStorage @95 + glSampleCoverage @96 + glScissor @97 + glShaderBinary @98 + glShaderSource @99 + glStencilFunc @100 + glStencilFuncSeparate @101 + glStencilMask @102 + glStencilMaskSeparate @103 + glStencilOp @104 + glStencilOpSeparate @105 + glTexImage2D @106 + glTexParameterf @107 + glTexParameterfv @108 + glTexParameteri @109 + glTexParameteriv @110 + glTexSubImage2D @111 + glUniform1f @112 + glUniform1fv @113 + glUniform1i @114 + glUniform1iv @115 + glUniform2f @116 + glUniform2fv @117 + glUniform2i @118 + glUniform2iv @119 + glUniform3f @120 + glUniform3fv @121 + glUniform3i @122 + glUniform3iv @123 + glUniform4f @124 + glUniform4fv @125 + glUniform4i @126 + glUniform4iv @127 + glUniformMatrix2fv @128 + glUniformMatrix3fv @129 + glUniformMatrix4fv @130 + glUseProgram @131 + glValidateProgram @132 + glVertexAttrib1f @133 + glVertexAttrib1fv @134 + glVertexAttrib2f @135 + glVertexAttrib2fv @136 + glVertexAttrib3f @137 + glVertexAttrib3fv @138 + glVertexAttrib4f @139 + glVertexAttrib4fv @140 + glVertexAttribPointer @141 + glViewport @142 ; Extensions - glBlitFramebufferANGLE@40 @149 - glRenderbufferStorageMultisampleANGLE@20 @150 - glDeleteFencesNV@8 @151 - glFinishFenceNV@4 @152 - glGenFencesNV@8 @153 - glGetFenceivNV@12 @154 - glIsFenceNV@4 @155 - glSetFenceNV@8 @156 - glTestFenceNV@4 @157 - glGetTranslatedShaderSourceANGLE@16 @159 - glTexStorage2DEXT@20 @160 - glGetGraphicsResetStatusEXT@0 @161 - glReadnPixelsEXT@32 @162 - glGetnUniformfvEXT@16 @163 - glGetnUniformivEXT@16 @164 - glGenQueriesEXT@8 @165 - glDeleteQueriesEXT@8 @166 - glIsQueryEXT@4 @167 - glBeginQueryEXT@8 @168 - glEndQueryEXT@4 @169 - glGetQueryivEXT@12 @170 - glGetQueryObjectuivEXT@12 @171 - glVertexAttribDivisorANGLE@8 @172 - glDrawArraysInstancedANGLE@16 @173 - glDrawElementsInstancedANGLE@20 @174 - glProgramBinaryOES@16 @175 - glGetProgramBinaryOES@20 @176 - glDrawBuffersEXT@8 @179 - glMapBufferOES@8 @285 - glUnmapBufferOES@4 @286 - 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 + glBlitFramebufferANGLE @149 + glRenderbufferStorageMultisampleANGLE @150 + glDeleteFencesNV @151 + glFinishFenceNV @152 + glGenFencesNV @153 + glGetFenceivNV @154 + glIsFenceNV @155 + glSetFenceNV @156 + glTestFenceNV @157 + glGetTranslatedShaderSourceANGLE @159 + glTexStorage2DEXT @160 + glGetGraphicsResetStatusEXT @161 + glReadnPixelsEXT @162 + glGetnUniformfvEXT @163 + glGetnUniformivEXT @164 + glGenQueriesEXT @165 + glDeleteQueriesEXT @166 + glIsQueryEXT @167 + glBeginQueryEXT @168 + glEndQueryEXT @169 + glGetQueryivEXT @170 + glGetQueryObjectuivEXT @171 + glVertexAttribDivisorANGLE @172 + glDrawArraysInstancedANGLE @173 + glDrawElementsInstancedANGLE @174 + glProgramBinaryOES @175 + glGetProgramBinaryOES @176 + glDrawBuffersEXT @179 + glMapBufferOES @285 + glUnmapBufferOES @286 + 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 + glBindUniformLocationCHROMIUM @318 + glCoverageModulationCHROMIUM @319 + + glMatrixLoadfCHROMIUM @320 + glMatrixLoadIdentityCHROMIUM @321 + glGenPathsCHROMIUM @322 + glDeletePathsCHROMIUM @323 + glIsPathCHROMIUM @324 + glPathCommandsCHROMIUM @325 + glPathParameterfCHROMIUM @326 + glPathParameteriCHROMIUM @327 + glGetPathParameterfvCHROMIUM @328 + glGetPathParameterivCHROMIUM @329 + glPathStencilFuncCHROMIUM @330 + glStencilFillPathCHROMIUM @331 + glStencilStrokePathCHROMIUM @332 + glCoverFillPathCHROMIUM @333 + glCoverStrokePathCHROMIUM @334 + glStencilThenCoverFillPathCHROMIUM @335 + glStencilThenCoverStrokePathCHROMIUM @336 + glCoverFillPathInstancedCHROMIUM @337 + glCoverStrokePathInstancedCHROMIUM @338 + glStencilStrokePathInstancedCHROMIUM @339 + glStencilFillPathInstancedCHROMIUM @340 + glStencilThenCoverFillPathInstancedCHROMIUM @341 + glStencilThenCoverStrokePathInstancedCHROMIUM @342 + glBindFragmentInputLocationCHROMIUM @343 + glProgramPathFragmentInputGenCHROMIUM @344 + + glFramebufferTextureMultiviewLayeredANGLE @413 + glFramebufferTextureMultiviewSideBySideANGLE @414 + glRequestExtensionANGLE @415 ; GLES 3.0 Functions - glReadBuffer@4 @180 - glDrawRangeElements@24 @181 - glTexImage3D@40 @182 - glTexSubImage3D@44 @183 - glCopyTexSubImage3D@36 @184 - glCompressedTexImage3D@36 @185 - glCompressedTexSubImage3D@44 @186 - glGenQueries@8 @187 - glDeleteQueries@8 @188 - glIsQuery@4 @189 - glBeginQuery@8 @190 - glEndQuery@4 @191 - glGetQueryiv@12 @192 - glGetQueryObjectuiv@12 @193 - glUnmapBuffer@4 @194 - glGetBufferPointerv@12 @195 - glDrawBuffers@8 @196 - glUniformMatrix2x3fv@16 @197 - glUniformMatrix3x2fv@16 @198 - glUniformMatrix2x4fv@16 @199 - glUniformMatrix4x2fv@16 @200 - glUniformMatrix3x4fv@16 @201 - glUniformMatrix4x3fv@16 @202 - glBlitFramebuffer@40 @203 - glRenderbufferStorageMultisample@20 @204 - glFramebufferTextureLayer@20 @205 - glMapBufferRange@16 @206 - glFlushMappedBufferRange@12 @207 - glBindVertexArray@4 @208 - glDeleteVertexArrays@8 @209 - glGenVertexArrays@8 @210 - glIsVertexArray@4 @211 - glGetIntegeri_v@12 @212 - glBeginTransformFeedback@4 @213 - glEndTransformFeedback@0 @214 - glBindBufferRange@20 @215 - glBindBufferBase@12 @216 - glTransformFeedbackVaryings@16 @217 - glGetTransformFeedbackVarying@28 @218 - glVertexAttribIPointer@20 @219 - glGetVertexAttribIiv@12 @220 - glGetVertexAttribIuiv@12 @221 - glVertexAttribI4i@20 @222 - glVertexAttribI4ui@20 @223 - glVertexAttribI4iv@8 @224 - glVertexAttribI4uiv@8 @225 - glGetUniformuiv@12 @226 - glGetFragDataLocation@8 @227 - glUniform1ui@8 @228 - glUniform2ui@12 @229 - glUniform3ui@16 @230 - glUniform4ui@20 @231 - glUniform1uiv@12 @232 - glUniform2uiv@12 @233 - glUniform3uiv@12 @234 - glUniform4uiv@12 @235 - glClearBufferiv@12 @236 - glClearBufferuiv@12 @237 - glClearBufferfv@12 @238 - glClearBufferfi@16 @239 - glGetStringi@8 @240 - glCopyBufferSubData@20 @241 - glGetUniformIndices@16 @242 - glGetActiveUniformsiv@20 @243 - glGetUniformBlockIndex@8 @244 - glGetActiveUniformBlockiv@16 @245 - glGetActiveUniformBlockName@20 @246 - glUniformBlockBinding@12 @247 - glDrawArraysInstanced@16 @248 - glDrawElementsInstanced@20 @249 - glFenceSync@8 @250 - glIsSync@4 @251 - glDeleteSync@4 @252 - glClientWaitSync@16 @253 - glWaitSync@16 @254 - glGetInteger64v@8 @255 - glGetSynciv@20 @256 - glGetInteger64i_v@12 @257 - glGetBufferParameteri64v@12 @258 - glGenSamplers@8 @259 - glDeleteSamplers@8 @260 - glIsSampler@4 @261 - glBindSampler@8 @262 - glSamplerParameteri@12 @263 - glSamplerParameteriv@12 @264 - glSamplerParameterf@12 @265 - glSamplerParameterfv@12 @266 - glGetSamplerParameteriv@12 @267 - glGetSamplerParameterfv@12 @268 - glVertexAttribDivisor@8 @269 - glBindTransformFeedback@8 @270 - glDeleteTransformFeedbacks@8 @271 - glGenTransformFeedbacks@8 @272 - glIsTransformFeedback@4 @273 - glPauseTransformFeedback@0 @274 - glResumeTransformFeedback@0 @275 - glGetProgramBinary@20 @276 - glProgramBinary@16 @277 - glProgramParameteri@12 @278 - glInvalidateFramebuffer@12 @279 - glInvalidateSubFramebuffer@28 @280 - glTexStorage2D@20 @281 - glTexStorage3D@24 @282 - glGetInternalformativ@20 @283 + glReadBuffer @180 + glDrawRangeElements @181 + glTexImage3D @182 + glTexSubImage3D @183 + glCopyTexSubImage3D @184 + glCompressedTexImage3D @185 + glCompressedTexSubImage3D @186 + glGenQueries @187 + glDeleteQueries @188 + glIsQuery @189 + glBeginQuery @190 + glEndQuery @191 + glGetQueryiv @192 + glGetQueryObjectuiv @193 + glUnmapBuffer @194 + glGetBufferPointerv @195 + glDrawBuffers @196 + glUniformMatrix2x3fv @197 + glUniformMatrix3x2fv @198 + glUniformMatrix2x4fv @199 + glUniformMatrix4x2fv @200 + glUniformMatrix3x4fv @201 + glUniformMatrix4x3fv @202 + glBlitFramebuffer @203 + glRenderbufferStorageMultisample @204 + glFramebufferTextureLayer @205 + glMapBufferRange @206 + glFlushMappedBufferRange @207 + glBindVertexArray @208 + glDeleteVertexArrays @209 + glGenVertexArrays @210 + glIsVertexArray @211 + glGetIntegeri_v @212 + glBeginTransformFeedback @213 + glEndTransformFeedback @214 + glBindBufferRange @215 + glBindBufferBase @216 + glTransformFeedbackVaryings @217 + glGetTransformFeedbackVarying @218 + glVertexAttribIPointer @219 + glGetVertexAttribIiv @220 + glGetVertexAttribIuiv @221 + glVertexAttribI4i @222 + glVertexAttribI4ui @223 + glVertexAttribI4iv @224 + glVertexAttribI4uiv @225 + glGetUniformuiv @226 + glGetFragDataLocation @227 + glUniform1ui @228 + glUniform2ui @229 + glUniform3ui @230 + glUniform4ui @231 + glUniform1uiv @232 + glUniform2uiv @233 + glUniform3uiv @234 + glUniform4uiv @235 + glClearBufferiv @236 + glClearBufferuiv @237 + glClearBufferfv @238 + glClearBufferfi @239 + glGetStringi @240 + glCopyBufferSubData @241 + glGetUniformIndices @242 + glGetActiveUniformsiv @243 + glGetUniformBlockIndex @244 + glGetActiveUniformBlockiv @245 + glGetActiveUniformBlockName @246 + glUniformBlockBinding @247 + glDrawArraysInstanced @248 + glDrawElementsInstanced @249 + glFenceSync @250 + glIsSync @251 + glDeleteSync @252 + glClientWaitSync @253 + glWaitSync @254 + glGetInteger64v @255 + glGetSynciv @256 + glGetInteger64i_v @257 + glGetBufferParameteri64v @258 + glGenSamplers @259 + glDeleteSamplers @260 + glIsSampler @261 + glBindSampler @262 + glSamplerParameteri @263 + glSamplerParameteriv @264 + glSamplerParameterf @265 + glSamplerParameterfv @266 + glGetSamplerParameteriv @267 + glGetSamplerParameterfv @268 + glVertexAttribDivisor @269 + glBindTransformFeedback @270 + glDeleteTransformFeedbacks @271 + glGenTransformFeedbacks @272 + glIsTransformFeedback @273 + glPauseTransformFeedback @274 + glResumeTransformFeedback @275 + glGetProgramBinary @276 + glProgramBinary @277 + glProgramParameteri @278 + glInvalidateFramebuffer @279 + glInvalidateSubFramebuffer @280 + glTexStorage2D @281 + glTexStorage3D @282 + glGetInternalformativ @283 - ; ANGLE Platform Implementation - ANGLEPlatformCurrent@0 @290 - ANGLEPlatformInitialize@4 @291 - ANGLEPlatformShutdown@0 @292 - \ No newline at end of file + ; GLES 3.1 Functions + glDispatchCompute @345 + glDispatchComputeIndirect @346 + glDrawArraysIndirect @347 + glDrawElementsIndirect @348 + glFramebufferParameteri @349 + glGetFramebufferParameteriv @350 + glGetProgramInterfaceiv @351 + glGetProgramResourceIndex @352 + glGetProgramResourceName @353 + glGetProgramResourceiv @354 + glGetProgramResourceLocation @355 + glUseProgramStages @356 + glActiveShaderProgram @357 + glCreateShaderProgramv @358 + glBindProgramPipeline @359 + glDeleteProgramPipelines @360 + glGenProgramPipelines @361 + glIsProgramPipeline @362 + glGetProgramPipelineiv @363 + glProgramUniform1i @364 + glProgramUniform2i @365 + glProgramUniform3i @366 + glProgramUniform4i @367 + glProgramUniform1ui @368 + glProgramUniform2ui @369 + glProgramUniform3ui @370 + glProgramUniform4ui @371 + glProgramUniform1f @372 + glProgramUniform2f @373 + glProgramUniform3f @374 + glProgramUniform4f @375 + glProgramUniform1iv @376 + glProgramUniform2iv @377 + glProgramUniform3iv @378 + glProgramUniform4iv @379 + glProgramUniform1uiv @380 + glProgramUniform2uiv @381 + glProgramUniform3uiv @382 + glProgramUniform4uiv @383 + glProgramUniform1fv @384 + glProgramUniform2fv @385 + glProgramUniform3fv @386 + glProgramUniform4fv @387 + glProgramUniformMatrix2fv @388 + glProgramUniformMatrix3fv @389 + glProgramUniformMatrix4fv @390 + glProgramUniformMatrix2x3fv @391 + glProgramUniformMatrix3x2fv @392 + glProgramUniformMatrix2x4fv @393 + glProgramUniformMatrix4x2fv @394 + glProgramUniformMatrix3x4fv @395 + glProgramUniformMatrix4x3fv @396 + glValidateProgramPipeline @397 + glGetProgramPipelineInfoLog @398 + glBindImageTexture @399 + glGetBooleani_v @400 + glMemoryBarrier @401 + glMemoryBarrierByRegion @402 + glTexStorage2DMultisample @403 + glGetMultisamplefv @404 + glSampleMaski @405 + glGetTexLevelParameteriv @406 + glGetTexLevelParameterfv @407 + glBindVertexBuffer @408 + glVertexAttribFormat @409 + glVertexAttribIFormat @410 + glVertexAttribBinding @411 + glVertexBindingDivisor @412 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def index e0c3823abf..9a00a9f8ae 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def @@ -202,6 +202,38 @@ EXPORTS glGetQueryObjectivEXT @315 glGetQueryObjecti64vEXT @316 glGetQueryObjectui64vEXT @317 + glBindUniformLocationCHROMIUM @318 + glCoverageModulationCHROMIUM @319 + + glMatrixLoadfCHROMIUM @320 + glMatrixLoadIdentityCHROMIUM @321 + glGenPathsCHROMIUM @322 + glDeletePathsCHROMIUM @323 + glIsPathCHROMIUM @324 + glPathCommandsCHROMIUM @325 + glPathParameterfCHROMIUM @326 + glPathParameteriCHROMIUM @327 + glGetPathParameterfvCHROMIUM @328 + glGetPathParameterivCHROMIUM @329 + glPathStencilFuncCHROMIUM @330 + glStencilFillPathCHROMIUM @331 + glStencilStrokePathCHROMIUM @332 + glCoverFillPathCHROMIUM @333 + glCoverStrokePathCHROMIUM @334 + glStencilThenCoverFillPathCHROMIUM @335 + glStencilThenCoverStrokePathCHROMIUM @336 + glCoverFillPathInstancedCHROMIUM @337 + glCoverStrokePathInstancedCHROMIUM @338 + glStencilStrokePathInstancedCHROMIUM @339 + glStencilFillPathInstancedCHROMIUM @340 + glStencilThenCoverFillPathInstancedCHROMIUM @341 + glStencilThenCoverStrokePathInstancedCHROMIUM @342 + glBindFragmentInputLocationCHROMIUM @343 + glProgramPathFragmentInputGenCHROMIUM @344 + + glFramebufferTextureMultiviewLayeredANGLE @413 + glFramebufferTextureMultiviewSideBySideANGLE @414 + glRequestExtensionANGLE @415 ; GLES 3.0 Functions glReadBuffer @180 @@ -309,7 +341,72 @@ EXPORTS glTexStorage3D @282 glGetInternalformativ @283 - ; ANGLE Platform Implementation - ANGLEPlatformCurrent @290 - ANGLEPlatformInitialize @291 - ANGLEPlatformShutdown @292 + ; GLES 3.1 Functions + glDispatchCompute @345 + glDispatchComputeIndirect @346 + glDrawArraysIndirect @347 + glDrawElementsIndirect @348 + glFramebufferParameteri @349 + glGetFramebufferParameteriv @350 + glGetProgramInterfaceiv @351 + glGetProgramResourceIndex @352 + glGetProgramResourceName @353 + glGetProgramResourceiv @354 + glGetProgramResourceLocation @355 + glUseProgramStages @356 + glActiveShaderProgram @357 + glCreateShaderProgramv @358 + glBindProgramPipeline @359 + glDeleteProgramPipelines @360 + glGenProgramPipelines @361 + glIsProgramPipeline @362 + glGetProgramPipelineiv @363 + glProgramUniform1i @364 + glProgramUniform2i @365 + glProgramUniform3i @366 + glProgramUniform4i @367 + glProgramUniform1ui @368 + glProgramUniform2ui @369 + glProgramUniform3ui @370 + glProgramUniform4ui @371 + glProgramUniform1f @372 + glProgramUniform2f @373 + glProgramUniform3f @374 + glProgramUniform4f @375 + glProgramUniform1iv @376 + glProgramUniform2iv @377 + glProgramUniform3iv @378 + glProgramUniform4iv @379 + glProgramUniform1uiv @380 + glProgramUniform2uiv @381 + glProgramUniform3uiv @382 + glProgramUniform4uiv @383 + glProgramUniform1fv @384 + glProgramUniform2fv @385 + glProgramUniform3fv @386 + glProgramUniform4fv @387 + glProgramUniformMatrix2fv @388 + glProgramUniformMatrix3fv @389 + glProgramUniformMatrix4fv @390 + glProgramUniformMatrix2x3fv @391 + glProgramUniformMatrix3x2fv @392 + glProgramUniformMatrix2x4fv @393 + glProgramUniformMatrix4x2fv @394 + glProgramUniformMatrix3x4fv @395 + glProgramUniformMatrix4x3fv @396 + glValidateProgramPipeline @397 + glGetProgramPipelineInfoLog @398 + glBindImageTexture @399 + glGetBooleani_v @400 + glMemoryBarrier @401 + glMemoryBarrierByRegion @402 + glTexStorage2DMultisample @403 + glGetMultisamplefv @404 + glSampleMaski @405 + glGetTexLevelParameteriv @406 + glGetTexLevelParameterfv @407 + glBindVertexBuffer @408 + glVertexAttribFormat @409 + glVertexAttribIFormat @410 + glVertexAttribBinding @411 + glVertexBindingDivisor @412 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def deleted file mode 100644 index 5a4966f66d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def +++ /dev/null @@ -1,316 +0,0 @@ -LIBRARY libGLESv2d -EXPORTS - glActiveTexture@4 @1 - glAttachShader@8 @2 - glBindAttribLocation@12 @3 - glBindBuffer@8 @4 - glBindFramebuffer@8 @5 - glBindRenderbuffer@8 @6 - glBindTexture@8 @7 - glBlendColor@16 @8 - glBlendEquation@4 @9 - glBlendEquationSeparate@8 @10 - glBlendFunc@8 @11 - glBlendFuncSeparate@16 @12 - glBufferData@16 @13 - glBufferSubData@16 @14 - glCheckFramebufferStatus@4 @15 - glClear@4 @16 - glClearColor@16 @17 - glClearDepthf@4 @18 - glClearStencil@4 @19 - glColorMask@16 @20 - glCompileShader@4 @21 - glCompressedTexImage2D@32 @22 - glCompressedTexSubImage2D@36 @23 - glCopyTexImage2D@32 @24 - glCopyTexSubImage2D@32 @25 - glCreateProgram@0 @26 - glCreateShader@4 @27 - glCullFace@4 @28 - glDeleteBuffers@8 @29 - glDeleteFramebuffers@8 @30 - glDeleteProgram@4 @32 - glDeleteRenderbuffers@8 @33 - glDeleteShader@4 @34 - glDeleteTextures@8 @31 - glDepthFunc@4 @36 - glDepthMask@4 @37 - glDepthRangef@8 @38 - glDetachShader@8 @35 - glDisable@4 @39 - glDisableVertexAttribArray@4 @40 - glDrawArrays@12 @41 - glDrawElements@16 @42 - glEnable@4 @43 - glEnableVertexAttribArray@4 @44 - glFinish@0 @45 - glFlush@0 @46 - glFramebufferRenderbuffer@16 @47 - glFramebufferTexture2D@20 @48 - glFrontFace@4 @49 - glGenBuffers@8 @50 - glGenFramebuffers@8 @52 - glGenRenderbuffers@8 @53 - glGenTextures@8 @54 - glGenerateMipmap@4 @51 - glGetActiveAttrib@28 @55 - glGetActiveUniform@28 @56 - glGetAttachedShaders@16 @57 - glGetAttribLocation@8 @58 - glGetBooleanv@8 @59 - glGetBufferParameteriv@12 @60 - glGetError@0 @61 - glGetFloatv@8 @62 - glGetFramebufferAttachmentParameteriv@16 @63 - glGetIntegerv@8 @64 - glGetProgramInfoLog@16 @66 - glGetProgramiv@12 @65 - glGetRenderbufferParameteriv@12 @67 - glGetShaderInfoLog@16 @69 - glGetShaderPrecisionFormat@16 @70 - glGetShaderSource@16 @71 - glGetShaderiv@12 @68 - glGetString@4 @72 - glGetTexParameterfv@12 @73 - glGetTexParameteriv@12 @74 - glGetUniformLocation@8 @77 - glGetUniformfv@12 @75 - glGetUniformiv@12 @76 - glGetVertexAttribPointerv@12 @80 - glGetVertexAttribfv@12 @78 - glGetVertexAttribiv@12 @79 - glHint@8 @81 - glIsBuffer@4 @82 - glIsEnabled@4 @83 - glIsFramebuffer@4 @84 - glIsProgram@4 @85 - glIsRenderbuffer@4 @86 - glIsShader@4 @87 - glIsTexture@4 @88 - glLineWidth@4 @89 - glLinkProgram@4 @90 - glPixelStorei@8 @91 - glPolygonOffset@8 @92 - glReadPixels@28 @93 - glReleaseShaderCompiler@0 @94 - glRenderbufferStorage@16 @95 - glSampleCoverage@8 @96 - glScissor@16 @97 - glShaderBinary@20 @98 - glShaderSource@16 @99 - glStencilFunc@12 @100 - glStencilFuncSeparate@16 @101 - glStencilMask@4 @102 - glStencilMaskSeparate@8 @103 - glStencilOp@12 @104 - glStencilOpSeparate@16 @105 - glTexImage2D@36 @106 - glTexParameterf@12 @107 - glTexParameterfv@12 @108 - glTexParameteri@12 @109 - glTexParameteriv@12 @110 - glTexSubImage2D@36 @111 - glUniform1f@8 @112 - glUniform1fv@12 @113 - glUniform1i@8 @114 - glUniform1iv@12 @115 - glUniform2f@12 @116 - glUniform2fv@12 @117 - glUniform2i@12 @118 - glUniform2iv@12 @119 - glUniform3f@16 @120 - glUniform3fv@12 @121 - glUniform3i@16 @122 - glUniform3iv@12 @123 - glUniform4f@20 @124 - glUniform4fv@12 @125 - glUniform4i@20 @126 - glUniform4iv@12 @127 - glUniformMatrix2fv@16 @128 - glUniformMatrix3fv@16 @129 - glUniformMatrix4fv@16 @130 - glUseProgram@4 @131 - glValidateProgram@4 @132 - glVertexAttrib1f@8 @133 - glVertexAttrib1fv@8 @134 - glVertexAttrib2f@12 @135 - glVertexAttrib2fv@8 @136 - glVertexAttrib3f@16 @137 - glVertexAttrib3fv@8 @138 - glVertexAttrib4f@20 @139 - glVertexAttrib4fv@8 @140 - glVertexAttribPointer@24 @141 - glViewport@16 @142 - - ; Extensions - glBlitFramebufferANGLE@40 @149 - glRenderbufferStorageMultisampleANGLE@20 @150 - glDeleteFencesNV@8 @151 - glFinishFenceNV@4 @152 - glGenFencesNV@8 @153 - glGetFenceivNV@12 @154 - glIsFenceNV@4 @155 - glSetFenceNV@8 @156 - glTestFenceNV@4 @157 - glGetTranslatedShaderSourceANGLE@16 @159 - glTexStorage2DEXT@20 @160 - glGetGraphicsResetStatusEXT@0 @161 - glReadnPixelsEXT@32 @162 - glGetnUniformfvEXT@16 @163 - glGetnUniformivEXT@16 @164 - glGenQueriesEXT@8 @165 - glDeleteQueriesEXT@8 @166 - glIsQueryEXT@4 @167 - glBeginQueryEXT@8 @168 - glEndQueryEXT@4 @169 - glGetQueryivEXT@12 @170 - glGetQueryObjectuivEXT@12 @171 - glVertexAttribDivisorANGLE@8 @172 - glDrawArraysInstancedANGLE@16 @173 - glDrawElementsInstancedANGLE@20 @174 - glProgramBinaryOES@16 @175 - glGetProgramBinaryOES@20 @176 - glDrawBuffersEXT@8 @179 - glMapBufferOES@8 @285 - glUnmapBufferOES@4 @286 - 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 - glDrawRangeElements@24 @181 - glTexImage3D@40 @182 - glTexSubImage3D@44 @183 - glCopyTexSubImage3D@36 @184 - glCompressedTexImage3D@36 @185 - glCompressedTexSubImage3D@44 @186 - glGenQueries@8 @187 - glDeleteQueries@8 @188 - glIsQuery@4 @189 - glBeginQuery@8 @190 - glEndQuery@4 @191 - glGetQueryiv@12 @192 - glGetQueryObjectuiv@12 @193 - glUnmapBuffer@4 @194 - glGetBufferPointerv@12 @195 - glDrawBuffers@8 @196 - glUniformMatrix2x3fv@16 @197 - glUniformMatrix3x2fv@16 @198 - glUniformMatrix2x4fv@16 @199 - glUniformMatrix4x2fv@16 @200 - glUniformMatrix3x4fv@16 @201 - glUniformMatrix4x3fv@16 @202 - glBlitFramebuffer@40 @203 - glRenderbufferStorageMultisample@20 @204 - glFramebufferTextureLayer@20 @205 - glMapBufferRange@16 @206 - glFlushMappedBufferRange@12 @207 - glBindVertexArray@4 @208 - glDeleteVertexArrays@8 @209 - glGenVertexArrays@8 @210 - glIsVertexArray@4 @211 - glGetIntegeri_v@12 @212 - glBeginTransformFeedback@4 @213 - glEndTransformFeedback@0 @214 - glBindBufferRange@20 @215 - glBindBufferBase@12 @216 - glTransformFeedbackVaryings@16 @217 - glGetTransformFeedbackVarying@28 @218 - glVertexAttribIPointer@20 @219 - glGetVertexAttribIiv@12 @220 - glGetVertexAttribIuiv@12 @221 - glVertexAttribI4i@20 @222 - glVertexAttribI4ui@20 @223 - glVertexAttribI4iv@8 @224 - glVertexAttribI4uiv@8 @225 - glGetUniformuiv@12 @226 - glGetFragDataLocation@8 @227 - glUniform1ui@8 @228 - glUniform2ui@12 @229 - glUniform3ui@16 @230 - glUniform4ui@20 @231 - glUniform1uiv@12 @232 - glUniform2uiv@12 @233 - glUniform3uiv@12 @234 - glUniform4uiv@12 @235 - glClearBufferiv@12 @236 - glClearBufferuiv@12 @237 - glClearBufferfv@12 @238 - glClearBufferfi@16 @239 - glGetStringi@8 @240 - glCopyBufferSubData@20 @241 - glGetUniformIndices@16 @242 - glGetActiveUniformsiv@20 @243 - glGetUniformBlockIndex@8 @244 - glGetActiveUniformBlockiv@16 @245 - glGetActiveUniformBlockName@20 @246 - glUniformBlockBinding@12 @247 - glDrawArraysInstanced@16 @248 - glDrawElementsInstanced@20 @249 - glFenceSync@8 @250 - glIsSync@4 @251 - glDeleteSync@4 @252 - glClientWaitSync@16 @253 - glWaitSync@16 @254 - glGetInteger64v@8 @255 - glGetSynciv@20 @256 - glGetInteger64i_v@12 @257 - glGetBufferParameteri64v@12 @258 - glGenSamplers@8 @259 - glDeleteSamplers@8 @260 - glIsSampler@4 @261 - glBindSampler@8 @262 - glSamplerParameteri@12 @263 - glSamplerParameteriv@12 @264 - glSamplerParameterf@12 @265 - glSamplerParameterfv@12 @266 - glGetSamplerParameteriv@12 @267 - glGetSamplerParameterfv@12 @268 - glVertexAttribDivisor@8 @269 - glBindTransformFeedback@8 @270 - glDeleteTransformFeedbacks@8 @271 - glGenTransformFeedbacks@8 @272 - glIsTransformFeedback@4 @273 - glPauseTransformFeedback@0 @274 - glResumeTransformFeedback@0 @275 - glGetProgramBinary@20 @276 - glProgramBinary@16 @277 - glProgramParameteri@12 @278 - glInvalidateFramebuffer@12 @279 - glInvalidateSubFramebuffer@28 @280 - glTexStorage2D@20 @281 - glTexStorage3D@24 @282 - glGetInternalformativ@20 @283 - - ; 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/proc_table.h b/src/3rdparty/angle/src/libGLESv2/proc_table.h new file mode 100644 index 0000000000..f718291be7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/proc_table.h @@ -0,0 +1,24 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// getProcAddress loader table: +// Mapping from a string entry point name to function address. +// + +#ifndef LIBGLESV2_PROC_TABLE_H_ +#define LIBGLESV2_PROC_TABLE_H_ + +#include +#include + +namespace egl +{ +using ProcEntry = std::pair; + +extern ProcEntry g_procTable[]; +extern size_t g_numProcs; +} // namespace egl + +#endif // LIBGLESV2_PROC_TABLE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/proc_table_autogen.cpp b/src/3rdparty/angle/src/libGLESv2/proc_table_autogen.cpp new file mode 100644 index 0000000000..f294c1edc3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/proc_table_autogen.cpp @@ -0,0 +1,548 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_proc_table.py using data from proc_table_data.json. +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// getProcAddress loader table: +// Mapping from a string entry point name to function address. +// + +#include "libGLESv2/proc_table.h" + +#include "libGLESv2/entry_points_egl.h" +#include "libGLESv2/entry_points_egl_ext.h" +#include "libGLESv2/entry_points_gles_2_0_autogen.h" +#include "libGLESv2/entry_points_gles_2_0_ext.h" +#include "libGLESv2/entry_points_gles_3_0_autogen.h" +#include "libGLESv2/entry_points_gles_3_1_autogen.h" +#include "platform/Platform.h" + +#define P(FUNC) reinterpret_cast<__eglMustCastToProperFunctionPointerType>(FUNC) + +namespace egl +{ +ProcEntry g_procTable[] = { + {"ANGLEGetDisplayPlatform", P(ANGLEGetDisplayPlatform)}, + {"ANGLEResetDisplayPlatform", P(ANGLEResetDisplayPlatform)}, + {"eglBindAPI", P(egl::BindAPI)}, + {"eglBindTexImage", P(egl::BindTexImage)}, + {"eglChooseConfig", P(egl::ChooseConfig)}, + {"eglClientWaitSync", P(egl::ClientWaitSync)}, + {"eglCopyBuffers", P(egl::CopyBuffers)}, + {"eglCreateContext", P(egl::CreateContext)}, + {"eglCreateDeviceANGLE", P(egl::CreateDeviceANGLE)}, + {"eglCreateImage", P(egl::CreateImage)}, + {"eglCreateImageKHR", P(egl::CreateImageKHR)}, + {"eglCreatePbufferFromClientBuffer", P(egl::CreatePbufferFromClientBuffer)}, + {"eglCreatePbufferSurface", P(egl::CreatePbufferSurface)}, + {"eglCreatePixmapSurface", P(egl::CreatePixmapSurface)}, + {"eglCreatePlatformPixmapSurface", P(egl::CreatePlatformPixmapSurface)}, + {"eglCreatePlatformWindowSurface", P(egl::CreatePlatformWindowSurface)}, + {"eglCreateStreamKHR", P(egl::CreateStreamKHR)}, + {"eglCreateStreamProducerD3DTextureNV12ANGLE", P(egl::CreateStreamProducerD3DTextureNV12ANGLE)}, + {"eglCreateSync", P(egl::CreateSync)}, + {"eglCreateWindowSurface", P(egl::CreateWindowSurface)}, + {"eglDestroyContext", P(egl::DestroyContext)}, + {"eglDestroyImage", P(egl::DestroyImage)}, + {"eglDestroyImageKHR", P(egl::DestroyImageKHR)}, + {"eglDestroyStreamKHR", P(egl::DestroyStreamKHR)}, + {"eglDestroySurface", P(egl::DestroySurface)}, + {"eglDestroySync", P(egl::DestroySync)}, + {"eglGetConfigAttrib", P(egl::GetConfigAttrib)}, + {"eglGetConfigs", P(egl::GetConfigs)}, + {"eglGetCurrentContext", P(egl::GetCurrentContext)}, + {"eglGetCurrentDisplay", P(egl::GetCurrentDisplay)}, + {"eglGetCurrentSurface", P(egl::GetCurrentSurface)}, + {"eglGetDisplay", P(egl::GetDisplay)}, + {"eglGetError", P(egl::GetError)}, + {"eglGetPlatformDisplay", P(egl::GetPlatformDisplay)}, + {"eglGetPlatformDisplayEXT", P(egl::GetPlatformDisplayEXT)}, + {"eglGetProcAddress", P(egl::GetProcAddress)}, + {"eglGetSyncAttrib", P(egl::GetSyncAttrib)}, + {"eglGetSyncValuesCHROMIUM", P(egl::GetSyncValuesCHROMIUM)}, + {"eglInitialize", P(egl::Initialize)}, + {"eglMakeCurrent", P(egl::MakeCurrent)}, + {"eglPostSubBufferNV", P(egl::PostSubBufferNV)}, + {"eglProgramCacheGetAttribANGLE", P(egl::ProgramCacheGetAttribANGLE)}, + {"eglProgramCachePopulateANGLE", P(egl::ProgramCachePopulateANGLE)}, + {"eglProgramCacheQueryANGLE", P(egl::ProgramCacheQueryANGLE)}, + {"eglProgramCacheResizeANGLE", P(egl::ProgramCacheResizeANGLE)}, + {"eglQueryAPI", P(egl::QueryAPI)}, + {"eglQueryContext", P(egl::QueryContext)}, + {"eglQueryDeviceAttribEXT", P(egl::QueryDeviceAttribEXT)}, + {"eglQueryDeviceStringEXT", P(egl::QueryDeviceStringEXT)}, + {"eglQueryDisplayAttribEXT", P(egl::QueryDisplayAttribEXT)}, + {"eglQueryStreamKHR", P(egl::QueryStreamKHR)}, + {"eglQueryStreamu64KHR", P(egl::QueryStreamu64KHR)}, + {"eglQueryString", P(egl::QueryString)}, + {"eglQuerySurface", P(egl::QuerySurface)}, + {"eglQuerySurfacePointerANGLE", P(egl::QuerySurfacePointerANGLE)}, + {"eglReleaseDeviceANGLE", P(egl::ReleaseDeviceANGLE)}, + {"eglReleaseTexImage", P(egl::ReleaseTexImage)}, + {"eglReleaseThread", P(egl::ReleaseThread)}, + {"eglStreamAttribKHR", P(egl::StreamAttribKHR)}, + {"eglStreamConsumerAcquireKHR", P(egl::StreamConsumerAcquireKHR)}, + {"eglStreamConsumerGLTextureExternalAttribsNV", + P(egl::StreamConsumerGLTextureExternalAttribsNV)}, + {"eglStreamConsumerGLTextureExternalKHR", P(egl::StreamConsumerGLTextureExternalKHR)}, + {"eglStreamConsumerReleaseKHR", P(egl::StreamConsumerReleaseKHR)}, + {"eglStreamPostD3DTextureNV12ANGLE", P(egl::StreamPostD3DTextureNV12ANGLE)}, + {"eglSurfaceAttrib", P(egl::SurfaceAttrib)}, + {"eglSwapBuffers", P(egl::SwapBuffers)}, + {"eglSwapBuffersWithDamageEXT", P(egl::SwapBuffersWithDamageEXT)}, + {"eglSwapInterval", P(egl::SwapInterval)}, + {"eglTerminate", P(egl::Terminate)}, + {"eglWaitClient", P(egl::WaitClient)}, + {"eglWaitGL", P(egl::WaitGL)}, + {"eglWaitNative", P(egl::WaitNative)}, + {"eglWaitSync", P(egl::WaitSync)}, + {"glActiveShaderProgram", P(gl::ActiveShaderProgram)}, + {"glActiveTexture", P(gl::ActiveTexture)}, + {"glAttachShader", P(gl::AttachShader)}, + {"glBeginQuery", P(gl::BeginQuery)}, + {"glBeginQueryEXT", P(gl::BeginQueryEXT)}, + {"glBeginTransformFeedback", P(gl::BeginTransformFeedback)}, + {"glBindAttribLocation", P(gl::BindAttribLocation)}, + {"glBindBuffer", P(gl::BindBuffer)}, + {"glBindBufferBase", P(gl::BindBufferBase)}, + {"glBindBufferRange", P(gl::BindBufferRange)}, + {"glBindFramebuffer", P(gl::BindFramebuffer)}, + {"glBindImageTexture", P(gl::BindImageTexture)}, + {"glBindProgramPipeline", P(gl::BindProgramPipeline)}, + {"glBindRenderbuffer", P(gl::BindRenderbuffer)}, + {"glBindSampler", P(gl::BindSampler)}, + {"glBindTexture", P(gl::BindTexture)}, + {"glBindTransformFeedback", P(gl::BindTransformFeedback)}, + {"glBindUniformLocationCHROMIUM", P(gl::BindUniformLocationCHROMIUM)}, + {"glBindVertexArray", P(gl::BindVertexArray)}, + {"glBindVertexArrayOES", P(gl::BindVertexArrayOES)}, + {"glBindVertexBuffer", P(gl::BindVertexBuffer)}, + {"glBlendColor", P(gl::BlendColor)}, + {"glBlendEquation", P(gl::BlendEquation)}, + {"glBlendEquationSeparate", P(gl::BlendEquationSeparate)}, + {"glBlendFunc", P(gl::BlendFunc)}, + {"glBlendFuncSeparate", P(gl::BlendFuncSeparate)}, + {"glBlitFramebuffer", P(gl::BlitFramebuffer)}, + {"glBlitFramebufferANGLE", P(gl::BlitFramebufferANGLE)}, + {"glBufferData", P(gl::BufferData)}, + {"glBufferSubData", P(gl::BufferSubData)}, + {"glCheckFramebufferStatus", P(gl::CheckFramebufferStatus)}, + {"glClear", P(gl::Clear)}, + {"glClearBufferfi", P(gl::ClearBufferfi)}, + {"glClearBufferfv", P(gl::ClearBufferfv)}, + {"glClearBufferiv", P(gl::ClearBufferiv)}, + {"glClearBufferuiv", P(gl::ClearBufferuiv)}, + {"glClearColor", P(gl::ClearColor)}, + {"glClearDepthf", P(gl::ClearDepthf)}, + {"glClearStencil", P(gl::ClearStencil)}, + {"glClientWaitSync", P(gl::ClientWaitSync)}, + {"glColorMask", P(gl::ColorMask)}, + {"glCompileShader", P(gl::CompileShader)}, + {"glCompressedCopyTextureCHROMIUM", P(gl::CompressedCopyTextureCHROMIUM)}, + {"glCompressedTexImage2D", P(gl::CompressedTexImage2D)}, + {"glCompressedTexImage2DRobustANGLE", P(gl::CompressedTexImage2DRobustANGLE)}, + {"glCompressedTexImage3D", P(gl::CompressedTexImage3D)}, + {"glCompressedTexImage3DRobustANGLE", P(gl::CompressedTexImage3DRobustANGLE)}, + {"glCompressedTexSubImage2D", P(gl::CompressedTexSubImage2D)}, + {"glCompressedTexSubImage2DRobustANGLE", P(gl::CompressedTexSubImage2DRobustANGLE)}, + {"glCompressedTexSubImage3D", P(gl::CompressedTexSubImage3D)}, + {"glCompressedTexSubImage3DRobustANGLE", P(gl::CompressedTexSubImage3DRobustANGLE)}, + {"glCopyBufferSubData", P(gl::CopyBufferSubData)}, + {"glCopySubTextureCHROMIUM", P(gl::CopySubTextureCHROMIUM)}, + {"glCopyTexImage2D", P(gl::CopyTexImage2D)}, + {"glCopyTexSubImage2D", P(gl::CopyTexSubImage2D)}, + {"glCopyTexSubImage3D", P(gl::CopyTexSubImage3D)}, + {"glCopyTextureCHROMIUM", P(gl::CopyTextureCHROMIUM)}, + {"glCreateProgram", P(gl::CreateProgram)}, + {"glCreateShader", P(gl::CreateShader)}, + {"glCreateShaderProgramv", P(gl::CreateShaderProgramv)}, + {"glCullFace", P(gl::CullFace)}, + {"glDebugMessageCallbackKHR", P(gl::DebugMessageCallbackKHR)}, + {"glDebugMessageControlKHR", P(gl::DebugMessageControlKHR)}, + {"glDebugMessageInsertKHR", P(gl::DebugMessageInsertKHR)}, + {"glDeleteBuffers", P(gl::DeleteBuffers)}, + {"glDeleteFencesNV", P(gl::DeleteFencesNV)}, + {"glDeleteFramebuffers", P(gl::DeleteFramebuffers)}, + {"glDeleteProgram", P(gl::DeleteProgram)}, + {"glDeleteProgramPipelines", P(gl::DeleteProgramPipelines)}, + {"glDeleteQueries", P(gl::DeleteQueries)}, + {"glDeleteQueriesEXT", P(gl::DeleteQueriesEXT)}, + {"glDeleteRenderbuffers", P(gl::DeleteRenderbuffers)}, + {"glDeleteSamplers", P(gl::DeleteSamplers)}, + {"glDeleteShader", P(gl::DeleteShader)}, + {"glDeleteSync", P(gl::DeleteSync)}, + {"glDeleteTextures", P(gl::DeleteTextures)}, + {"glDeleteTransformFeedbacks", P(gl::DeleteTransformFeedbacks)}, + {"glDeleteVertexArrays", P(gl::DeleteVertexArrays)}, + {"glDeleteVertexArraysOES", P(gl::DeleteVertexArraysOES)}, + {"glDepthFunc", P(gl::DepthFunc)}, + {"glDepthMask", P(gl::DepthMask)}, + {"glDepthRangef", P(gl::DepthRangef)}, + {"glDetachShader", P(gl::DetachShader)}, + {"glDisable", P(gl::Disable)}, + {"glDisableVertexAttribArray", P(gl::DisableVertexAttribArray)}, + {"glDiscardFramebufferEXT", P(gl::DiscardFramebufferEXT)}, + {"glDispatchCompute", P(gl::DispatchCompute)}, + {"glDispatchComputeIndirect", P(gl::DispatchComputeIndirect)}, + {"glDrawArrays", P(gl::DrawArrays)}, + {"glDrawArraysIndirect", P(gl::DrawArraysIndirect)}, + {"glDrawArraysInstanced", P(gl::DrawArraysInstanced)}, + {"glDrawArraysInstancedANGLE", P(gl::DrawArraysInstancedANGLE)}, + {"glDrawBuffers", P(gl::DrawBuffers)}, + {"glDrawBuffersEXT", P(gl::DrawBuffersEXT)}, + {"glDrawElements", P(gl::DrawElements)}, + {"glDrawElementsIndirect", P(gl::DrawElementsIndirect)}, + {"glDrawElementsInstanced", P(gl::DrawElementsInstanced)}, + {"glDrawElementsInstancedANGLE", P(gl::DrawElementsInstancedANGLE)}, + {"glDrawRangeElements", P(gl::DrawRangeElements)}, + {"glEGLImageTargetRenderbufferStorageOES", P(gl::EGLImageTargetRenderbufferStorageOES)}, + {"glEGLImageTargetTexture2DOES", P(gl::EGLImageTargetTexture2DOES)}, + {"glEnable", P(gl::Enable)}, + {"glEnableVertexAttribArray", P(gl::EnableVertexAttribArray)}, + {"glEndQuery", P(gl::EndQuery)}, + {"glEndQueryEXT", P(gl::EndQueryEXT)}, + {"glEndTransformFeedback", P(gl::EndTransformFeedback)}, + {"glFenceSync", P(gl::FenceSync)}, + {"glFinish", P(gl::Finish)}, + {"glFinishFenceNV", P(gl::FinishFenceNV)}, + {"glFlush", P(gl::Flush)}, + {"glFlushMappedBufferRange", P(gl::FlushMappedBufferRange)}, + {"glFlushMappedBufferRangeEXT", P(gl::FlushMappedBufferRangeEXT)}, + {"glFramebufferParameteri", P(gl::FramebufferParameteri)}, + {"glFramebufferRenderbuffer", P(gl::FramebufferRenderbuffer)}, + {"glFramebufferTexture2D", P(gl::FramebufferTexture2D)}, + {"glFramebufferTextureLayer", P(gl::FramebufferTextureLayer)}, + {"glFramebufferTextureMultiviewLayeredANGLE", P(gl::FramebufferTextureMultiviewLayeredANGLE)}, + {"glFramebufferTextureMultiviewSideBySideANGLE", + P(gl::FramebufferTextureMultiviewSideBySideANGLE)}, + {"glFrontFace", P(gl::FrontFace)}, + {"glGenBuffers", P(gl::GenBuffers)}, + {"glGenFencesNV", P(gl::GenFencesNV)}, + {"glGenFramebuffers", P(gl::GenFramebuffers)}, + {"glGenProgramPipelines", P(gl::GenProgramPipelines)}, + {"glGenQueries", P(gl::GenQueries)}, + {"glGenQueriesEXT", P(gl::GenQueriesEXT)}, + {"glGenRenderbuffers", P(gl::GenRenderbuffers)}, + {"glGenSamplers", P(gl::GenSamplers)}, + {"glGenTextures", P(gl::GenTextures)}, + {"glGenTransformFeedbacks", P(gl::GenTransformFeedbacks)}, + {"glGenVertexArrays", P(gl::GenVertexArrays)}, + {"glGenVertexArraysOES", P(gl::GenVertexArraysOES)}, + {"glGenerateMipmap", P(gl::GenerateMipmap)}, + {"glGetActiveAttrib", P(gl::GetActiveAttrib)}, + {"glGetActiveUniform", P(gl::GetActiveUniform)}, + {"glGetActiveUniformBlockName", P(gl::GetActiveUniformBlockName)}, + {"glGetActiveUniformBlockiv", P(gl::GetActiveUniformBlockiv)}, + {"glGetActiveUniformBlockivRobustANGLE", P(gl::GetActiveUniformBlockivRobustANGLE)}, + {"glGetActiveUniformsiv", P(gl::GetActiveUniformsiv)}, + {"glGetAttachedShaders", P(gl::GetAttachedShaders)}, + {"glGetAttribLocation", P(gl::GetAttribLocation)}, + {"glGetBooleani_v", P(gl::GetBooleani_v)}, + {"glGetBooleani_vRobustANGLE", P(gl::GetBooleani_vRobustANGLE)}, + {"glGetBooleanv", P(gl::GetBooleanv)}, + {"glGetBooleanvRobustANGLE", P(gl::GetBooleanvRobustANGLE)}, + {"glGetBufferParameteri64v", P(gl::GetBufferParameteri64v)}, + {"glGetBufferParameteri64vRobustANGLE", P(gl::GetBufferParameteri64vRobustANGLE)}, + {"glGetBufferParameteriv", P(gl::GetBufferParameteriv)}, + {"glGetBufferParameterivRobustANGLE", P(gl::GetBufferParameterivRobustANGLE)}, + {"glGetBufferPointerv", P(gl::GetBufferPointerv)}, + {"glGetBufferPointervOES", P(gl::GetBufferPointervOES)}, + {"glGetBufferPointervRobustANGLE", P(gl::GetBufferPointervRobustANGLE)}, + {"glGetDebugMessageLogKHR", P(gl::GetDebugMessageLogKHR)}, + {"glGetError", P(gl::GetError)}, + {"glGetFenceivNV", P(gl::GetFenceivNV)}, + {"glGetFloatv", P(gl::GetFloatv)}, + {"glGetFloatvRobustANGLE", P(gl::GetFloatvRobustANGLE)}, + {"glGetFragDataLocation", P(gl::GetFragDataLocation)}, + {"glGetFramebufferAttachmentParameteriv", P(gl::GetFramebufferAttachmentParameteriv)}, + {"glGetFramebufferAttachmentParameterivRobustANGLE", + P(gl::GetFramebufferAttachmentParameterivRobustANGLE)}, + {"glGetFramebufferParameteriv", P(gl::GetFramebufferParameteriv)}, + {"glGetFramebufferParameterivRobustANGLE", P(gl::GetFramebufferParameterivRobustANGLE)}, + {"glGetGraphicsResetStatusEXT", P(gl::GetGraphicsResetStatusEXT)}, + {"glGetInteger64i_v", P(gl::GetInteger64i_v)}, + {"glGetInteger64i_vRobustANGLE", P(gl::GetInteger64i_vRobustANGLE)}, + {"glGetInteger64v", P(gl::GetInteger64v)}, + {"glGetInteger64vRobustANGLE", P(gl::GetInteger64vRobustANGLE)}, + {"glGetIntegeri_v", P(gl::GetIntegeri_v)}, + {"glGetIntegeri_vRobustANGLE", P(gl::GetIntegeri_vRobustANGLE)}, + {"glGetIntegerv", P(gl::GetIntegerv)}, + {"glGetIntegervRobustANGLE", P(gl::GetIntegervRobustANGLE)}, + {"glGetInternalformativ", P(gl::GetInternalformativ)}, + {"glGetInternalformativRobustANGLE", P(gl::GetInternalformativRobustANGLE)}, + {"glGetMultisamplefv", P(gl::GetMultisamplefv)}, + {"glGetMultisamplefvRobustANGLE", P(gl::GetMultisamplefvRobustANGLE)}, + {"glGetObjectLabelKHR", P(gl::GetObjectLabelKHR)}, + {"glGetObjectPtrLabelKHR", P(gl::GetObjectPtrLabelKHR)}, + {"glGetPointervKHR", P(gl::GetPointervKHR)}, + {"glGetPointervRobustANGLERobustANGLE", P(gl::GetPointervRobustANGLERobustANGLE)}, + {"glGetProgramBinary", P(gl::GetProgramBinary)}, + {"glGetProgramBinaryOES", P(gl::GetProgramBinaryOES)}, + {"glGetProgramInfoLog", P(gl::GetProgramInfoLog)}, + {"glGetProgramInterfaceiv", P(gl::GetProgramInterfaceiv)}, + {"glGetProgramInterfaceivRobustANGLE", P(gl::GetProgramInterfaceivRobustANGLE)}, + {"glGetProgramPipelineInfoLog", P(gl::GetProgramPipelineInfoLog)}, + {"glGetProgramPipelineiv", P(gl::GetProgramPipelineiv)}, + {"glGetProgramResourceIndex", P(gl::GetProgramResourceIndex)}, + {"glGetProgramResourceLocation", P(gl::GetProgramResourceLocation)}, + {"glGetProgramResourceName", P(gl::GetProgramResourceName)}, + {"glGetProgramResourceiv", P(gl::GetProgramResourceiv)}, + {"glGetProgramiv", P(gl::GetProgramiv)}, + {"glGetProgramivRobustANGLE", P(gl::GetProgramivRobustANGLE)}, + {"glGetQueryObjecti64vEXT", P(gl::GetQueryObjecti64vEXT)}, + {"glGetQueryObjecti64vRobustANGLE", P(gl::GetQueryObjecti64vRobustANGLE)}, + {"glGetQueryObjectivEXT", P(gl::GetQueryObjectivEXT)}, + {"glGetQueryObjectivRobustANGLE", P(gl::GetQueryObjectivRobustANGLE)}, + {"glGetQueryObjectui64vEXT", P(gl::GetQueryObjectui64vEXT)}, + {"glGetQueryObjectui64vRobustANGLE", P(gl::GetQueryObjectui64vRobustANGLE)}, + {"glGetQueryObjectuiv", P(gl::GetQueryObjectuiv)}, + {"glGetQueryObjectuivEXT", P(gl::GetQueryObjectuivEXT)}, + {"glGetQueryObjectuivRobustANGLE", P(gl::GetQueryObjectuivRobustANGLE)}, + {"glGetQueryiv", P(gl::GetQueryiv)}, + {"glGetQueryivEXT", P(gl::GetQueryivEXT)}, + {"glGetQueryivRobustANGLE", P(gl::GetQueryivRobustANGLE)}, + {"glGetRenderbufferParameteriv", P(gl::GetRenderbufferParameteriv)}, + {"glGetRenderbufferParameterivRobustANGLE", P(gl::GetRenderbufferParameterivRobustANGLE)}, + {"glGetSamplerParameterIivRobustANGLE", P(gl::GetSamplerParameterIivRobustANGLE)}, + {"glGetSamplerParameterIuivRobustANGLE", P(gl::GetSamplerParameterIuivRobustANGLE)}, + {"glGetSamplerParameterfv", P(gl::GetSamplerParameterfv)}, + {"glGetSamplerParameterfvRobustANGLE", P(gl::GetSamplerParameterfvRobustANGLE)}, + {"glGetSamplerParameteriv", P(gl::GetSamplerParameteriv)}, + {"glGetSamplerParameterivRobustANGLE", P(gl::GetSamplerParameterivRobustANGLE)}, + {"glGetShaderInfoLog", P(gl::GetShaderInfoLog)}, + {"glGetShaderPrecisionFormat", P(gl::GetShaderPrecisionFormat)}, + {"glGetShaderSource", P(gl::GetShaderSource)}, + {"glGetShaderiv", P(gl::GetShaderiv)}, + {"glGetShaderivRobustANGLE", P(gl::GetShaderivRobustANGLE)}, + {"glGetString", P(gl::GetString)}, + {"glGetStringi", P(gl::GetStringi)}, + {"glGetSynciv", P(gl::GetSynciv)}, + {"glGetTexLevelParameterfv", P(gl::GetTexLevelParameterfv)}, + {"glGetTexLevelParameterfvRobustANGLE", P(gl::GetTexLevelParameterfvRobustANGLE)}, + {"glGetTexLevelParameteriv", P(gl::GetTexLevelParameteriv)}, + {"glGetTexLevelParameterivRobustANGLE", P(gl::GetTexLevelParameterivRobustANGLE)}, + {"glGetTexParameterIivRobustANGLE", P(gl::GetTexParameterIivRobustANGLE)}, + {"glGetTexParameterIuivRobustANGLE", P(gl::GetTexParameterIuivRobustANGLE)}, + {"glGetTexParameterfv", P(gl::GetTexParameterfv)}, + {"glGetTexParameterfvRobustANGLE", P(gl::GetTexParameterfvRobustANGLE)}, + {"glGetTexParameteriv", P(gl::GetTexParameteriv)}, + {"glGetTexParameterivRobustANGLE", P(gl::GetTexParameterivRobustANGLE)}, + {"glGetTransformFeedbackVarying", P(gl::GetTransformFeedbackVarying)}, + {"glGetTranslatedShaderSourceANGLE", P(gl::GetTranslatedShaderSourceANGLE)}, + {"glGetUniformBlockIndex", P(gl::GetUniformBlockIndex)}, + {"glGetUniformIndices", P(gl::GetUniformIndices)}, + {"glGetUniformLocation", P(gl::GetUniformLocation)}, + {"glGetUniformfv", P(gl::GetUniformfv)}, + {"glGetUniformfvRobustANGLE", P(gl::GetUniformfvRobustANGLE)}, + {"glGetUniformiv", P(gl::GetUniformiv)}, + {"glGetUniformivRobustANGLE", P(gl::GetUniformivRobustANGLE)}, + {"glGetUniformuiv", P(gl::GetUniformuiv)}, + {"glGetUniformuivRobustANGLE", P(gl::GetUniformuivRobustANGLE)}, + {"glGetVertexAttribIiv", P(gl::GetVertexAttribIiv)}, + {"glGetVertexAttribIivRobustANGLE", P(gl::GetVertexAttribIivRobustANGLE)}, + {"glGetVertexAttribIuiv", P(gl::GetVertexAttribIuiv)}, + {"glGetVertexAttribIuivRobustANGLE", P(gl::GetVertexAttribIuivRobustANGLE)}, + {"glGetVertexAttribPointerv", P(gl::GetVertexAttribPointerv)}, + {"glGetVertexAttribPointervRobustANGLE", P(gl::GetVertexAttribPointervRobustANGLE)}, + {"glGetVertexAttribfv", P(gl::GetVertexAttribfv)}, + {"glGetVertexAttribfvRobustANGLE", P(gl::GetVertexAttribfvRobustANGLE)}, + {"glGetVertexAttribiv", P(gl::GetVertexAttribiv)}, + {"glGetVertexAttribivRobustANGLE", P(gl::GetVertexAttribivRobustANGLE)}, + {"glGetnUniformfvEXT", P(gl::GetnUniformfvEXT)}, + {"glGetnUniformfvRobustANGLE", P(gl::GetnUniformfvRobustANGLE)}, + {"glGetnUniformivEXT", P(gl::GetnUniformivEXT)}, + {"glGetnUniformivRobustANGLE", P(gl::GetnUniformivRobustANGLE)}, + {"glGetnUniformuivRobustANGLE", P(gl::GetnUniformuivRobustANGLE)}, + {"glHint", P(gl::Hint)}, + {"glInsertEventMarkerEXT", P(gl::InsertEventMarkerEXT)}, + {"glInvalidateFramebuffer", P(gl::InvalidateFramebuffer)}, + {"glInvalidateSubFramebuffer", P(gl::InvalidateSubFramebuffer)}, + {"glIsBuffer", P(gl::IsBuffer)}, + {"glIsEnabled", P(gl::IsEnabled)}, + {"glIsFenceNV", P(gl::IsFenceNV)}, + {"glIsFramebuffer", P(gl::IsFramebuffer)}, + {"glIsProgram", P(gl::IsProgram)}, + {"glIsProgramPipeline", P(gl::IsProgramPipeline)}, + {"glIsQuery", P(gl::IsQuery)}, + {"glIsQueryEXT", P(gl::IsQueryEXT)}, + {"glIsRenderbuffer", P(gl::IsRenderbuffer)}, + {"glIsSampler", P(gl::IsSampler)}, + {"glIsShader", P(gl::IsShader)}, + {"glIsSync", P(gl::IsSync)}, + {"glIsTexture", P(gl::IsTexture)}, + {"glIsTransformFeedback", P(gl::IsTransformFeedback)}, + {"glIsVertexArray", P(gl::IsVertexArray)}, + {"glIsVertexArrayOES", P(gl::IsVertexArrayOES)}, + {"glLineWidth", P(gl::LineWidth)}, + {"glLinkProgram", P(gl::LinkProgram)}, + {"glMapBufferOES", P(gl::MapBufferOES)}, + {"glMapBufferRange", P(gl::MapBufferRange)}, + {"glMapBufferRangeEXT", P(gl::MapBufferRangeEXT)}, + {"glMemoryBarrier", P(gl::MemoryBarrier)}, + {"glMemoryBarrierByRegion", P(gl::MemoryBarrierByRegion)}, + {"glObjectLabelKHR", P(gl::ObjectLabelKHR)}, + {"glObjectPtrLabelKHR", P(gl::ObjectPtrLabelKHR)}, + {"glPauseTransformFeedback", P(gl::PauseTransformFeedback)}, + {"glPixelStorei", P(gl::PixelStorei)}, + {"glPolygonOffset", P(gl::PolygonOffset)}, + {"glPopDebugGroupKHR", P(gl::PopDebugGroupKHR)}, + {"glPopGroupMarkerEXT", P(gl::PopGroupMarkerEXT)}, + {"glProgramBinary", P(gl::ProgramBinary)}, + {"glProgramBinaryOES", P(gl::ProgramBinaryOES)}, + {"glProgramParameteri", P(gl::ProgramParameteri)}, + {"glProgramUniform1f", P(gl::ProgramUniform1f)}, + {"glProgramUniform1fv", P(gl::ProgramUniform1fv)}, + {"glProgramUniform1i", P(gl::ProgramUniform1i)}, + {"glProgramUniform1iv", P(gl::ProgramUniform1iv)}, + {"glProgramUniform1ui", P(gl::ProgramUniform1ui)}, + {"glProgramUniform1uiv", P(gl::ProgramUniform1uiv)}, + {"glProgramUniform2f", P(gl::ProgramUniform2f)}, + {"glProgramUniform2fv", P(gl::ProgramUniform2fv)}, + {"glProgramUniform2i", P(gl::ProgramUniform2i)}, + {"glProgramUniform2iv", P(gl::ProgramUniform2iv)}, + {"glProgramUniform2ui", P(gl::ProgramUniform2ui)}, + {"glProgramUniform2uiv", P(gl::ProgramUniform2uiv)}, + {"glProgramUniform3f", P(gl::ProgramUniform3f)}, + {"glProgramUniform3fv", P(gl::ProgramUniform3fv)}, + {"glProgramUniform3i", P(gl::ProgramUniform3i)}, + {"glProgramUniform3iv", P(gl::ProgramUniform3iv)}, + {"glProgramUniform3ui", P(gl::ProgramUniform3ui)}, + {"glProgramUniform3uiv", P(gl::ProgramUniform3uiv)}, + {"glProgramUniform4f", P(gl::ProgramUniform4f)}, + {"glProgramUniform4fv", P(gl::ProgramUniform4fv)}, + {"glProgramUniform4i", P(gl::ProgramUniform4i)}, + {"glProgramUniform4iv", P(gl::ProgramUniform4iv)}, + {"glProgramUniform4ui", P(gl::ProgramUniform4ui)}, + {"glProgramUniform4uiv", P(gl::ProgramUniform4uiv)}, + {"glProgramUniformMatrix2fv", P(gl::ProgramUniformMatrix2fv)}, + {"glProgramUniformMatrix2x3fv", P(gl::ProgramUniformMatrix2x3fv)}, + {"glProgramUniformMatrix2x4fv", P(gl::ProgramUniformMatrix2x4fv)}, + {"glProgramUniformMatrix3fv", P(gl::ProgramUniformMatrix3fv)}, + {"glProgramUniformMatrix3x2fv", P(gl::ProgramUniformMatrix3x2fv)}, + {"glProgramUniformMatrix3x4fv", P(gl::ProgramUniformMatrix3x4fv)}, + {"glProgramUniformMatrix4fv", P(gl::ProgramUniformMatrix4fv)}, + {"glProgramUniformMatrix4x2fv", P(gl::ProgramUniformMatrix4x2fv)}, + {"glProgramUniformMatrix4x3fv", P(gl::ProgramUniformMatrix4x3fv)}, + {"glPushDebugGroupKHR", P(gl::PushDebugGroupKHR)}, + {"glPushGroupMarkerEXT", P(gl::PushGroupMarkerEXT)}, + {"glQueryCounterEXT", P(gl::QueryCounterEXT)}, + {"glReadBuffer", P(gl::ReadBuffer)}, + {"glReadPixels", P(gl::ReadPixels)}, + {"glReadPixelsRobustANGLE", P(gl::ReadPixelsRobustANGLE)}, + {"glReadnPixelsEXT", P(gl::ReadnPixelsEXT)}, + {"glReadnPixelsRobustANGLE", P(gl::ReadnPixelsRobustANGLE)}, + {"glReleaseShaderCompiler", P(gl::ReleaseShaderCompiler)}, + {"glRenderbufferStorage", P(gl::RenderbufferStorage)}, + {"glRenderbufferStorageMultisample", P(gl::RenderbufferStorageMultisample)}, + {"glRenderbufferStorageMultisampleANGLE", P(gl::RenderbufferStorageMultisampleANGLE)}, + {"glRequestExtensionANGLE", P(gl::RequestExtensionANGLE)}, + {"glResumeTransformFeedback", P(gl::ResumeTransformFeedback)}, + {"glSampleCoverage", P(gl::SampleCoverage)}, + {"glSampleMaski", P(gl::SampleMaski)}, + {"glSamplerParameterIivRobustANGLE", P(gl::SamplerParameterIivRobustANGLE)}, + {"glSamplerParameterIuivRobustANGLE", P(gl::SamplerParameterIuivRobustANGLE)}, + {"glSamplerParameterf", P(gl::SamplerParameterf)}, + {"glSamplerParameterfv", P(gl::SamplerParameterfv)}, + {"glSamplerParameterfvRobustANGLE", P(gl::SamplerParameterfvRobustANGLE)}, + {"glSamplerParameteri", P(gl::SamplerParameteri)}, + {"glSamplerParameteriv", P(gl::SamplerParameteriv)}, + {"glSamplerParameterivRobustANGLE", P(gl::SamplerParameterivRobustANGLE)}, + {"glScissor", P(gl::Scissor)}, + {"glSetFenceNV", P(gl::SetFenceNV)}, + {"glShaderBinary", P(gl::ShaderBinary)}, + {"glShaderSource", P(gl::ShaderSource)}, + {"glStencilFunc", P(gl::StencilFunc)}, + {"glStencilFuncSeparate", P(gl::StencilFuncSeparate)}, + {"glStencilMask", P(gl::StencilMask)}, + {"glStencilMaskSeparate", P(gl::StencilMaskSeparate)}, + {"glStencilOp", P(gl::StencilOp)}, + {"glStencilOpSeparate", P(gl::StencilOpSeparate)}, + {"glTestFenceNV", P(gl::TestFenceNV)}, + {"glTexImage2D", P(gl::TexImage2D)}, + {"glTexImage2DRobustANGLE", P(gl::TexImage2DRobustANGLE)}, + {"glTexImage3D", P(gl::TexImage3D)}, + {"glTexImage3DRobustANGLE", P(gl::TexImage3DRobustANGLE)}, + {"glTexParameterIivRobustANGLE", P(gl::TexParameterIivRobustANGLE)}, + {"glTexParameterIuivRobustANGLE", P(gl::TexParameterIuivRobustANGLE)}, + {"glTexParameterf", P(gl::TexParameterf)}, + {"glTexParameterfv", P(gl::TexParameterfv)}, + {"glTexParameterfvRobustANGLE", P(gl::TexParameterfvRobustANGLE)}, + {"glTexParameteri", P(gl::TexParameteri)}, + {"glTexParameteriv", P(gl::TexParameteriv)}, + {"glTexParameterivRobustANGLE", P(gl::TexParameterivRobustANGLE)}, + {"glTexStorage2D", P(gl::TexStorage2D)}, + {"glTexStorage2DEXT", P(gl::TexStorage2DEXT)}, + {"glTexStorage2DMultisample", P(gl::TexStorage2DMultisample)}, + {"glTexStorage3D", P(gl::TexStorage3D)}, + {"glTexSubImage2D", P(gl::TexSubImage2D)}, + {"glTexSubImage2DRobustANGLE", P(gl::TexSubImage2DRobustANGLE)}, + {"glTexSubImage3D", P(gl::TexSubImage3D)}, + {"glTexSubImage3DRobustANGLE", P(gl::TexSubImage3DRobustANGLE)}, + {"glTransformFeedbackVaryings", P(gl::TransformFeedbackVaryings)}, + {"glUniform1f", P(gl::Uniform1f)}, + {"glUniform1fv", P(gl::Uniform1fv)}, + {"glUniform1i", P(gl::Uniform1i)}, + {"glUniform1iv", P(gl::Uniform1iv)}, + {"glUniform1ui", P(gl::Uniform1ui)}, + {"glUniform1uiv", P(gl::Uniform1uiv)}, + {"glUniform2f", P(gl::Uniform2f)}, + {"glUniform2fv", P(gl::Uniform2fv)}, + {"glUniform2i", P(gl::Uniform2i)}, + {"glUniform2iv", P(gl::Uniform2iv)}, + {"glUniform2ui", P(gl::Uniform2ui)}, + {"glUniform2uiv", P(gl::Uniform2uiv)}, + {"glUniform3f", P(gl::Uniform3f)}, + {"glUniform3fv", P(gl::Uniform3fv)}, + {"glUniform3i", P(gl::Uniform3i)}, + {"glUniform3iv", P(gl::Uniform3iv)}, + {"glUniform3ui", P(gl::Uniform3ui)}, + {"glUniform3uiv", P(gl::Uniform3uiv)}, + {"glUniform4f", P(gl::Uniform4f)}, + {"glUniform4fv", P(gl::Uniform4fv)}, + {"glUniform4i", P(gl::Uniform4i)}, + {"glUniform4iv", P(gl::Uniform4iv)}, + {"glUniform4ui", P(gl::Uniform4ui)}, + {"glUniform4uiv", P(gl::Uniform4uiv)}, + {"glUniformBlockBinding", P(gl::UniformBlockBinding)}, + {"glUniformMatrix2fv", P(gl::UniformMatrix2fv)}, + {"glUniformMatrix2x3fv", P(gl::UniformMatrix2x3fv)}, + {"glUniformMatrix2x4fv", P(gl::UniformMatrix2x4fv)}, + {"glUniformMatrix3fv", P(gl::UniformMatrix3fv)}, + {"glUniformMatrix3x2fv", P(gl::UniformMatrix3x2fv)}, + {"glUniformMatrix3x4fv", P(gl::UniformMatrix3x4fv)}, + {"glUniformMatrix4fv", P(gl::UniformMatrix4fv)}, + {"glUniformMatrix4x2fv", P(gl::UniformMatrix4x2fv)}, + {"glUniformMatrix4x3fv", P(gl::UniformMatrix4x3fv)}, + {"glUnmapBuffer", P(gl::UnmapBuffer)}, + {"glUnmapBufferOES", P(gl::UnmapBufferOES)}, + {"glUseProgram", P(gl::UseProgram)}, + {"glUseProgramStages", P(gl::UseProgramStages)}, + {"glValidateProgram", P(gl::ValidateProgram)}, + {"glValidateProgramPipeline", P(gl::ValidateProgramPipeline)}, + {"glVertexAttrib1f", P(gl::VertexAttrib1f)}, + {"glVertexAttrib1fv", P(gl::VertexAttrib1fv)}, + {"glVertexAttrib2f", P(gl::VertexAttrib2f)}, + {"glVertexAttrib2fv", P(gl::VertexAttrib2fv)}, + {"glVertexAttrib3f", P(gl::VertexAttrib3f)}, + {"glVertexAttrib3fv", P(gl::VertexAttrib3fv)}, + {"glVertexAttrib4f", P(gl::VertexAttrib4f)}, + {"glVertexAttrib4fv", P(gl::VertexAttrib4fv)}, + {"glVertexAttribBinding", P(gl::VertexAttribBinding)}, + {"glVertexAttribDivisor", P(gl::VertexAttribDivisor)}, + {"glVertexAttribDivisorANGLE", P(gl::VertexAttribDivisorANGLE)}, + {"glVertexAttribFormat", P(gl::VertexAttribFormat)}, + {"glVertexAttribI4i", P(gl::VertexAttribI4i)}, + {"glVertexAttribI4iv", P(gl::VertexAttribI4iv)}, + {"glVertexAttribI4ui", P(gl::VertexAttribI4ui)}, + {"glVertexAttribI4uiv", P(gl::VertexAttribI4uiv)}, + {"glVertexAttribIFormat", P(gl::VertexAttribIFormat)}, + {"glVertexAttribIPointer", P(gl::VertexAttribIPointer)}, + {"glVertexAttribPointer", P(gl::VertexAttribPointer)}, + {"glVertexBindingDivisor", P(gl::VertexBindingDivisor)}, + {"glViewport", P(gl::Viewport)}, + {"glWaitSync", P(gl::WaitSync)}}; + +size_t g_numProcs = 516; +} // namespace egl diff --git a/src/3rdparty/angle/src/libGLESv2/proc_table_data.json b/src/3rdparty/angle/src/libGLESv2/proc_table_data.json new file mode 100644 index 0000000000..5ce1d433a8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/proc_table_data.json @@ -0,0 +1,662 @@ +{ + "GLES2 core": [ + "glActiveTexture", + "glAttachShader", + "glBindAttribLocation", + "glBindBuffer", + "glBindFramebuffer", + "glBindRenderbuffer", + "glBindTexture", + "glBlendColor", + "glBlendEquation", + "glBlendEquationSeparate", + "glBlendFunc", + "glBlendFuncSeparate", + "glBufferData", + "glBufferSubData", + "glCheckFramebufferStatus", + "glClear", + "glClearColor", + "glClearDepthf", + "glClearStencil", + "glCompileShader", + "glColorMask", + "glCompressedTexImage2D", + "glCompressedTexSubImage2D", + "glCopyTexImage2D", + "glCopyTexSubImage2D", + "glCreateProgram", + "glCreateShader", + "glCullFace", + "glDeleteBuffers", + "glDeleteFramebuffers", + "glDeleteProgram", + "glDeleteRenderbuffers", + "glDeleteShader", + "glDeleteTextures", + "glDepthFunc", + "glDepthMask", + "glDepthRangef", + "glDetachShader", + "glDisable", + "glDisableVertexAttribArray", + "glDrawArrays", + "glDrawElements", + "glEnable", + "glEnableVertexAttribArray", + "glFinish", + "glFlush", + "glFramebufferRenderbuffer", + "glFramebufferTexture2D", + "glFrontFace", + "glGenBuffers", + "glGenerateMipmap", + "glGenFramebuffers", + "glGenRenderbuffers", + "glGenTextures", + "glGetActiveAttrib", + "glGetActiveUniform", + "glGetAttachedShaders", + "glGetAttribLocation", + "glGetBooleanv", + "glGetBufferParameteriv", + "glGetError", + "glGetFloatv", + "glGetFramebufferAttachmentParameteriv", + "glGetIntegerv", + "glGetProgramiv", + "glGetProgramInfoLog", + "glGetRenderbufferParameteriv", + "glGetShaderiv", + "glGetShaderInfoLog", + "glGetShaderPrecisionFormat", + "glGetShaderSource", + "glGetString", + "glGetTexParameterfv", + "glGetTexParameteriv", + "glGetUniformfv", + "glGetUniformiv", + "glGetUniformLocation", + "glGetVertexAttribfv", + "glGetVertexAttribiv", + "glGetVertexAttribPointerv", + "glHint", + "glIsBuffer", + "glIsEnabled", + "glIsFramebuffer", + "glIsProgram", + "glIsRenderbuffer", + "glIsShader", + "glIsTexture", + "glLineWidth", + "glLinkProgram", + "glPixelStorei", + "glPolygonOffset", + "glReadPixels", + "glReleaseShaderCompiler", + "glRenderbufferStorage", + "glSampleCoverage", + "glScissor", + "glShaderBinary", + "glShaderSource", + "glStencilFunc", + "glStencilFuncSeparate", + "glStencilMask", + "glStencilMaskSeparate", + "glStencilOp", + "glStencilOpSeparate", + "glTexImage2D", + "glTexParameterf", + "glTexParameterfv", + "glTexParameteri", + "glTexParameteriv", + "glTexSubImage2D", + "glUniform1f", + "glUniform1fv", + "glUniform1i", + "glUniform1iv", + "glUniform2f", + "glUniform2fv", + "glUniform2i", + "glUniform2iv", + "glUniform3f", + "glUniform3fv", + "glUniform3i", + "glUniform3iv", + "glUniform4f", + "glUniform4fv", + "glUniform4i", + "glUniform4iv", + "glUniformMatrix2fv", + "glUniformMatrix3fv", + "glUniformMatrix4fv", + "glUseProgram", + "glValidateProgram", + "glVertexAttrib1f", + "glVertexAttrib1fv", + "glVertexAttrib2f", + "glVertexAttrib2fv", + "glVertexAttrib3f", + "glVertexAttrib3fv", + "glVertexAttrib4f", + "glVertexAttrib4fv", + "glVertexAttribPointer", + "glViewport" + ], + + "GL_ANGLE_framebuffer_blit": [ + "glBlitFramebufferANGLE" + ], + + "GL_ANGLE_framebuffer_multisample": [ + "glRenderbufferStorageMultisampleANGLE" + ], + + "GL_EXT_discard_framebuffer": [ + "glDiscardFramebufferEXT" + ], + + "GL_NV_fence": [ + "glDeleteFencesNV", + "glGenFencesNV", + "glIsFenceNV", + "glTestFenceNV", + "glGetFenceivNV", + "glFinishFenceNV", + "glSetFenceNV" + ], + + "GL_ANGLE_translated_shader_source": [ + "glGetTranslatedShaderSourceANGLE" + ], + + "GL_EXT_texture_storage": [ + "glTexStorage2DEXT" + ], + + "GL_EXT_robustness": [ + "glGetGraphicsResetStatusEXT", + "glReadnPixelsEXT", + "glGetnUniformfvEXT", + "glGetnUniformivEXT" + ], + + "GL_EXT_occlusion_query_boolean": [ + "glGenQueriesEXT", + "glDeleteQueriesEXT", + "glIsQueryEXT", + "glBeginQueryEXT", + "glEndQueryEXT", + "glGetQueryivEXT", + "glGetQueryObjectuivEXT" + ], + + "GL_EXT_disjoint_timer_query": [ + "glGenQueriesEXT", + "glDeleteQueriesEXT", + "glIsQueryEXT", + "glBeginQueryEXT", + "glEndQueryEXT", + "glQueryCounterEXT", + "glGetQueryivEXT", + "glGetQueryObjectivEXT", + "glGetQueryObjectuivEXT", + "glGetQueryObjecti64vEXT", + "glGetQueryObjectui64vEXT" + ], + + "GL_EXT_draw_buffers": [ + "glDrawBuffersEXT" + ], + + "GL_ANGLE_instanced_arrays": [ + "glDrawArraysInstancedANGLE", + "glDrawElementsInstancedANGLE", + "glVertexAttribDivisorANGLE" + ], + + "GL_OES_get_program_binary": [ + "glGetProgramBinaryOES", + "glProgramBinaryOES" + ], + + "GL_OES_mapbuffer": [ + "glMapBufferOES", + "glUnmapBufferOES", + "glGetBufferPointervOES" + ], + + "GL_EXT_map_buffer_range": [ + "glMapBufferRangeEXT", + "glFlushMappedBufferRangeEXT" + ], + + "GL_EXT_debug_marker": [ + "glInsertEventMarkerEXT", + "glPushGroupMarkerEXT", + "glPopGroupMarkerEXT" + ], + + "GL_OES_EGL_image": [ + "glEGLImageTargetTexture2DOES", + "glEGLImageTargetRenderbufferStorageOES" + ], + + "GL_OES_vertex_array_object": [ + "glBindVertexArrayOES", + "glDeleteVertexArraysOES", + "glGenVertexArraysOES", + "glIsVertexArrayOES" + ], + + "GL_KHR_debug": [ + "glDebugMessageControlKHR", + "glDebugMessageInsertKHR", + "glDebugMessageCallbackKHR", + "glGetDebugMessageLogKHR", + "glPushDebugGroupKHR", + "glPopDebugGroupKHR", + "glObjectLabelKHR", + "glGetObjectLabelKHR", + "glObjectPtrLabelKHR", + "glGetObjectPtrLabelKHR", + "glGetPointervKHR" + ], + + "GL_CHROMIUM_bind_uniform_location": [ + "glBindUniformLocationCHROMIUM" + ], + + "GL_CHROMIUM_copy_texture": [ + "glCopyTextureCHROMIUM", + "glCopySubTextureCHROMIUM" + ], + + "GL_CHROMIUM_copy_compressed_texture": [ + "glCompressedCopyTextureCHROMIUM" + ], + + "GL_ANGLE_request_extension": [ + "glRequestExtensionANGLE" + ], + + "GL_ANGLE_robust_client_memory": [ + "glGetBooleanvRobustANGLE", + "glGetBufferParameterivRobustANGLE", + "glGetFloatvRobustANGLE", + "glGetFramebufferAttachmentParameterivRobustANGLE", + "glGetIntegervRobustANGLE", + "glGetProgramivRobustANGLE", + "glGetRenderbufferParameterivRobustANGLE", + "glGetShaderivRobustANGLE", + "glGetTexParameterfvRobustANGLE", + "glGetTexParameterivRobustANGLE", + "glGetUniformfvRobustANGLE", + "glGetUniformivRobustANGLE", + "glGetVertexAttribfvRobustANGLE", + "glGetVertexAttribivRobustANGLE", + "glGetVertexAttribPointervRobustANGLE", + "glReadPixelsRobustANGLE", + "glTexImage2DRobustANGLE", + "glTexParameterfvRobustANGLE", + "glTexParameterivRobustANGLE", + "glTexSubImage2DRobustANGLE", + "glTexImage3DRobustANGLE", + "glTexSubImage3DRobustANGLE", + "glCompressedTexImage2DRobustANGLE", + "glCompressedTexSubImage2DRobustANGLE", + "glCompressedTexImage3DRobustANGLE", + "glCompressedTexSubImage3DRobustANGLE", + "glGetQueryivRobustANGLE", + "glGetQueryObjectuivRobustANGLE", + "glGetBufferPointervRobustANGLE", + "glGetIntegeri_vRobustANGLE", + "glGetInternalformativRobustANGLE", + "glGetVertexAttribIivRobustANGLE", + "glGetVertexAttribIuivRobustANGLE", + "glGetUniformuivRobustANGLE", + "glGetActiveUniformBlockivRobustANGLE", + "glGetInteger64vRobustANGLE", + "glGetInteger64i_vRobustANGLE", + "glGetBufferParameteri64vRobustANGLE", + "glSamplerParameterivRobustANGLE", + "glSamplerParameterfvRobustANGLE", + "glGetSamplerParameterivRobustANGLE", + "glGetSamplerParameterfvRobustANGLE", + "glGetFramebufferParameterivRobustANGLE", + "glGetProgramInterfaceivRobustANGLE", + "glGetBooleani_vRobustANGLE", + "glGetMultisamplefvRobustANGLE", + "glGetTexLevelParameterivRobustANGLE", + "glGetTexLevelParameterfvRobustANGLE", + "glGetPointervRobustANGLERobustANGLE", + "glReadnPixelsRobustANGLE", + "glGetnUniformfvRobustANGLE", + "glGetnUniformivRobustANGLE", + "glGetnUniformuivRobustANGLE", + "glTexParameterIivRobustANGLE", + "glTexParameterIuivRobustANGLE", + "glGetTexParameterIivRobustANGLE", + "glGetTexParameterIuivRobustANGLE", + "glSamplerParameterIivRobustANGLE", + "glSamplerParameterIuivRobustANGLE", + "glGetSamplerParameterIivRobustANGLE", + "glGetSamplerParameterIuivRobustANGLE", + "glGetQueryObjectivRobustANGLE", + "glGetQueryObjecti64vRobustANGLE", + "glGetQueryObjectui64vRobustANGLE" + ], + + "GL_ANGLE_multiview": [ + "glFramebufferTextureMultiviewLayeredANGLE", + "glFramebufferTextureMultiviewSideBySideANGLE" + ], + + "GLES3 core": [ + "glReadBuffer", + "glDrawRangeElements", + "glTexImage3D", + "glTexSubImage3D", + "glCopyTexSubImage3D", + "glCompressedTexImage3D", + "glCompressedTexSubImage3D", + "glGenQueries", + "glDeleteQueries", + "glIsQuery", + "glBeginQuery", + "glEndQuery", + "glGetQueryiv", + "glGetQueryObjectuiv", + "glUnmapBuffer", + "glGetBufferPointerv", + "glDrawBuffers", + "glUniformMatrix2x3fv", + "glUniformMatrix3x2fv", + "glUniformMatrix2x4fv", + "glUniformMatrix4x2fv", + "glUniformMatrix3x4fv", + "glUniformMatrix4x3fv", + "glBlitFramebuffer", + "glRenderbufferStorageMultisample", + "glFramebufferTextureLayer", + "glMapBufferRange", + "glFlushMappedBufferRange", + "glBindVertexArray", + "glDeleteVertexArrays", + "glGenVertexArrays", + "glIsVertexArray", + "glGetIntegeri_v", + "glBeginTransformFeedback", + "glEndTransformFeedback", + "glBindBufferRange", + "glBindBufferBase", + "glTransformFeedbackVaryings", + "glGetTransformFeedbackVarying", + "glVertexAttribIPointer", + "glGetVertexAttribIiv", + "glGetVertexAttribIuiv", + "glVertexAttribI4i", + "glVertexAttribI4ui", + "glVertexAttribI4iv", + "glVertexAttribI4uiv", + "glGetUniformuiv", + "glGetFragDataLocation", + "glUniform1ui", + "glUniform2ui", + "glUniform3ui", + "glUniform4ui", + "glUniform1uiv", + "glUniform2uiv", + "glUniform3uiv", + "glUniform4uiv", + "glClearBufferiv", + "glClearBufferuiv", + "glClearBufferfv", + "glClearBufferfi", + "glGetStringi", + "glCopyBufferSubData", + "glGetUniformIndices", + "glGetActiveUniformsiv", + "glGetUniformBlockIndex", + "glGetActiveUniformBlockiv", + "glGetActiveUniformBlockName", + "glUniformBlockBinding", + "glDrawArraysInstanced", + "glDrawElementsInstanced", + "glFenceSync", + "glIsSync", + "glDeleteSync", + "glClientWaitSync", + "glWaitSync", + "glGetInteger64v", + "glGetSynciv", + "glGetInteger64i_v", + "glGetBufferParameteri64v", + "glGenSamplers", + "glDeleteSamplers", + "glIsSampler", + "glBindSampler", + "glSamplerParameteri", + "glSamplerParameteriv", + "glSamplerParameterf", + "glSamplerParameterfv", + "glGetSamplerParameteriv", + "glGetSamplerParameterfv", + "glVertexAttribDivisor", + "glBindTransformFeedback", + "glDeleteTransformFeedbacks", + "glGenTransformFeedbacks", + "glIsTransformFeedback", + "glPauseTransformFeedback", + "glResumeTransformFeedback", + "glGetProgramBinary", + "glProgramBinary", + "glProgramParameteri", + "glInvalidateFramebuffer", + "glInvalidateSubFramebuffer", + "glTexStorage2D", + "glTexStorage3D", + "glGetInternalformativ" + ], + + "GLES31 core": [ + "glDispatchCompute", + "glDispatchComputeIndirect", + "glDrawArraysIndirect", + "glDrawElementsIndirect", + "glFramebufferParameteri", + "glGetFramebufferParameteriv", + "glGetProgramInterfaceiv", + "glGetProgramResourceIndex", + "glGetProgramResourceName", + "glGetProgramResourceiv", + "glGetProgramResourceLocation", + "glUseProgramStages", + "glActiveShaderProgram", + "glCreateShaderProgramv", + "glBindProgramPipeline", + "glDeleteProgramPipelines", + "glGenProgramPipelines", + "glIsProgramPipeline", + "glGetProgramPipelineiv", + "glProgramUniform1i", + "glProgramUniform2i", + "glProgramUniform3i", + "glProgramUniform4i", + "glProgramUniform1ui", + "glProgramUniform2ui", + "glProgramUniform3ui", + "glProgramUniform4ui", + "glProgramUniform1f", + "glProgramUniform2f", + "glProgramUniform3f", + "glProgramUniform4f", + "glProgramUniform1iv", + "glProgramUniform2iv", + "glProgramUniform3iv", + "glProgramUniform4iv", + "glProgramUniform1uiv", + "glProgramUniform2uiv", + "glProgramUniform3uiv", + "glProgramUniform4uiv", + "glProgramUniform1fv", + "glProgramUniform2fv", + "glProgramUniform3fv", + "glProgramUniform4fv", + "glProgramUniformMatrix2fv", + "glProgramUniformMatrix3fv", + "glProgramUniformMatrix4fv", + "glProgramUniformMatrix2x3fv", + "glProgramUniformMatrix3x2fv", + "glProgramUniformMatrix2x4fv", + "glProgramUniformMatrix4x2fv", + "glProgramUniformMatrix3x4fv", + "glProgramUniformMatrix4x3fv", + "glValidateProgramPipeline", + "glGetProgramPipelineInfoLog", + "glBindImageTexture", + "glGetBooleani_v", + "glMemoryBarrier", + "glMemoryBarrierByRegion", + "glTexStorage2DMultisample", + "glGetMultisamplefv", + "glSampleMaski", + "glGetTexLevelParameteriv", + "glGetTexLevelParameterfv", + "glBindVertexBuffer", + "glVertexAttribFormat", + "glVertexAttribIFormat", + "glVertexAttribBinding", + "glVertexBindingDivisor" + ], + + "EGL 1.0": [ + "eglChooseConfig", + "eglCopyBuffers", + "eglCreateContext", + "eglCreatePbufferSurface", + "eglCreatePixmapSurface", + "eglCreateWindowSurface", + "eglDestroyContext", + "eglDestroySurface", + "eglGetConfigAttrib", + "eglGetConfigs", + "eglGetCurrentDisplay", + "eglGetCurrentSurface", + "eglGetDisplay", + "eglGetError", + "eglGetProcAddress", + "eglInitialize", + "eglMakeCurrent", + "eglQueryContext", + "eglQueryString", + "eglQuerySurface", + "eglSwapBuffers", + "eglTerminate", + "eglWaitGL", + "eglWaitNative" + ], + + "EGL 1.1": [ + "eglBindTexImage", + "eglReleaseTexImage", + "eglSurfaceAttrib", + "eglSwapInterval" + ], + + "EGL 1.2": [ + "eglBindAPI", + "eglQueryAPI", + "eglCreatePbufferFromClientBuffer", + "eglReleaseThread", + "eglWaitClient" + ], + + "EGL 1.4": [ + "eglGetCurrentContext" + ], + + "EGL 1.5": [ + "eglCreateSync", + "eglDestroySync", + "eglClientWaitSync", + "eglGetSyncAttrib", + "eglCreateImage", + "eglDestroyImage", + "eglGetPlatformDisplay", + "eglCreatePlatformWindowSurface", + "eglCreatePlatformPixmapSurface", + "eglWaitSync" + ], + + "EGL_ANGLE_query_surface_pointer": [ + "eglQuerySurfacePointerANGLE" + ], + + "EGL_NV_post_sub_buffer": [ + "eglPostSubBufferNV" + ], + + "EGL_EXT_platform_base": [ + "eglGetPlatformDisplayEXT" + ], + + "EGL_EXT_device_query": [ + "eglQueryDisplayAttribEXT", + "eglQueryDeviceAttribEXT", + "eglQueryDeviceStringEXT" + ], + + "EGL_KHR_image_base/EGL_KHR_image": [ + "eglCreateImageKHR", + "eglDestroyImageKHR" + ], + + "EGL_EXT_device_creation": [ + "eglCreateDeviceANGLE", + "eglReleaseDeviceANGLE" + ], + + "EGL_KHR_stream": [ + "eglCreateStreamKHR", + "eglDestroyStreamKHR", + "eglStreamAttribKHR", + "eglQueryStreamKHR", + "eglQueryStreamu64KHR" + ], + + "EGL_KHR_stream_consumer_gltexture": [ + "eglStreamConsumerGLTextureExternalKHR", + "eglStreamConsumerAcquireKHR", + "eglStreamConsumerReleaseKHR" + ], + + "EGL_NV_stream_consumer_gltexture_yuv": [ + "eglStreamConsumerGLTextureExternalAttribsNV" + ], + + "EGL_ANGLE_stream_producer_d3d_texture_nv12": [ + "eglCreateStreamProducerD3DTextureNV12ANGLE", + "eglStreamPostD3DTextureNV12ANGLE" + ], + + "EGL_CHROMIUM_get_sync_values": [ + "eglGetSyncValuesCHROMIUM" + ], + + "EGL_EXT_swap_buffers_with_damage": [ + "eglSwapBuffersWithDamageEXT" + ], + + "EGL_ANGLE_program_cache_control": [ + "eglProgramCacheGetAttribANGLE", + "eglProgramCacheQueryANGLE", + "eglProgramCachePopulateANGLE", + "eglProgramCacheResizeANGLE" + ], + + "angle::Platform related entry points": [ + "ANGLEGetDisplayPlatform", + "ANGLEResetDisplayPlatform" + ] +} diff --git a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp index fa6c8b8d79..17e272301a 100644 --- a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp +++ b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.cpp @@ -25,6 +25,8 @@ #include "third_party/compiler/ArrayBoundsClamper.h" +#include "compiler/translator/IntermTraverse.h" + // The built-in 'clamp' instruction only accepts floats and returns a float. I // iterated a few times with our driver team who examined the output from our // compiler - they said the multiple casts generates more code than a single @@ -38,7 +40,11 @@ const char* kIntClampBegin = "// BEGIN: Generated code for array bounds clamping const char* kIntClampEnd = "// END: Generated code for array bounds clamping\n\n"; const char* kIntClampDefinition = "int webgl_int_clamp(int value, int minValue, int maxValue) { return ((value < minValue) ? minValue : ((value > maxValue) ? maxValue : value)); }\n\n"; -namespace { +namespace sh +{ + +namespace +{ class ArrayBoundsClamperMarker : public TIntermTraverser { public: @@ -105,3 +111,5 @@ void ArrayBoundsClamper::OutputClampingFunctionDefinition(TInfoSinkBase& out) co } out << kIntClampBegin << kIntClampDefinition << kIntClampEnd; } + +} // namespace sh diff --git a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h index 27917e6eec..a4c407f760 100644 --- a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h +++ b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h @@ -29,8 +29,12 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" -class ArrayBoundsClamper { -public: +namespace sh +{ + +class ArrayBoundsClamper +{ + public: ArrayBoundsClamper(); // Must be set before compiling any shaders to ensure consistency @@ -57,4 +61,6 @@ private: bool mArrayBoundsClampDefinitionNeeded; }; +} // namespace sh + #endif // THIRD_PARTY_COMPILER_ARRAYBOUNDSCLAMPER_H_ diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/LICENSE b/src/3rdparty/angle/src/third_party/libXNVCtrl/LICENSE new file mode 100644 index 0000000000..74324c0c6f --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/LICENSE @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ \ No newline at end of file diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.c b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.c new file mode 100644 index 0000000000..e984373947 --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.c @@ -0,0 +1,1240 @@ +/* + * Copyright (c) 2008 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Make sure that XTHREADS is defined, so that the + * LockDisplay/UnlockDisplay macros are expanded properly and the + * libXNVCtrl library properly protects the Display connection. + */ + +#if !defined(XTHREADS) +#define XTHREADS +#endif /* XTHREADS */ + +#define NEED_EVENTS +#define NEED_REPLIES +#include +#include +#include +#include +#include +#include +#include "NVCtrlLib.h" +#include "nv_control.h" + +#define NVCTRL_EXT_EXISTS 1 +#define NVCTRL_EXT_NEED_TARGET_SWAP 2 +#define NVCTRL_EXT_64_BIT_ATTRIBUTES 4 +#define NVCTRL_EXT_NEED_CHECK (1 << (sizeof(XPointer) - 1)) + +static XExtensionInfo _nvctrl_ext_info_data; +static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data; +static const char *nvctrl_extension_name = NV_CONTROL_NAME; + +#define XNVCTRLCheckExtension(dpy,i,val) \ + XextCheckExtension (dpy, i, nvctrl_extension_name, val) +#define XNVCTRLSimpleCheckExtension(dpy,i) \ + XextSimpleCheckExtension (dpy, i, nvctrl_extension_name) + +static int close_display(); +static uintptr_t version_flags(Display *dpy, XExtDisplayInfo *info); +static Bool wire_to_event(); +static /* const */ XExtensionHooks nvctrl_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + close_display, /* close_display */ + wire_to_event, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static XEXT_GENERATE_FIND_DISPLAY (find_display, nvctrl_ext_info, + nvctrl_extension_name, + &nvctrl_extension_hooks, + NV_CONTROL_EVENTS, + (XPointer)NVCTRL_EXT_NEED_CHECK) + +static XEXT_GENERATE_CLOSE_DISPLAY (close_display, nvctrl_ext_info) + +/* + * NV-CONTROL versions 1.8 and 1.9 pack the target_type and target_id + * fields in reversed order. In order to talk to one of these servers, + * we need to swap these fields. + */ + +static void XNVCTRLCheckTargetData(Display *dpy, XExtDisplayInfo *info, + int *target_type, int *target_id) +{ + uintptr_t flags = version_flags(dpy, info); + + /* We need to swap the target_type and target_id */ + if (flags & NVCTRL_EXT_NEED_TARGET_SWAP) { + int tmp; + tmp = *target_type; + *target_type = *target_id; + *target_id = tmp; + } +} + + +Bool XNVCTRLQueryExtension ( + Display *dpy, + int *event_basep, + int *error_basep +){ + XExtDisplayInfo *info = find_display (dpy); + + if (XextHasExtension(info)) { + if (event_basep) *event_basep = info->codes->first_event; + if (error_basep) *error_basep = info->codes->first_error; + return True; + } else { + return False; + } +} + +/* + * Retrieve any cached flags that depend on the version of the NV-CONTROL + * extension. + */ + +static uintptr_t version_flags(Display *dpy, XExtDisplayInfo *info) +{ + uintptr_t data = (uintptr_t)info->data; + + /* If necessary, determine the NV-CONTROL version */ + if (data & NVCTRL_EXT_NEED_CHECK) { + int major, minor; + data = 0; + if (XNVCTRLQueryVersion(dpy, &major, &minor)) { + data |= NVCTRL_EXT_EXISTS; + if (major == 1 && (minor == 8 || minor == 9)) { + data |= NVCTRL_EXT_NEED_TARGET_SWAP; + } + if ((major > 1) || ((major == 1) && (minor > 20))) { + data |= NVCTRL_EXT_64_BIT_ATTRIBUTES; + } + } + + info->data = (XPointer)data; + } + + return data; +} + +Bool XNVCTRLQueryVersion ( + Display *dpy, + int *major, + int *minor +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryExtensionReply rep; + xnvCtrlQueryExtensionReq *req; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlQueryExtension, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryExtension; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + if (major) *major = rep.major; + if (minor) *minor = rep.minor; + UnlockDisplay (dpy); + SyncHandle (); + return True; +} + + +Bool XNVCTRLIsNvScreen ( + Display *dpy, + int screen +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlIsNvReply rep; + xnvCtrlIsNvReq *req; + Bool isnv; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlIsNv, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlIsNv; + req->screen = screen; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + isnv = rep.isnv; + UnlockDisplay (dpy); + SyncHandle (); + return isnv; +} + + +Bool XNVCTRLQueryTargetCount ( + Display *dpy, + int target_type, + int *value +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryTargetCountReply rep; + xnvCtrlQueryTargetCountReq *req; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlQueryTargetCount, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryTargetCount; + req->target_type = target_type; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + if (value) *value = rep.count; + UnlockDisplay (dpy); + SyncHandle (); + return True; +} + + +void XNVCTRLSetTargetAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int value +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSetAttributeReq *req; + + XNVCTRLSimpleCheckExtension (dpy, info); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + LockDisplay (dpy); + GetReq (nvCtrlSetAttribute, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSetAttribute; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + req->value = value; + UnlockDisplay (dpy); + SyncHandle (); +} + +void XNVCTRLSetAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int value +){ + XNVCTRLSetTargetAttribute (dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, + display_mask, attribute, value); +} + + +Bool XNVCTRLSetTargetAttributeAndGetStatus ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int value +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSetAttributeAndGetStatusReq *req; + xnvCtrlSetAttributeAndGetStatusReply rep; + Bool success; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlSetAttributeAndGetStatus, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSetAttributeAndGetStatus; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + req->value = value; + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + UnlockDisplay (dpy); + SyncHandle (); + + success = rep.flags; + return success; +} + +Bool XNVCTRLSetAttributeAndGetStatus ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int value +){ + return XNVCTRLSetTargetAttributeAndGetStatus(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, value); +} + + +Bool XNVCTRLQueryTargetAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int *value +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryAttributeReply rep; + xnvCtrlQueryAttributeReq *req; + Bool exists; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + LockDisplay (dpy); + GetReq (nvCtrlQueryAttribute, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryAttribute; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + exists = rep.flags; + if (exists && value) *value = rep.value; + UnlockDisplay (dpy); + SyncHandle (); + return exists; +} + +Bool XNVCTRLQueryAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int *value +){ + return XNVCTRLQueryTargetAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, attribute, value); +} + + +Bool XNVCTRLQueryTargetAttribute64 ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int64_t *value +){ + XExtDisplayInfo *info = find_display(dpy); + xnvCtrlQueryAttribute64Reply rep; + xnvCtrlQueryAttributeReq *req; + Bool exists; + + if (!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension(dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + LockDisplay(dpy); + GetReq(nvCtrlQueryAttribute, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryAttribute64; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + exists = rep.flags; + if (exists && value) *value = rep.value_64; + UnlockDisplay(dpy); + SyncHandle(); + return exists; +} + + +Bool XNVCTRLQueryTargetStringAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char **ptr +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryStringAttributeReply rep; + xnvCtrlQueryStringAttributeReq *req; + Bool exists; + int length, numbytes, slop; + + if (!ptr) return False; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + LockDisplay (dpy); + GetReq (nvCtrlQueryStringAttribute, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryStringAttribute; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + length = rep.length; + numbytes = rep.n; + slop = numbytes & 3; + exists = rep.flags; + if (exists) { + *ptr = (char *) Xmalloc(numbytes); + } + if (!exists || !*ptr) { + _XEatData(dpy, length); + UnlockDisplay (dpy); + SyncHandle (); + return False; + } else { + _XRead(dpy, (char *) *ptr, numbytes); + if (slop) _XEatData(dpy, 4-slop); + } + UnlockDisplay (dpy); + SyncHandle (); + return exists; +} + +Bool XNVCTRLQueryStringAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + char **ptr +){ + return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, ptr); +} + + +Bool XNVCTRLSetTargetStringAttribute ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *ptr +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSetStringAttributeReq *req; + xnvCtrlSetStringAttributeReply rep; + int size; + Bool success; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + size = strlen(ptr)+1; + + LockDisplay (dpy); + GetReq (nvCtrlSetStringAttribute, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSetStringAttribute; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + req->length += ((size + 3) & ~3) >> 2; + req->num_bytes = size; + Data(dpy, ptr, size); + + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + UnlockDisplay (dpy); + SyncHandle (); + + success = rep.flags; + return success; +} + +Bool XNVCTRLSetStringAttribute ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + char *ptr +){ + return XNVCTRLSetTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, ptr); +} + + +static Bool XNVCTRLQueryValidTargetAttributeValues32 ( + Display *dpy, + XExtDisplayInfo *info, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + xnvCtrlQueryValidAttributeValuesReply rep; + xnvCtrlQueryValidAttributeValuesReq *req; + Bool exists; + + LockDisplay (dpy); + GetReq (nvCtrlQueryValidAttributeValues, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryValidAttributeValues; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + exists = rep.flags; + if (exists) { + values->type = rep.attr_type; + if (rep.attr_type == ATTRIBUTE_TYPE_RANGE) { + values->u.range.min = rep.min; + values->u.range.max = rep.max; + } + if (rep.attr_type == ATTRIBUTE_TYPE_INT_BITS) { + values->u.bits.ints = rep.bits; + } + values->permissions = rep.perms; + } + UnlockDisplay (dpy); + SyncHandle (); + return exists; +} + + +Bool XNVCTRLQueryValidTargetStringAttributeValues ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + XExtDisplayInfo *info = find_display(dpy); + Bool exists; + xnvCtrlQueryValidAttributeValuesReply rep; + xnvCtrlQueryValidAttributeValuesReq *req; + + if (!values) return False; + + if (!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq (nvCtrlQueryValidAttributeValues, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryValidStringAttributeValues; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + exists = rep.flags; + if (exists) { + values->type = rep.attr_type; + values->permissions = rep.perms; + } + UnlockDisplay(dpy); + SyncHandle(); + return exists; +} + + +static Bool XNVCTRLQueryValidTargetAttributeValues64 ( + Display *dpy, + XExtDisplayInfo *info, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + xnvCtrlQueryValidAttributeValues64Reply rep; + xnvCtrlQueryValidAttributeValuesReq *req; + Bool exists; + + LockDisplay(dpy); + GetReq(nvCtrlQueryValidAttributeValues, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryValidAttributeValues64; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply(dpy, (xReply *)&rep, + sz_xnvCtrlQueryValidAttributeValues64Reply_extra, + xTrue)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + exists = rep.flags; + if (exists) { + values->type = rep.attr_type; + if (rep.attr_type == ATTRIBUTE_TYPE_RANGE) { + values->u.range.min = rep.min_64; + values->u.range.max = rep.max_64; + } + if (rep.attr_type == ATTRIBUTE_TYPE_INT_BITS) { + values->u.bits.ints = rep.bits_64; + } + values->permissions = rep.perms; + } + UnlockDisplay(dpy); + SyncHandle(); + return exists; +} + +Bool XNVCTRLQueryValidTargetAttributeValues ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + XExtDisplayInfo *info = find_display(dpy); + Bool exists; + uintptr_t flags; + + if (!values) return False; + + if (!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension(dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + flags = version_flags(dpy,info); + + if (!(flags & NVCTRL_EXT_EXISTS)) + return False; + + if (flags & NVCTRL_EXT_64_BIT_ATTRIBUTES) { + exists = XNVCTRLQueryValidTargetAttributeValues64(dpy, info, + target_type, + target_id, + display_mask, + attribute, + values); + } else { + exists = XNVCTRLQueryValidTargetAttributeValues32(dpy, info, + target_type, + target_id, + display_mask, + attribute, + values); + } + return exists; +} + + +Bool XNVCTRLQueryValidAttributeValues ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values +){ + return XNVCTRLQueryValidTargetAttributeValues(dpy, + NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, values); +} + + +static Bool QueryAttributePermissionsInternal ( + Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions, + unsigned int reqType +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryAttributePermissionsReply rep; + xnvCtrlQueryAttributePermissionsReq *req; + Bool exists; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(nvCtrlQueryAttributePermissions, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = reqType; + req->attribute = attribute; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { + UnlockDisplay (dpy); + SyncHandle(); + return False; + } + exists = rep.flags; + if (exists && permissions) { + permissions->type = rep.attr_type; + permissions->permissions = rep.perms; + } + UnlockDisplay(dpy); + SyncHandle(); + return exists; +} + + +Bool XNVCTRLQueryAttributePermissions ( + Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions +){ + return QueryAttributePermissionsInternal(dpy, + attribute, + permissions, + X_nvCtrlQueryAttributePermissions); +} + + +Bool XNVCTRLQueryStringAttributePermissions ( + Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions +){ + return QueryAttributePermissionsInternal(dpy, + attribute, + permissions, + X_nvCtrlQueryStringAttributePermissions); +} + + +Bool XNVCTRLQueryBinaryDataAttributePermissions ( + Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions +){ + return QueryAttributePermissionsInternal(dpy, + attribute, + permissions, + X_nvCtrlQueryBinaryDataAttributePermissions); +} + + +Bool XNVCTRLQueryStringOperationAttributePermissions ( + Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions +){ + return QueryAttributePermissionsInternal(dpy, + attribute, + permissions, + X_nvCtrlQueryStringOperationAttributePermissions); +} + + +void XNVCTRLSetGvoColorConversion ( + Display *dpy, + int screen, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3] +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSetGvoColorConversionReq *req; + + XNVCTRLSimpleCheckExtension (dpy, info); + + LockDisplay (dpy); + GetReq (nvCtrlSetGvoColorConversion, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSetGvoColorConversion; + req->screen = screen; + + req->cscMatrix_y_r = colorMatrix[0][0]; + req->cscMatrix_y_g = colorMatrix[0][1]; + req->cscMatrix_y_b = colorMatrix[0][2]; + + req->cscMatrix_cr_r = colorMatrix[1][0]; + req->cscMatrix_cr_g = colorMatrix[1][1]; + req->cscMatrix_cr_b = colorMatrix[1][2]; + + req->cscMatrix_cb_r = colorMatrix[2][0]; + req->cscMatrix_cb_g = colorMatrix[2][1]; + req->cscMatrix_cb_b = colorMatrix[2][2]; + + req->cscOffset_y = colorOffset[0]; + req->cscOffset_cr = colorOffset[1]; + req->cscOffset_cb = colorOffset[2]; + + req->cscScale_y = colorScale[0]; + req->cscScale_cr = colorScale[1]; + req->cscScale_cb = colorScale[2]; + + UnlockDisplay (dpy); + SyncHandle (); +} + + +Bool XNVCTRLQueryGvoColorConversion ( + Display *dpy, + int screen, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3] +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryGvoColorConversionReply rep; + xnvCtrlQueryGvoColorConversionReq *req; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + + GetReq (nvCtrlQueryGvoColorConversion, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryGvoColorConversion; + req->screen = screen; + + if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + + _XRead(dpy, (char *)(colorMatrix), 36); + _XRead(dpy, (char *)(colorOffset), 12); + _XRead(dpy, (char *)(colorScale), 12); + + UnlockDisplay (dpy); + SyncHandle (); + + return True; +} + + +Bool XNVCtrlSelectTargetNotify ( + Display *dpy, + int target_type, + int target_id, + int notify_type, + Bool onoff +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSelectTargetNotifyReq *req; + + if(!XextHasExtension (info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlSelectTargetNotify, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSelectTargetNotify; + req->target_type = target_type; + req->target_id = target_id; + req->notifyType = notify_type; + req->onoff = onoff; + UnlockDisplay (dpy); + SyncHandle (); + + return True; +} + + +Bool XNVCtrlSelectNotify ( + Display *dpy, + int screen, + int type, + Bool onoff +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlSelectNotifyReq *req; + + if(!XextHasExtension (info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + + LockDisplay (dpy); + GetReq (nvCtrlSelectNotify, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlSelectNotify; + req->screen = screen; + req->notifyType = type; + req->onoff = onoff; + UnlockDisplay (dpy); + SyncHandle (); + + return True; +} + +Bool XNVCTRLQueryTargetBinaryData ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len +){ + XExtDisplayInfo *info = find_display (dpy); + xnvCtrlQueryBinaryDataReply rep; + xnvCtrlQueryBinaryDataReq *req; + Bool exists; + int length, numbytes, slop; + + if (!ptr) return False; + + if(!XextHasExtension(info)) + return False; + + XNVCTRLCheckExtension (dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + LockDisplay (dpy); + GetReq (nvCtrlQueryBinaryData, req); + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlQueryBinaryData; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay (dpy); + SyncHandle (); + return False; + } + length = rep.length; + numbytes = rep.n; + slop = numbytes & 3; + exists = rep.flags; + if (exists) { + *ptr = (unsigned char *) Xmalloc(numbytes); + } + if (!exists || !*ptr) { + _XEatData(dpy, length); + UnlockDisplay (dpy); + SyncHandle (); + return False; + } else { + _XRead(dpy, (char *) *ptr, numbytes); + if (slop) _XEatData(dpy, 4-slop); + } + if (len) *len = numbytes; + UnlockDisplay (dpy); + SyncHandle (); + return exists; +} + +Bool XNVCTRLQueryBinaryData ( + Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len +){ + return XNVCTRLQueryTargetBinaryData(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, + screen, display_mask, + attribute, ptr, len); +} + +Bool XNVCTRLStringOperation ( + Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *pIn, + char **ppOut +) { + XExtDisplayInfo *info = find_display(dpy); + xnvCtrlStringOperationReq *req; + xnvCtrlStringOperationReply rep; + Bool ret; + int inSize, outSize, length, slop; + + if (!XextHasExtension(info)) + return False; + + if (!ppOut) + return False; + + *ppOut = NULL; + + XNVCTRLCheckExtension(dpy, info, False); + XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); + + if (pIn) { + inSize = strlen(pIn) + 1; + } else { + inSize = 0; + } + + LockDisplay(dpy); + GetReq(nvCtrlStringOperation, req); + + req->reqType = info->codes->major_opcode; + req->nvReqType = X_nvCtrlStringOperation; + req->target_type = target_type; + req->target_id = target_id; + req->display_mask = display_mask; + req->attribute = attribute; + + req->length += ((inSize + 3) & ~3) >> 2; + req->num_bytes = inSize; + + if (pIn) { + Data(dpy, pIn, inSize); + } + + if (!_XReply (dpy, (xReply *) &rep, 0, False)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + length = rep.length; + outSize = rep.num_bytes; + slop = outSize & 3; + + if (outSize) *ppOut = (char *) Xmalloc(outSize); + + if (!*ppOut) { + _XEatData(dpy, length); + } else { + _XRead(dpy, (char *) *ppOut, outSize); + if (slop) _XEatData(dpy, 4-slop); + } + + ret = rep.ret; + + UnlockDisplay(dpy); + SyncHandle(); + + return ret; +} + + +static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire) +{ + XExtDisplayInfo *info = find_display (dpy); + XNVCtrlEvent *re; + xnvctrlEvent *event; + XNVCtrlEventTarget *reTarget; + xnvctrlEventTarget *eventTarget; + XNVCtrlEventTargetAvailability *reTargetAvailability; + XNVCtrlStringEventTarget *reTargetString; + XNVCtrlBinaryEventTarget *reTargetBinary; + + XNVCTRLCheckExtension (dpy, info, False); + + switch ((wire->u.u.type & 0x7F) - info->codes->first_event) { + case ATTRIBUTE_CHANGED_EVENT: + re = (XNVCtrlEvent *) host; + event = (xnvctrlEvent *) wire; + re->attribute_changed.type = event->u.u.type & 0x7F; + re->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) event); + re->attribute_changed.send_event = ((event->u.u.type & 0x80) != 0); + re->attribute_changed.display = dpy; + re->attribute_changed.time = event->u.attribute_changed.time; + re->attribute_changed.screen = event->u.attribute_changed.screen; + re->attribute_changed.display_mask = + event->u.attribute_changed.display_mask; + re->attribute_changed.attribute = event->u.attribute_changed.attribute; + re->attribute_changed.value = event->u.attribute_changed.value; + break; + case TARGET_ATTRIBUTE_CHANGED_EVENT: + reTarget = (XNVCtrlEventTarget *) host; + eventTarget = (xnvctrlEventTarget *) wire; + reTarget->attribute_changed.type = eventTarget->u.u.type & 0x7F; + reTarget->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget); + reTarget->attribute_changed.send_event = + ((eventTarget->u.u.type & 0x80) != 0); + reTarget->attribute_changed.display = dpy; + reTarget->attribute_changed.time = + eventTarget->u.attribute_changed.time; + reTarget->attribute_changed.target_type = + eventTarget->u.attribute_changed.target_type; + reTarget->attribute_changed.target_id = + eventTarget->u.attribute_changed.target_id; + reTarget->attribute_changed.display_mask = + eventTarget->u.attribute_changed.display_mask; + reTarget->attribute_changed.attribute = + eventTarget->u.attribute_changed.attribute; + reTarget->attribute_changed.value = + eventTarget->u.attribute_changed.value; + break; + case TARGET_ATTRIBUTE_AVAILABILITY_CHANGED_EVENT: + reTargetAvailability = (XNVCtrlEventTargetAvailability *) host; + eventTarget = (xnvctrlEventTarget *) wire; + reTargetAvailability->attribute_changed.type = + eventTarget->u.u.type & 0x7F; + reTargetAvailability->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget); + reTargetAvailability->attribute_changed.send_event = + ((eventTarget->u.u.type & 0x80) != 0); + reTargetAvailability->attribute_changed.display = dpy; + reTargetAvailability->attribute_changed.time = + eventTarget->u.availability_changed.time; + reTargetAvailability->attribute_changed.target_type = + eventTarget->u.availability_changed.target_type; + reTargetAvailability->attribute_changed.target_id = + eventTarget->u.availability_changed.target_id; + reTargetAvailability->attribute_changed.display_mask = + eventTarget->u.availability_changed.display_mask; + reTargetAvailability->attribute_changed.attribute = + eventTarget->u.availability_changed.attribute; + reTargetAvailability->attribute_changed.availability = + eventTarget->u.availability_changed.availability; + reTargetAvailability->attribute_changed.value = + eventTarget->u.availability_changed.value; + break; + case TARGET_STRING_ATTRIBUTE_CHANGED_EVENT: + reTargetString = (XNVCtrlStringEventTarget *) host; + eventTarget = (xnvctrlEventTarget *) wire; + reTargetString->attribute_changed.type = eventTarget->u.u.type & 0x7F; + reTargetString->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget); + reTargetString->attribute_changed.send_event = + ((eventTarget->u.u.type & 0x80) != 0); + reTargetString->attribute_changed.display = dpy; + reTargetString->attribute_changed.time = + eventTarget->u.attribute_changed.time; + reTargetString->attribute_changed.target_type = + eventTarget->u.attribute_changed.target_type; + reTargetString->attribute_changed.target_id = + eventTarget->u.attribute_changed.target_id; + reTargetString->attribute_changed.display_mask = + eventTarget->u.attribute_changed.display_mask; + reTargetString->attribute_changed.attribute = + eventTarget->u.attribute_changed.attribute; + break; + case TARGET_BINARY_ATTRIBUTE_CHANGED_EVENT: + reTargetBinary = (XNVCtrlBinaryEventTarget *) host; + eventTarget = (xnvctrlEventTarget *) wire; + reTargetBinary->attribute_changed.type = eventTarget->u.u.type & 0x7F; + reTargetBinary->attribute_changed.serial = + _XSetLastRequestRead(dpy, (xGenericReply*) eventTarget); + reTargetBinary->attribute_changed.send_event = + ((eventTarget->u.u.type & 0x80) != 0); + reTargetBinary->attribute_changed.display = dpy; + reTargetBinary->attribute_changed.time = + eventTarget->u.attribute_changed.time; + reTargetBinary->attribute_changed.target_type = + eventTarget->u.attribute_changed.target_type; + reTargetBinary->attribute_changed.target_id = + eventTarget->u.attribute_changed.target_id; + reTargetBinary->attribute_changed.display_mask = + eventTarget->u.attribute_changed.display_mask; + reTargetBinary->attribute_changed.attribute = + eventTarget->u.attribute_changed.attribute; + break; + + default: + return False; + } + + return True; +} + diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.h b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.h new file mode 100644 index 0000000000..7bd7ab7a33 --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrl.h @@ -0,0 +1,4365 @@ +/* + * Copyright (c) 2010 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __NVCTRL_H +#define __NVCTRL_H + +#include + +/**************************************************************************/ + +/* + * Attribute Targets + * + * Targets define attribute groups. For example, some attributes are only + * valid to set on a GPU, others are only valid when talking about an + * X Screen. Target types are then what is used to identify the target + * group of the attribute you wish to set/query. + * + * Here are the supported target types: + */ + +#define NV_CTRL_TARGET_TYPE_X_SCREEN 0 +#define NV_CTRL_TARGET_TYPE_GPU 1 +#define NV_CTRL_TARGET_TYPE_FRAMELOCK 2 +#define NV_CTRL_TARGET_TYPE_VCSC 3 /* Visual Computing System */ +#define NV_CTRL_TARGET_TYPE_GVI 4 +#define NV_CTRL_TARGET_TYPE_COOLER 5 /* e.g., fan */ +#define NV_CTRL_TARGET_TYPE_THERMAL_SENSOR 6 +#define NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER 7 +#define NV_CTRL_TARGET_TYPE_DISPLAY 8 + +/**************************************************************************/ + +/* + * Attributes + * + * Some attributes may only be read; some may require a display_mask + * argument and others may be valid only for specific target types. + * This information is encoded in the "permission" comment after each + * attribute #define, and can be queried at run time with + * XNVCTRLQueryValidAttributeValues() and/or + * XNVCTRLQueryValidTargetAttributeValues() + * + * Key to Integer Attribute "Permissions": + * + * R: The attribute is readable (in general, all attributes will be + * readable) + * + * W: The attribute is writable (attributes may not be writable for + * various reasons: they represent static system information, they + * can only be changed by changing an XF86Config option, etc). + * + * D: The attribute requires the display mask argument. The + * attributes NV_CTRL_CONNECTED_DISPLAYS and NV_CTRL_ENABLED_DISPLAYS + * will be a bitmask of what display devices are connected and what + * display devices are enabled for use in X, respectively. Each bit + * in the bitmask represents a display device; it is these bits which + * should be used as the display_mask when dealing with attributes + * designated with "D" below. For attributes that do not require the + * display mask, the argument is ignored. + * + * Alternatively, NV-CONTROL versions 1.27 and greater allow these + * attributes to be accessed via display target types, in which case + * the display_mask is ignored. + * + * G: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GPU + * target type via XNVCTRLQueryTargetAttribute(). + * + * F: The attribute may be queried using an NV_CTRL_TARGET_TYPE_FRAMELOCK + * target type via XNVCTRLQueryTargetAttribute(). + * + * X: When Xinerama is enabled, this attribute is kept consistent across + * all Physical X Screens; assignment of this attribute will be + * broadcast by the NVIDIA X Driver to all X Screens. + * + * V: The attribute may be queried using an NV_CTRL_TARGET_TYPE_VCSC + * target type via XNVCTRLQueryTargetAttribute(). + * + * I: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GVI target type + * via XNVCTRLQueryTargetAttribute(). + * + * Q: The attribute is a 64-bit integer attribute; use the 64-bit versions + * of the appropriate query interfaces. + * + * C: The attribute may be queried using an NV_CTRL_TARGET_TYPE_COOLER target + * type via XNVCTRLQueryTargetAttribute(). + * + * S: The attribute may be queried using an NV_CTRL_TARGET_TYPE_THERMAL_SENSOR + * target type via XNVCTRLQueryTargetAttribute(). + * + * T: The attribute may be queried using an + * NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER target type + * via XNVCTRLQueryTargetAttribute(). + * + * NOTE: Unless mentioned otherwise, all attributes may be queried using + * an NV_CTRL_TARGET_TYPE_X_SCREEN target type via + * XNVCTRLQueryTargetAttribute(). + */ + +/**************************************************************************/ + +/* + * Integer attributes: + * + * Integer attributes can be queried through the XNVCTRLQueryAttribute() and + * XNVCTRLQueryTargetAttribute() function calls. + * + * Integer attributes can be set through the XNVCTRLSetAttribute() and + * XNVCTRLSetTargetAttribute() function calls. + * + * Unless otherwise noted, all integer attributes can be queried/set + * using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot + * take an NV_CTRL_TARGET_TYPE_X_SCREEN also cannot be queried/set through + * XNVCTRLQueryAttribute()/XNVCTRLSetAttribute() (Since these assume + * an X Screen target). + */ + +/* + * NV_CTRL_FLATPANEL_SCALING - not supported + */ + +#define NV_CTRL_FLATPANEL_SCALING 2 /* RWDG */ +#define NV_CTRL_FLATPANEL_SCALING_DEFAULT 0 +#define NV_CTRL_FLATPANEL_SCALING_NATIVE 1 +#define NV_CTRL_FLATPANEL_SCALING_SCALED 2 +#define NV_CTRL_FLATPANEL_SCALING_CENTERED 3 +#define NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED 4 + +/* + * NV_CTRL_FLATPANEL_DITHERING is deprecated; NV_CTRL_DITHERING should + * be used instead. + */ + +#define NV_CTRL_FLATPANEL_DITHERING 3 /* RWDG */ +#define NV_CTRL_FLATPANEL_DITHERING_DEFAULT 0 +#define NV_CTRL_FLATPANEL_DITHERING_ENABLED 1 +#define NV_CTRL_FLATPANEL_DITHERING_DISABLED 2 + +/* + * NV_CTRL_DITHERING - the requested dithering configuration; + * possible values are: + * + * 0: auto (the driver will decide when to dither) + * 1: enabled (the driver will always dither when possible) + * 2: disabled (the driver will never dither) + */ + +#define NV_CTRL_DITHERING 3 /* RWDG */ +#define NV_CTRL_DITHERING_AUTO 0 +#define NV_CTRL_DITHERING_ENABLED 1 +#define NV_CTRL_DITHERING_DISABLED 2 + +/* + * NV_CTRL_DIGITAL_VIBRANCE - sets the digital vibrance level for the + * specified display device. + */ + +#define NV_CTRL_DIGITAL_VIBRANCE 4 /* RWDG */ + +/* + * NV_CTRL_BUS_TYPE - returns the bus type through which the specified device + * is connected to the computer. + * When this attribute is queried on an X screen target, the bus type of the + * GPU driving the X screen is returned. + */ + +#define NV_CTRL_BUS_TYPE 5 /* R--GI */ +#define NV_CTRL_BUS_TYPE_AGP 0 +#define NV_CTRL_BUS_TYPE_PCI 1 +#define NV_CTRL_BUS_TYPE_PCI_EXPRESS 2 +#define NV_CTRL_BUS_TYPE_INTEGRATED 3 + +/* + * NV_CTRL_VIDEO_RAM - returns the total amount of memory available + * to the specified GPU (or the GPU driving the specified X + * screen). Note: if the GPU supports TurboCache(TM), the value + * reported may exceed the amount of video memory installed on the + * GPU. The value reported for integrated GPUs may likewise exceed + * the amount of dedicated system memory set aside by the system + * BIOS for use by the integrated GPU. + */ + +#define NV_CTRL_VIDEO_RAM 6 /* R--G */ + +/* + * NV_CTRL_IRQ - returns the interrupt request line used by the specified + * device. + * When this attribute is queried on an X screen target, the IRQ of the GPU + * driving the X screen is returned. + */ + +#define NV_CTRL_IRQ 7 /* R--GI */ + +/* + * NV_CTRL_OPERATING_SYSTEM - returns the operating system on which + * the X server is running. + */ + +#define NV_CTRL_OPERATING_SYSTEM 8 /* R--G */ +#define NV_CTRL_OPERATING_SYSTEM_LINUX 0 +#define NV_CTRL_OPERATING_SYSTEM_FREEBSD 1 +#define NV_CTRL_OPERATING_SYSTEM_SUNOS 2 + +/* + * NV_CTRL_SYNC_TO_VBLANK - enables sync to vblank for OpenGL clients. + * This setting is only applied to OpenGL clients that are started + * after this setting is applied. + */ + +#define NV_CTRL_SYNC_TO_VBLANK 9 /* RW-X */ +#define NV_CTRL_SYNC_TO_VBLANK_OFF 0 +#define NV_CTRL_SYNC_TO_VBLANK_ON 1 + +/* + * NV_CTRL_LOG_ANISO - enables anisotropic filtering for OpenGL + * clients; on some NVIDIA hardware, this can only be enabled or + * disabled; on other hardware different levels of anisotropic + * filtering can be specified. This setting is only applied to OpenGL + * clients that are started after this setting is applied. + */ + +#define NV_CTRL_LOG_ANISO 10 /* RW-X */ + +/* + * NV_CTRL_FSAA_MODE - the FSAA setting for OpenGL clients; possible + * FSAA modes: + * + * NV_CTRL_FSAA_MODE_2x "2x Bilinear Multisampling" + * NV_CTRL_FSAA_MODE_2x_5t "2x Quincunx Multisampling" + * NV_CTRL_FSAA_MODE_15x15 "1.5 x 1.5 Supersampling" + * NV_CTRL_FSAA_MODE_2x2 "2 x 2 Supersampling" + * NV_CTRL_FSAA_MODE_4x "4x Bilinear Multisampling" + * NV_CTRL_FSAA_MODE_4x_9t "4x Gaussian Multisampling" + * NV_CTRL_FSAA_MODE_8x "2x Bilinear Multisampling by 4x Supersampling" + * NV_CTRL_FSAA_MODE_16x "4x Bilinear Multisampling by 4x Supersampling" + * NV_CTRL_FSAA_MODE_8xS "4x Multisampling by 2x Supersampling" + * + * This setting is only applied to OpenGL clients that are started + * after this setting is applied. + */ + +#define NV_CTRL_FSAA_MODE 11 /* RW-X */ +#define NV_CTRL_FSAA_MODE_NONE 0 +#define NV_CTRL_FSAA_MODE_2x 1 +#define NV_CTRL_FSAA_MODE_2x_5t 2 +#define NV_CTRL_FSAA_MODE_15x15 3 +#define NV_CTRL_FSAA_MODE_2x2 4 +#define NV_CTRL_FSAA_MODE_4x 5 +#define NV_CTRL_FSAA_MODE_4x_9t 6 +#define NV_CTRL_FSAA_MODE_8x 7 +#define NV_CTRL_FSAA_MODE_16x 8 +#define NV_CTRL_FSAA_MODE_8xS 9 +#define NV_CTRL_FSAA_MODE_8xQ 10 +#define NV_CTRL_FSAA_MODE_16xS 11 +#define NV_CTRL_FSAA_MODE_16xQ 12 +#define NV_CTRL_FSAA_MODE_32xS 13 +#define NV_CTRL_FSAA_MODE_32x 14 +#define NV_CTRL_FSAA_MODE_64xS 15 +#define NV_CTRL_FSAA_MODE_MAX NV_CTRL_FSAA_MODE_64xS + +/* + * NV_CTRL_TEXTURE_SHARPEN - enables texture sharpening for OpenGL + * clients. This setting is only applied to OpenGL clients that are + * started after this setting is applied. + */ + +#define NV_CTRL_TEXTURE_SHARPEN 12 /* RW-X */ +#define NV_CTRL_TEXTURE_SHARPEN_OFF 0 +#define NV_CTRL_TEXTURE_SHARPEN_ON 1 + +/* + * NV_CTRL_UBB - returns whether UBB is enabled for the specified X + * screen. + */ + +#define NV_CTRL_UBB 13 /* R-- */ +#define NV_CTRL_UBB_OFF 0 +#define NV_CTRL_UBB_ON 1 + +/* + * NV_CTRL_OVERLAY - returns whether the RGB overlay is enabled for + * the specified X screen. + */ + +#define NV_CTRL_OVERLAY 14 /* R-- */ +#define NV_CTRL_OVERLAY_OFF 0 +#define NV_CTRL_OVERLAY_ON 1 + +/* + * NV_CTRL_STEREO - returns whether stereo (and what type) is enabled + * for the specified X screen. + */ + +#define NV_CTRL_STEREO 16 /* R-- */ +#define NV_CTRL_STEREO_OFF 0 +#define NV_CTRL_STEREO_DDC 1 +#define NV_CTRL_STEREO_BLUELINE 2 +#define NV_CTRL_STEREO_DIN 3 +#define NV_CTRL_STEREO_PASSIVE_EYE_PER_DPY 4 +#define NV_CTRL_STEREO_VERTICAL_INTERLACED 5 +#define NV_CTRL_STEREO_COLOR_INTERLACED 6 +#define NV_CTRL_STEREO_HORIZONTAL_INTERLACED 7 +#define NV_CTRL_STEREO_CHECKERBOARD_PATTERN 8 +#define NV_CTRL_STEREO_INVERSE_CHECKERBOARD_PATTERN 9 +#define NV_CTRL_STEREO_3D_VISION 10 +#define NV_CTRL_STEREO_3D_VISION_PRO 11 + +/* + * NV_CTRL_EMULATE - controls OpenGL software emulation of future + * NVIDIA GPUs. + */ + +#define NV_CTRL_EMULATE 17 /* RW- */ +#define NV_CTRL_EMULATE_NONE 0 + +/* + * NV_CTRL_TWINVIEW - returns whether TwinView is enabled for the + * specified X screen. + */ + +#define NV_CTRL_TWINVIEW 18 /* R-- */ +#define NV_CTRL_TWINVIEW_NOT_ENABLED 0 +#define NV_CTRL_TWINVIEW_ENABLED 1 + +/* + * NV_CTRL_CONNECTED_DISPLAYS - returns a display mask indicating the last + * cached state of the display devices connected to the GPU or GPU driving + * the specified X screen. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_CONNECTED_DISPLAYS 19 /* R--G */ + +/* + * NV_CTRL_ENABLED_DISPLAYS - returns a display mask indicating what + * display devices are enabled for use on the specified X screen or + * GPU. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_ENABLED_DISPLAYS 20 /* R--G */ + +/**************************************************************************/ +/* + * Integer attributes specific to configuring Frame Lock on boards that + * support it. + */ + +/* + * NV_CTRL_FRAMELOCK - returns whether the underlying GPU supports + * Frame Lock. All of the other frame lock attributes are only + * applicable if NV_CTRL_FRAMELOCK is _SUPPORTED. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_FRAMELOCK 21 /* R--G */ +#define NV_CTRL_FRAMELOCK_NOT_SUPPORTED 0 +#define NV_CTRL_FRAMELOCK_SUPPORTED 1 + +/* + * NV_CTRL_FRAMELOCK_MASTER - get/set which display device to use + * as the frame lock master for the entire sync group. Note that only + * one node in the sync group should be configured as the master. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_MASTER 22 /* RW-G */ + +/* These are deprecated. NV_CTRL_FRAMELOCK_MASTER now takes and + returns a display mask as value. */ +#define NV_CTRL_FRAMELOCK_MASTER_FALSE 0 +#define NV_CTRL_FRAMELOCK_MASTER_TRUE 1 + +/* + * NV_CTRL_FRAMELOCK_POLARITY - sync either to the rising edge of the + * frame lock pulse, the falling edge of the frame lock pulse or both. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_POLARITY 23 /* RW-F */ +#define NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE 0x1 +#define NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE 0x2 +#define NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES 0x3 + +/* + * NV_CTRL_FRAMELOCK_SYNC_DELAY - delay between the frame lock pulse + * and the GPU sync. This value must be multiplied by + * NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION to determine the sync delay in + * nanoseconds. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + * + * USAGE NODE: NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX and + * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR are deprecated. + * The Sync Delay _MAX and _FACTOR are different for different + * GSync products and so, to be correct, the valid values for + * NV_CTRL_FRAMELOCK_SYNC_DELAY must be queried to get the range + * of acceptable sync delay values, and + * NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION must be queried to + * obtain the correct factor. + */ + +#define NV_CTRL_FRAMELOCK_SYNC_DELAY 24 /* RW-F */ +#define NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX 2047 // deprecated +#define NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR 7.81 // deprecated + +/* + * NV_CTRL_FRAMELOCK_SYNC_INTERVAL - how many house sync pulses + * between the frame lock sync generation (0 == sync every house sync); + * this only applies to the master when receiving house sync. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_SYNC_INTERVAL 25 /* RW-F */ + +/* + * NV_CTRL_FRAMELOCK_PORT0_STATUS - status of the rj45 port0. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_PORT0_STATUS 26 /* R--F */ +#define NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT 0 +#define NV_CTRL_FRAMELOCK_PORT0_STATUS_OUTPUT 1 + +/* + * NV_CTRL_FRAMELOCK_PORT1_STATUS - status of the rj45 port1. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_PORT1_STATUS 27 /* R--F */ +#define NV_CTRL_FRAMELOCK_PORT1_STATUS_INPUT 0 +#define NV_CTRL_FRAMELOCK_PORT1_STATUS_OUTPUT 1 + +/* + * NV_CTRL_FRAMELOCK_HOUSE_STATUS - returns whether or not the house + * sync signal was detected on the BNC connector of the frame lock + * board. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_HOUSE_STATUS 28 /* R--F */ +#define NV_CTRL_FRAMELOCK_HOUSE_STATUS_NOT_DETECTED 0 +#define NV_CTRL_FRAMELOCK_HOUSE_STATUS_DETECTED 1 + +/* + * NV_CTRL_FRAMELOCK_SYNC - enable/disable the syncing of display + * devices to the frame lock pulse as specified by previous calls to + * NV_CTRL_FRAMELOCK_MASTER and NV_CTRL_FRAMELOCK_SLAVES. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_SYNC 29 /* RW-G */ +#define NV_CTRL_FRAMELOCK_SYNC_DISABLE 0 +#define NV_CTRL_FRAMELOCK_SYNC_ENABLE 1 + +/* + * NV_CTRL_FRAMELOCK_SYNC_READY - reports whether a frame lock + * board is receiving sync (regardless of whether or not any display + * devices are using the sync). + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_SYNC_READY 30 /* R--F */ +#define NV_CTRL_FRAMELOCK_SYNC_READY_FALSE 0 +#define NV_CTRL_FRAMELOCK_SYNC_READY_TRUE 1 + +/* + * NV_CTRL_FRAMELOCK_STEREO_SYNC - this indicates that the GPU stereo + * signal is in sync with the frame lock stereo signal. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_STEREO_SYNC 31 /* R--G */ +#define NV_CTRL_FRAMELOCK_STEREO_SYNC_FALSE 0 +#define NV_CTRL_FRAMELOCK_STEREO_SYNC_TRUE 1 + +/* + * NV_CTRL_FRAMELOCK_TEST_SIGNAL - to test the connections in the sync + * group, tell the master to enable a test signal, then query port[01] + * status and sync_ready on all slaves. When done, tell the master to + * disable the test signal. Test signal should only be manipulated + * while NV_CTRL_FRAMELOCK_SYNC is enabled. + * + * The TEST_SIGNAL is also used to reset the Universal Frame Count (as + * returned by the glXQueryFrameCountNV() function in the + * GLX_NV_swap_group extension). Note: for best accuracy of the + * Universal Frame Count, it is recommended to toggle the TEST_SIGNAL + * on and off after enabling frame lock. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_FRAMELOCK_TEST_SIGNAL 32 /* RW-G */ +#define NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE 0 +#define NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE 1 + +/* + * NV_CTRL_FRAMELOCK_ETHERNET_DETECTED - The frame lock boards are + * cabled together using regular cat5 cable, connecting to rj45 ports + * on the backplane of the card. There is some concern that users may + * think these are ethernet ports and connect them to a + * router/hub/etc. The hardware can detect this and will shut off to + * prevent damage (either to itself or to the router). + * NV_CTRL_FRAMELOCK_ETHERNET_DETECTED may be called to find out if + * ethernet is connected to one of the rj45 ports. An appropriate + * error message should then be displayed. The _PORT0 and _PORT1 + * values may be or'ed together. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED 33 /* R--F */ +#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_NONE 0 +#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT0 0x1 +#define NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT1 0x2 + +/* + * NV_CTRL_FRAMELOCK_VIDEO_MODE - get/set what video mode is used + * to interperate the house sync signal. This should only be set + * on the master. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_VIDEO_MODE 34 /* RW-F */ +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE 0 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL 1 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_NTSCPALSECAM 2 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV 3 + +/* + * During FRAMELOCK bring-up, the above values were redefined to + * these: + */ + +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO 0 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL 1 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL 2 +#define NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL 3 + +/* + * NV_CTRL_FRAMELOCK_SYNC_RATE - this is the refresh rate that the + * frame lock board is sending to the GPU, in milliHz. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_FRAMELOCK_SYNC_RATE 35 /* R--F */ + +/**************************************************************************/ + +/* + * NV_CTRL_FORCE_GENERIC_CPU - inhibit the use of CPU specific + * features such as MMX, SSE, or 3DNOW! for OpenGL clients; this + * option may result in performance loss, but may be useful in + * conjunction with software such as the Valgrind memory debugger. + * This setting is only applied to OpenGL clients that are started + * after this setting is applied. + * + * USAGE NOTE: This attribute is deprecated. CPU compatibility is now + * checked each time during initialization. + */ + +#define NV_CTRL_FORCE_GENERIC_CPU 37 /* RW-X */ +#define NV_CTRL_FORCE_GENERIC_CPU_DISABLE 0 +#define NV_CTRL_FORCE_GENERIC_CPU_ENABLE 1 + +/* + * NV_CTRL_OPENGL_AA_LINE_GAMMA - for OpenGL clients, allow + * Gamma-corrected antialiased lines to consider variances in the + * color display capabilities of output devices when rendering smooth + * lines. Only available on recent Quadro GPUs. This setting is only + * applied to OpenGL clients that are started after this setting is + * applied. + */ + +#define NV_CTRL_OPENGL_AA_LINE_GAMMA 38 /* RW-X */ +#define NV_CTRL_OPENGL_AA_LINE_GAMMA_DISABLE 0 +#define NV_CTRL_OPENGL_AA_LINE_GAMMA_ENABLE 1 + +/* + * NV_CTRL_FRAMELOCK_TIMING - this is TRUE when the gpu is both receiving + * and locked to an input timing signal. Timing information may come from + * the following places: Another frame lock device that is set to master, + * the house sync signal, or the GPU's internal timing from a display + * device. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_FRAMELOCK_TIMING 39 /* R--G */ +#define NV_CTRL_FRAMELOCK_TIMING_FALSE 0 +#define NV_CTRL_FRAMELOCK_TIMING_TRUE 1 + +/* + * NV_CTRL_FLIPPING_ALLOWED - when TRUE, OpenGL will swap by flipping + * when possible; when FALSE, OpenGL will alway swap by blitting. + */ + +#define NV_CTRL_FLIPPING_ALLOWED 40 /* RW-X */ +#define NV_CTRL_FLIPPING_ALLOWED_FALSE 0 +#define NV_CTRL_FLIPPING_ALLOWED_TRUE 1 + +/* + * NV_CTRL_ARCHITECTURE - returns the architecture on which the X server is + * running. + */ + +#define NV_CTRL_ARCHITECTURE 41 /* R-- */ +#define NV_CTRL_ARCHITECTURE_X86 0 +#define NV_CTRL_ARCHITECTURE_X86_64 1 +#define NV_CTRL_ARCHITECTURE_IA64 2 + +/* + * NV_CTRL_TEXTURE_CLAMPING - texture clamping mode in OpenGL. By + * default, _SPEC is used, which forces OpenGL texture clamping to + * conform with the OpenGL specification. _EDGE forces NVIDIA's + * OpenGL implementation to remap GL_CLAMP to GL_CLAMP_TO_EDGE, + * which is not strictly conformant, but some applications rely on + * the non-conformant behavior. + */ + +#define NV_CTRL_TEXTURE_CLAMPING 42 /* RW-X */ +#define NV_CTRL_TEXTURE_CLAMPING_EDGE 0 +#define NV_CTRL_TEXTURE_CLAMPING_SPEC 1 + +#define NV_CTRL_CURSOR_SHADOW 43 /* RW- */ +#define NV_CTRL_CURSOR_SHADOW_DISABLE 0 +#define NV_CTRL_CURSOR_SHADOW_ENABLE 1 + +#define NV_CTRL_CURSOR_SHADOW_ALPHA 44 /* RW- */ +#define NV_CTRL_CURSOR_SHADOW_RED 45 /* RW- */ +#define NV_CTRL_CURSOR_SHADOW_GREEN 46 /* RW- */ +#define NV_CTRL_CURSOR_SHADOW_BLUE 47 /* RW- */ + +#define NV_CTRL_CURSOR_SHADOW_X_OFFSET 48 /* RW- */ +#define NV_CTRL_CURSOR_SHADOW_Y_OFFSET 49 /* RW- */ + +/* + * When Application Control for FSAA is enabled, then what the + * application requests is used, and NV_CTRL_FSAA_MODE is ignored. If + * this is disabled, then any application setting is overridden with + * NV_CTRL_FSAA_MODE + */ + +#define NV_CTRL_FSAA_APPLICATION_CONTROLLED 50 /* RW-X */ +#define NV_CTRL_FSAA_APPLICATION_CONTROLLED_ENABLED 1 +#define NV_CTRL_FSAA_APPLICATION_CONTROLLED_DISABLED 0 + +/* + * When Application Control for LogAniso is enabled, then what the + * application requests is used, and NV_CTRL_LOG_ANISO is ignored. If + * this is disabled, then any application setting is overridden with + * NV_CTRL_LOG_ANISO + */ + +#define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED 51 /* RW-X */ +#define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_ENABLED 1 +#define NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_DISABLED 0 + +/* + * IMAGE_SHARPENING adjusts the sharpness of the display's image + * quality by amplifying high frequency content. Valid values will + * normally be in the range [0,32). Only available on GeForceFX or + * newer. + */ + +#define NV_CTRL_IMAGE_SHARPENING 52 /* RWDG */ + +/* + * NV_CTRL_TV_OVERSCAN adjusts the amount of overscan on the specified + * display device. + */ + +#define NV_CTRL_TV_OVERSCAN 53 /* RWDG */ + +/* + * NV_CTRL_TV_FLICKER_FILTER adjusts the amount of flicker filter on + * the specified display device. + */ + +#define NV_CTRL_TV_FLICKER_FILTER 54 /* RWDG */ + +/* + * NV_CTRL_TV_BRIGHTNESS adjusts the amount of brightness on the + * specified display device. + */ + +#define NV_CTRL_TV_BRIGHTNESS 55 /* RWDG */ + +/* + * NV_CTRL_TV_HUE adjusts the amount of hue on the specified display + * device. + */ + +#define NV_CTRL_TV_HUE 56 /* RWDG */ + +/* + * NV_CTRL_TV_CONTRAST adjusts the amount of contrast on the specified + * display device. + */ + +#define NV_CTRL_TV_CONTRAST 57 /* RWDG */ + +/* + * NV_CTRL_TV_SATURATION adjusts the amount of saturation on the + * specified display device. + */ + +#define NV_CTRL_TV_SATURATION 58 /* RWDG */ + +/* + * NV_CTRL_TV_RESET_SETTINGS - this write-only attribute can be used + * to request that all TV Settings be reset to their default values; + * typical usage would be that this attribute be sent, and then all + * the TV attributes be queried to retrieve their new values. + */ + +#define NV_CTRL_TV_RESET_SETTINGS 59 /* -WDG */ + +/* + * NV_CTRL_GPU_CORE_TEMPERATURE reports the current core temperature + * of the GPU driving the X screen. + */ + +#define NV_CTRL_GPU_CORE_TEMPERATURE 60 /* R--G */ + +/* + * NV_CTRL_GPU_CORE_THRESHOLD reports the current GPU core slowdown + * threshold temperature, NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD and + * NV_CTRL_GPU_MAX_CORE_THRESHOLD report the default and MAX core + * slowdown threshold temperatures. + * + * NV_CTRL_GPU_CORE_THRESHOLD reflects the temperature at which the + * GPU is throttled to prevent overheating. + */ + +#define NV_CTRL_GPU_CORE_THRESHOLD 61 /* R--G */ +#define NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD 62 /* R--G */ +#define NV_CTRL_GPU_MAX_CORE_THRESHOLD 63 /* R--G */ + +/* + * NV_CTRL_AMBIENT_TEMPERATURE reports the current temperature in the + * immediate neighbourhood of the GPU driving the X screen. + */ + +#define NV_CTRL_AMBIENT_TEMPERATURE 64 /* R--G */ + +/* + * NV_CTRL_PBUFFER_SCANOUT_SUPPORTED - returns whether this X screen + * supports scanout of FP pbuffers; + * + * if this screen does not support PBUFFER_SCANOUT, then all other + * PBUFFER_SCANOUT attributes are unavailable. + * + * PBUFFER_SCANOUT is supported if and only if: + * - Twinview is configured with clone mode. The secondary screen is used to + * scanout the pbuffer. + * - The desktop is running in with 16 bits per pixel. + */ +#define NV_CTRL_PBUFFER_SCANOUT_SUPPORTED 65 /* R-- */ +#define NV_CTRL_PBUFFER_SCANOUT_FALSE 0 +#define NV_CTRL_PBUFFER_SCANOUT_TRUE 1 + +/* + * NV_CTRL_PBUFFER_SCANOUT_XID indicates the XID of the pbuffer used for + * scanout. + */ +#define NV_CTRL_PBUFFER_SCANOUT_XID 66 /* RW- */ + +/**************************************************************************/ +/* + * The NV_CTRL_GVO_* integer attributes are used to configure GVO + * (Graphics to Video Out). This functionality is available, for + * example, on the Quadro FX 4000 SDI graphics board. + * + * The following is a typical usage pattern for the GVO attributes: + * + * - query NV_CTRL_GVO_SUPPORTED to determine if the X screen supports GV0. + * + * - specify NV_CTRL_GVO_SYNC_MODE (one of FREE_RUNNING, GENLOCK, or + * FRAMELOCK); if you specify GENLOCK or FRAMELOCK, you should also + * specify NV_CTRL_GVO_SYNC_SOURCE. + * + * - Use NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED and + * NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED to detect what input syncs are + * present. + * + * (If no analog sync is detected but it is known that a valid + * bi-level or tri-level sync is connected set + * NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE appropriately and + * retest with NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED). + * + * - if syncing to input sync, query the + * NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT attribute; note that Input video + * format can only be queried after SYNC_SOURCE is specified. + * + * - specify the NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT + * + * - specify the NV_CTRL_GVO_DATA_FORMAT + * + * - specify any custom Color Space Conversion (CSC) matrix, offset, + * and scale with XNVCTRLSetGvoColorConversion(). + * + * - if using the GLX_NV_video_out extension to display one or more + * pbuffers, call glXGetVideoDeviceNV() to lock the GVO output for use + * by the GLX client; then bind the pbuffer(s) to the GVO output with + * glXBindVideoImageNV() and send pbuffers to the GVO output with + * glXSendPbufferToVideoNV(); see the GLX_NV_video_out spec for more + * details. + * + * - if using the GLX_NV_present_video extension, call + * glXBindVideoDeviceNV() to bind the GVO video device to current + * OpenGL context. + * + * Note that setting most GVO attributes only causes the value to be + * cached in the X server. The values will be flushed to the hardware + * either when the next MetaMode is set that uses the GVO display + * device, or when a GLX pbuffer is bound to the GVO output (with + * glXBindVideoImageNV()). + * + * Note that GLX_NV_video_out/GLX_NV_present_video and X screen use + * are mutually exclusive. If a MetaMode is currently using the GVO + * device, then glXGetVideoDeviceNV and glXBindVideoImageNV() will + * fail. Similarly, if a GLX client has locked the GVO output (via + * glXGetVideoDeviceNV or glXBindVideoImageNV), then setting a + * MetaMode that uses the GVO device will fail. The + * NV_CTRL_GVO_GLX_LOCKED event will be sent when a GLX client locks + * the GVO output. + * + */ + +/* + * NV_CTRL_GVO_SUPPORTED - returns whether this X screen supports GVO; + * if this screen does not support GVO output, then all other GVO + * attributes are unavailable. + */ + +#define NV_CTRL_GVO_SUPPORTED 67 /* R-- */ +#define NV_CTRL_GVO_SUPPORTED_FALSE 0 +#define NV_CTRL_GVO_SUPPORTED_TRUE 1 + +/* + * NV_CTRL_GVO_SYNC_MODE - selects the GVO sync mode; possible values + * are: + * + * FREE_RUNNING - GVO does not sync to any external signal + * + * GENLOCK - the GVO output is genlocked to an incoming sync signal; + * genlocking locks at hsync. This requires that the output video + * format exactly match the incoming sync video format. + * + * FRAMELOCK - the GVO output is frame locked to an incoming sync + * signal; frame locking locks at vsync. This requires that the output + * video format have the same refresh rate as the incoming sync video + * format. + */ + +#define NV_CTRL_GVO_SYNC_MODE 68 /* RW- */ +#define NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING 0 +#define NV_CTRL_GVO_SYNC_MODE_GENLOCK 1 +#define NV_CTRL_GVO_SYNC_MODE_FRAMELOCK 2 + +/* + * NV_CTRL_GVO_SYNC_SOURCE - if NV_CTRL_GVO_SYNC_MODE is set to either + * GENLOCK or FRAMELOCK, this controls which sync source is used as + * the incoming sync signal (either Composite or SDI). If + * NV_CTRL_GVO_SYNC_MODE is FREE_RUNNING, this attribute has no + * effect. + */ + +#define NV_CTRL_GVO_SYNC_SOURCE 69 /* RW- */ +#define NV_CTRL_GVO_SYNC_SOURCE_COMPOSITE 0 +#define NV_CTRL_GVO_SYNC_SOURCE_SDI 1 + +/* + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT - specifies the desired output video + * format for GVO devices or the desired input video format for GVI devices. + * + * Note that for GVO, the valid video formats may vary depending on + * the NV_CTRL_GVO_SYNC_MODE and the incoming sync video format. See + * the definition of NV_CTRL_GVO_SYNC_MODE. + * + * Note that when querying the ValidValues for this data type, the + * values are reported as bits within a bitmask + * (ATTRIBUTE_TYPE_INT_BITS); unfortunately, there are more valid + * value bits than will fit in a single 32-bit value. To solve this, + * query the ValidValues for NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT to + * check which of the first 31 VIDEO_FORMATS are valid, query the + * ValidValues for NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 to check which + * of the 32-63 VIDEO_FORMATS are valid, and query the ValidValues of + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 to check which of the 64-95 + * VIDEO_FORMATS are valid. + * + * Note: Setting this attribute on a GVI device may also result in the + * following NV-CONTROL attributes being reset on that device (to + * ensure the configuration remains valid): + * NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT + * NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING + */ + +#define NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT 70 /* RW--I */ + +#define NV_CTRL_GVIO_VIDEO_FORMAT_NONE 0 +#define NV_CTRL_GVIO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC 1 +#define NV_CTRL_GVIO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL 2 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_59_94_SMPTE296 3 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296 4 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1035I_59_94_SMPTE260 5 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1035I_60_00_SMPTE260 6 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_SMPTE295 7 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_SMPTE274 8 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_59_94_SMPTE274 9 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_60_00_SMPTE274 10 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_23_976_SMPTE274 11 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_24_00_SMPTE274 12 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_25_00_SMPTE274 13 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_29_97_SMPTE274 14 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_30_00_SMPTE274 15 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_50_00_SMPTE296 16 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_48_00_SMPTE274 17 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_47_96_SMPTE274 18 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_30_00_SMPTE296 19 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_29_97_SMPTE296 20 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_25_00_SMPTE296 21 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_24_00_SMPTE296 22 +#define NV_CTRL_GVIO_VIDEO_FORMAT_720P_23_98_SMPTE296 23 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274 24 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274 25 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274 26 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274 27 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274 28 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_30_00_SMPTE372 29 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_29_97_SMPTE372 30 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_60_00_SMPTE372 31 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_59_94_SMPTE372 32 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_25_00_SMPTE372 33 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_50_00_SMPTE372 34 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_24_00_SMPTE372 35 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_23_98_SMPTE372 36 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_48_00_SMPTE372 37 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_47_96_SMPTE372 38 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_50_00_3G_LEVEL_A_SMPTE274 39 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_59_94_3G_LEVEL_A_SMPTE274 40 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_60_00_3G_LEVEL_A_SMPTE274 41 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_60_00_3G_LEVEL_B_SMPTE274 42 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_60_00_3G_LEVEL_B_SMPTE274 43 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_60_00_3G_LEVEL_B_SMPTE372 44 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_50_00_3G_LEVEL_B_SMPTE274 45 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_3G_LEVEL_B_SMPTE274 46 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_50_00_3G_LEVEL_B_SMPTE372 47 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_30_00_3G_LEVEL_B_SMPTE274 48 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_30_00_3G_LEVEL_B_SMPTE372 49 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_25_00_3G_LEVEL_B_SMPTE274 50 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_25_00_3G_LEVEL_B_SMPTE372 51 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_24_00_3G_LEVEL_B_SMPTE274 52 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_24_00_3G_LEVEL_B_SMPTE372 53 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_48_00_3G_LEVEL_B_SMPTE274 54 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_48_00_3G_LEVEL_B_SMPTE372 55 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_59_94_3G_LEVEL_B_SMPTE274 56 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_59_94_3G_LEVEL_B_SMPTE274 57 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_59_94_3G_LEVEL_B_SMPTE372 58 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_29_97_3G_LEVEL_B_SMPTE274 59 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_29_97_3G_LEVEL_B_SMPTE372 60 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080P_23_98_3G_LEVEL_B_SMPTE274 61 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048P_23_98_3G_LEVEL_B_SMPTE372 62 +#define NV_CTRL_GVIO_VIDEO_FORMAT_1080I_47_96_3G_LEVEL_B_SMPTE274 63 +#define NV_CTRL_GVIO_VIDEO_FORMAT_2048I_47_96_3G_LEVEL_B_SMPTE372 64 + +/* + * The following are deprecated; NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT and the + * corresponding NV_CTRL_GVIO_* formats should be used instead. + */ +#define NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT 70 /* RW- */ + +#define NV_CTRL_GVO_VIDEO_FORMAT_NONE 0 +#define NV_CTRL_GVO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC 1 +#define NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL 2 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_59_94_SMPTE296 3 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296 4 +#define NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260 5 +#define NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260 6 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295 7 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274 8 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274 9 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_60_00_SMPTE274 10 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_976_SMPTE274 11 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE274 12 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274 13 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274 14 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274 15 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_50_00_SMPTE296 16 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274 17 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274 18 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_30_00_SMPTE296 19 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_29_97_SMPTE296 20 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_25_00_SMPTE296 21 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_24_00_SMPTE296 22 +#define NV_CTRL_GVO_VIDEO_FORMAT_720P_23_98_SMPTE296 23 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274 24 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274 25 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274 26 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274 27 +#define NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274 28 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_30_00_SMPTE372 29 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_29_97_SMPTE372 30 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_60_00_SMPTE372 31 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_59_94_SMPTE372 32 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_25_00_SMPTE372 33 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_50_00_SMPTE372 34 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_24_00_SMPTE372 35 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048P_23_98_SMPTE372 36 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_48_00_SMPTE372 37 +#define NV_CTRL_GVO_VIDEO_FORMAT_2048I_47_96_SMPTE372 38 + +/* + * NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT - indicates the input video format + * detected for GVO or GVI devices; the possible values are the + * NV_CTRL_GVIO_VIDEO_FORMAT constants. + * + * For GVI devices, the jack number should be specified in the lower + * 16 bits of the "display_mask" parameter, while the channel number should be + * specified in the upper 16 bits. + */ + +#define NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT 71 /* R--I */ + +/* + * The following is deprecated. Use NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT, + * instead. + */ +#define NV_CTRL_GVO_INPUT_VIDEO_FORMAT 71 /* R-- */ + +/* + * NV_CTRL_GVO_DATA_FORMAT - This controls how the data in the source + * (either the X screen or the GLX pbuffer) is interpretted and + * displayed. + * + * Note: some of the below DATA_FORMATS have been renamed. For + * example, R8G8B8_TO_RGB444 has been renamed to X8X8X8_444_PASSTHRU. + * This is to more accurately reflect DATA_FORMATS where the + * per-channel data could be either RGB or YCrCb -- the point is that + * the driver and GVO hardware do not perform any implicit color space + * conversion on the data; it is passed through to the SDI out. + */ + +#define NV_CTRL_GVO_DATA_FORMAT 72 /* RW- */ +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB444 0 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_YCRCBA4444 1 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_YCRCBZ4444 2 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB422 3 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_YCRCBA4224 4 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_YCRCBZ4224 5 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_RGB444 6 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8_444_PASSTHRU 6 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_RGBA4444 7 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8A8_4444_PASSTHRU 7 +#define NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_RGBZ4444 8 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8Z8_4444_PASSTHRU 8 +#define NV_CTRL_GVO_DATA_FORMAT_Y10CR10CB10_TO_YCRCB444 9 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X10X10X10_444_PASSTHRU 9 +#define NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8_TO_YCRCB444 10 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8_444_PASSTHRU 10 +#define NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8A10_TO_YCRCBA4444 11 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8A10_4444_PASSTHRU 11 +#define NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8Z10_TO_YCRCBZ4444 12 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8Z10_4444_PASSTHRU 12 +#define NV_CTRL_GVO_DATA_FORMAT_DUAL_R8G8B8_TO_DUAL_YCRCB422 13 +#define NV_CTRL_GVO_DATA_FORMAT_DUAL_Y8CR8CB8_TO_DUAL_YCRCB422 14 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_DUAL_X8X8X8_TO_DUAL_422_PASSTHRU 14 +#define NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB422 15 +#define NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB444 16 +#define NV_CTRL_GVO_DATA_FORMAT_Y12CR12CB12_TO_YCRCB444 17 // renamed +#define NV_CTRL_GVO_DATA_FORMAT_X12X12X12_444_PASSTHRU 17 +#define NV_CTRL_GVO_DATA_FORMAT_R12G12B12_TO_YCRCB444 18 +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8_422_PASSTHRU 19 +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8A8_4224_PASSTHRU 20 +#define NV_CTRL_GVO_DATA_FORMAT_X8X8X8Z8_4224_PASSTHRU 21 +#define NV_CTRL_GVO_DATA_FORMAT_X10X10X10_422_PASSTHRU 22 +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8_422_PASSTHRU 23 +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8A10_4224_PASSTHRU 24 +#define NV_CTRL_GVO_DATA_FORMAT_X10X8X8Z10_4224_PASSTHRU 25 +#define NV_CTRL_GVO_DATA_FORMAT_X12X12X12_422_PASSTHRU 26 +#define NV_CTRL_GVO_DATA_FORMAT_R12G12B12_TO_YCRCB422 27 + +/* + * NV_CTRL_GVO_DISPLAY_X_SCREEN - no longer supported + */ + +#define NV_CTRL_GVO_DISPLAY_X_SCREEN 73 /* RW- */ +#define NV_CTRL_GVO_DISPLAY_X_SCREEN_ENABLE 1 +#define NV_CTRL_GVO_DISPLAY_X_SCREEN_DISABLE 0 + +/* + * NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED - indicates whether + * Composite Sync input is detected. + */ + +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED 74 /* R-- */ +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED_FALSE 0 +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED_TRUE 1 + +/* + * NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE - get/set the + * Composite Sync input detect mode. + */ + +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE 75 /* RW- */ +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_AUTO 0 +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_BI_LEVEL 1 +#define NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_TRI_LEVEL 2 + +/* + * NV_CTRL_GVO_SYNC_INPUT_DETECTED - indicates whether SDI Sync input + * is detected, and what type. + */ + +#define NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED 76 /* R-- */ +#define NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_NONE 0 +#define NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_HD 1 +#define NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_SD 2 + +/* + * NV_CTRL_GVO_VIDEO_OUTPUTS - indicates which GVO video output + * connectors are currently outputing data. + */ + +#define NV_CTRL_GVO_VIDEO_OUTPUTS 77 /* R-- */ +#define NV_CTRL_GVO_VIDEO_OUTPUTS_NONE 0 +#define NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO1 1 +#define NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO2 2 +#define NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO_BOTH 3 + +/* + * NV_CTRL_GVO_FPGA_VERSION - indicates the version of the Firmware on + * the GVO device. Deprecated; use + * NV_CTRL_STRING_GVIO_FIRMWARE_VERSION instead. + */ + +#define NV_CTRL_GVO_FIRMWARE_VERSION 78 /* R-- */ + +/* + * NV_CTRL_GVO_SYNC_DELAY_PIXELS - controls the delay between the + * input sync and the output sync in numbers of pixels from hsync; + * this is a 12 bit value. + * + * If the NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW bit is set, + * then setting this value will set an advance instead of a delay. + */ + +#define NV_CTRL_GVO_SYNC_DELAY_PIXELS 79 /* RW- */ + +/* + * NV_CTRL_GVO_SYNC_DELAY_LINES - controls the delay between the input + * sync and the output sync in numbers of lines from vsync; this is a + * 12 bit value. + * + * If the NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW bit is set, + * then setting this value will set an advance instead of a delay. + */ + +#define NV_CTRL_GVO_SYNC_DELAY_LINES 80 /* RW- */ + +/* + * NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE - must be set for a period + * of about 2 seconds for the new InputVideoFormat to be properly + * locked to. In nvidia-settings, we do a reacquire whenever genlock + * or frame lock mode is entered into, when the user clicks the + * "detect" button. This value can be written, but always reads back + * _FALSE. + */ + +#define NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE 81 /* -W- */ +#define NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_FALSE 0 +#define NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_TRUE 1 + +/* + * NV_CTRL_GVO_GLX_LOCKED - indicates that GVO configurability is + * locked by GLX; this occurs when either glXGetVideoDeviceNV (part of + * GLX_NV_video_out) or glXBindVideoDeviceNV (part of + * GLX_NV_present_video) is called. All GVO output resources are + * locked until released by the GLX_NV_video_out/GLX_NV_present_video + * client. + * + * When GVO is locked, setting of the following GVO NV-CONTROL attributes will + * not happen immediately and will instead be cached. The GVO resource will + * need to be disabled/released and re-enabled/claimed for the values to be + * flushed. These attributes are: + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT + * NV_CTRL_GVO_DATA_FORMAT + * NV_CTRL_GVO_FLIP_QUEUE_SIZE + * + * This attribute is deprecated and may be removed in a future release. Its + * functionality has been replaced by NV_CTRL_GVO_LOCK_OWNER. + */ + +#define NV_CTRL_GVO_GLX_LOCKED 82 /* R-- */ +#define NV_CTRL_GVO_GLX_LOCKED_FALSE 0 +#define NV_CTRL_GVO_GLX_LOCKED_TRUE 1 + +/* + * NV_CTRL_GVIO_VIDEO_FORMAT_{WIDTH,HEIGHT,REFRESH_RATE} - query the + * width, height, and refresh rate for the specified + * NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be queried with + * existing interfaces, XNVCTRLQueryAttribute() should be used, and + * the video format specified in the display_mask field; eg: + * + * XNVCTRLQueryAttribute (dpy, + * screen, + * NV_CTRL_GVIO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC, + * NV_CTRL_GVIO_VIDEO_FORMAT_WIDTH, + * &value); + * + * Note that Refresh Rate is in milliHertz values + */ + +#define NV_CTRL_GVIO_VIDEO_FORMAT_WIDTH 83 /* R--I */ +#define NV_CTRL_GVIO_VIDEO_FORMAT_HEIGHT 84 /* R--I */ +#define NV_CTRL_GVIO_VIDEO_FORMAT_REFRESH_RATE 85 /* R--I */ + +/* The following are deprecated; use the NV_CTRL_GVIO_* versions, instead */ +#define NV_CTRL_GVO_VIDEO_FORMAT_WIDTH 83 /* R-- */ +#define NV_CTRL_GVO_VIDEO_FORMAT_HEIGHT 84 /* R-- */ +#define NV_CTRL_GVO_VIDEO_FORMAT_REFRESH_RATE 85 /* R-- */ + +/* + * NV_CTRL_GVO_X_SCREEN_PAN_[XY] - no longer supported + */ + +#define NV_CTRL_GVO_X_SCREEN_PAN_X 86 /* RW- */ +#define NV_CTRL_GVO_X_SCREEN_PAN_Y 87 /* RW- */ + +/* + * NV_CTRL_GPU_OVERCLOCKING_STATE - query the current or set a new + * overclocking state; the value of this attribute controls the + * availability of additional overclocking attributes (see below). + * + * Note: this attribute is unavailable unless overclocking support + * has been enabled in the X server (by the user). + */ + +#define NV_CTRL_GPU_OVERCLOCKING_STATE 88 /* RW-G */ +#define NV_CTRL_GPU_OVERCLOCKING_STATE_NONE 0 +#define NV_CTRL_GPU_OVERCLOCKING_STATE_MANUAL 1 + +/* + * NV_CTRL_GPU_{2,3}D_CLOCK_FREQS - query or set the GPU and memory + * clocks of the device driving the X screen. New clock frequencies + * are tested before being applied, and may be rejected. + * + * Note: if the target clocks are too aggressive, their testing may + * render the system unresponsive. + * + * Note: while this attribute can always be queried, it can't be set + * unless NV_CTRL_GPU_OVERCLOCKING_STATE is set to _MANUAL. Since + * the target clocks may be rejected, the requester should read this + * attribute after the set to determine success or failure. + * + * NV_CTRL_GPU_{2,3}D_CLOCK_FREQS are "packed" integer attributes; the + * GPU clock is stored in the upper 16 bits of the integer, and the + * memory clock is stored in the lower 16 bits of the integer. All + * clock values are in MHz. + */ + +#define NV_CTRL_GPU_2D_CLOCK_FREQS 89 /* RW-G */ +#define NV_CTRL_GPU_3D_CLOCK_FREQS 90 /* RW-G */ + +/* + * NV_CTRL_GPU_DEFAULT_{2,3}D_CLOCK_FREQS - query the default memory + * and GPU core clocks of the device driving the X screen. + * + * NV_CTRL_GPU_DEFAULT_{2,3}D_CLOCK_FREQS are "packed" integer + * attributes; the GPU clock is stored in the upper 16 bits of the + * integer, and the memory clock is stored in the lower 16 bits of the + * integer. All clock values are in MHz. + */ + +#define NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS 91 /* R--G */ +#define NV_CTRL_GPU_DEFAULT_3D_CLOCK_FREQS 92 /* R--G */ + +/* + * NV_CTRL_GPU_CURRENT_CLOCK_FREQS - query the current GPU and memory + * clocks of the graphics device driving the X screen. + * + * NV_CTRL_GPU_CURRENT_CLOCK_FREQS is a "packed" integer attribute; + * the GPU clock is stored in the upper 16 bits of the integer, and + * the memory clock is stored in the lower 16 bits of the integer. + * All clock values are in MHz. All clock values are in MHz. + */ + +#define NV_CTRL_GPU_CURRENT_CLOCK_FREQS 93 /* R--G */ + +/* + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS - Holds the last calculated + * optimal 3D clock frequencies found by the + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION process. Querying this + * attribute before having probed for the optimal clocks will return + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_INVALID + * + * Note: unless NV_CTRL_GPU_OVERCLOCKING_STATE is set to _MANUAL, the + * optimal clock detection process is unavailable. + */ + +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS 94 /* R--G */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_INVALID 0 + +/* + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION - set to _START to + * initiate testing for the optimal 3D clock frequencies. Once + * found, the optimal clock frequencies will be returned by the + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS attribute asynchronously + * (using an X event, see XNVCtrlSelectNotify). + * + * To cancel an ongoing test for the optimal clocks, set the + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION attribute to _CANCEL + * + * Note: unless NV_CTRL_GPU_OVERCLOCKING_STATE is set to _MANUAL, the + * optimal clock detection process is unavailable. + */ + +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION 95 /* -W-G */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_START 0 +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_CANCEL 1 + +/* + * NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE - query this + * variable to know if a test is currently being run to + * determine the optimal 3D clock frequencies. _BUSY means a + * test is currently running, _IDLE means the test is not running. + * + * Note: unless NV_CTRL_GPU_OVERCLOCKING_STATE is set to _MANUAL, the + * optimal clock detection process is unavailable. + */ + +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE 96 /* R--G */ +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_IDLE 0 +#define NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_BUSY 1 + +/* + * NV_CTRL_FLATPANEL_CHIP_LOCATION - for the specified display device, + * report whether the flat panel is driven by the on-chip controller, + * or a separate controller chip elsewhere on the graphics board. + * This attribute is only available for flat panels. + */ + +#define NV_CTRL_FLATPANEL_CHIP_LOCATION 215 /* R-DG */ +#define NV_CTRL_FLATPANEL_CHIP_LOCATION_INTERNAL 0 +#define NV_CTRL_FLATPANEL_CHIP_LOCATION_EXTERNAL 1 + +/* + * NV_CTRL_FLATPANEL_LINK - report the number of links for a DVI connection, or + * the main link's active lane count for DisplayPort. + * This attribute is only available for flat panels. + */ + +#define NV_CTRL_FLATPANEL_LINK 216 /* R-DG */ +#define NV_CTRL_FLATPANEL_LINK_SINGLE 0 +#define NV_CTRL_FLATPANEL_LINK_DUAL 1 +#define NV_CTRL_FLATPANEL_LINK_QUAD 3 + +/* + * NV_CTRL_FLATPANEL_SIGNAL - for the specified display device, report + * whether the flat panel is driven by an LVDS, TMDS, or DisplayPort signal. + * This attribute is only available for flat panels. + */ + +#define NV_CTRL_FLATPANEL_SIGNAL 217 /* R-DG */ +#define NV_CTRL_FLATPANEL_SIGNAL_LVDS 0 +#define NV_CTRL_FLATPANEL_SIGNAL_TMDS 1 +#define NV_CTRL_FLATPANEL_SIGNAL_DISPLAYPORT 2 + +/* + * NV_CTRL_USE_HOUSE_SYNC - when TRUE, the server (master) frame lock + * device will propagate the incoming house sync signal as the outgoing + * frame lock sync signal. If the frame lock device cannot detect a + * frame lock sync signal, it will default to using the internal timings + * from the GPU connected to the primary connector. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_USE_HOUSE_SYNC 218 /* RW-F */ +#define NV_CTRL_USE_HOUSE_SYNC_FALSE 0 +#define NV_CTRL_USE_HOUSE_SYNC_TRUE 1 + +/* + * NV_CTRL_EDID_AVAILABLE - report if an EDID is available for the + * specified display device. + * + * This attribute may also be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN + * target. + */ + +#define NV_CTRL_EDID_AVAILABLE 219 /* R-DG */ +#define NV_CTRL_EDID_AVAILABLE_FALSE 0 +#define NV_CTRL_EDID_AVAILABLE_TRUE 1 + +/* + * NV_CTRL_FORCE_STEREO - when TRUE, OpenGL will force stereo flipping + * even when no stereo drawables are visible (if the device is configured + * to support it, see the "Stereo" X config option). + * When false, fall back to the default behavior of only flipping when a + * stereo drawable is visible. + */ + +#define NV_CTRL_FORCE_STEREO 220 /* RW- */ +#define NV_CTRL_FORCE_STEREO_FALSE 0 +#define NV_CTRL_FORCE_STEREO_TRUE 1 + +/* + * NV_CTRL_IMAGE_SETTINGS - the image quality setting for OpenGL clients. + * + * This setting is only applied to OpenGL clients that are started + * after this setting is applied. + */ + +#define NV_CTRL_IMAGE_SETTINGS 221 /* RW-X */ +#define NV_CTRL_IMAGE_SETTINGS_HIGH_QUALITY 0 +#define NV_CTRL_IMAGE_SETTINGS_QUALITY 1 +#define NV_CTRL_IMAGE_SETTINGS_PERFORMANCE 2 +#define NV_CTRL_IMAGE_SETTINGS_HIGH_PERFORMANCE 3 + +/* + * NV_CTRL_XINERAMA - return whether xinerama is enabled + */ + +#define NV_CTRL_XINERAMA 222 /* R--G */ +#define NV_CTRL_XINERAMA_OFF 0 +#define NV_CTRL_XINERAMA_ON 1 + +/* + * NV_CTRL_XINERAMA_STEREO - when TRUE, OpenGL will allow stereo flipping + * on multiple X screens configured with Xinerama. + * When FALSE, flipping is allowed only on one X screen at a time. + */ + +#define NV_CTRL_XINERAMA_STEREO 223 /* RW- */ +#define NV_CTRL_XINERAMA_STEREO_FALSE 0 +#define NV_CTRL_XINERAMA_STEREO_TRUE 1 + +/* + * NV_CTRL_BUS_RATE - if the bus type of the specified device is AGP, then + * NV_CTRL_BUS_RATE returns the configured AGP transfer rate. If the bus type + * is PCI Express, then this attribute returns the maximum link width. + * When this attribute is queried on an X screen target, the bus rate of the + * GPU driving the X screen is returned. + */ + +#define NV_CTRL_BUS_RATE 224 /* R--GI */ + +/* + * NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH - returns the maximum + * PCIe link width, in number of lanes. + */ +#define NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH NV_CTRL_BUS_RATE + +/* + * NV_CTRL_SHOW_SLI_HUD - when TRUE, OpenGL will draw information about the + * current SLI mode. + * Renamed this attribute to NV_CTRL_SHOW_SLI_VISUAL_INDICATOR + */ + +#define NV_CTRL_SHOW_SLI_HUD NV_CTRL_SHOW_SLI_VISUAL_INDICATOR +#define NV_CTRL_SHOW_SLI_HUD_FALSE NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_FALSE +#define NV_CTRL_SHOW_SLI_HUD_TRUE NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_TRUE + +/* + * NV_CTRL_SHOW_SLI_VISUAL_INDICATOR - when TRUE, OpenGL will draw information + * about the current SLI mode. + */ + +#define NV_CTRL_SHOW_SLI_VISUAL_INDICATOR 225 /* RW-X */ +#define NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_FALSE 0 +#define NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_TRUE 1 + +/* + * NV_CTRL_XV_SYNC_TO_DISPLAY - this control is valid when TwinView and + * XVideo Sync To VBlank are enabled. + * It controls which display device will be synched to. + */ + +#define NV_CTRL_XV_SYNC_TO_DISPLAY 226 /* RW- */ + +/* + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 - this attribute is only + * intended to be used to query the ValidValues for + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for VIDEO_FORMAT values between + * 31 and 63. See NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for details. + */ + +#define NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 227 /* ---GI */ + +/* + * The following is deprecated; use NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2, + * instead + */ +#define NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 227 /* --- */ + +/* + * NV_CTRL_GVO_OVERRIDE_HW_CSC - Override the SDI hardware's Color Space + * Conversion with the values controlled through + * XNVCTRLSetGvoColorConversion() and XNVCTRLGetGvoColorConversion(). If + * this attribute is FALSE, then the values specified through + * XNVCTRLSetGvoColorConversion() are ignored. + */ + +#define NV_CTRL_GVO_OVERRIDE_HW_CSC 228 /* RW- */ +#define NV_CTRL_GVO_OVERRIDE_HW_CSC_FALSE 0 +#define NV_CTRL_GVO_OVERRIDE_HW_CSC_TRUE 1 + +/* + * NV_CTRL_GVO_CAPABILITIES - this read-only attribute describes GVO + * capabilities that differ between NVIDIA SDI products. This value + * is a bitmask where each bit indicates whether that capability is + * available. + * + * APPLY_CSC_IMMEDIATELY - whether the CSC matrix, offset, and scale + * specified through XNVCTRLSetGvoColorConversion() will take affect + * immediately, or only after SDI output is disabled and enabled + * again. + * + * APPLY_CSC_TO_X_SCREEN - whether the CSC matrix, offset, and scale + * specified through XNVCTRLSetGvoColorConversion() will also apply + * to GVO output of an X screen, or only to OpenGL GVO output, as + * enabled through the GLX_NV_video_out extension. + * + * COMPOSITE_TERMINATION - whether the 75 ohm termination of the + * SDI composite input signal can be programmed through the + * NV_CTRL_GVO_COMPOSITE_TERMINATION attribute. + * + * SHARED_SYNC_BNC - whether the SDI device has a single BNC + * connector used for both (SDI & Composite) incoming signals. + * + * MULTIRATE_SYNC - whether the SDI device supports synchronization + * of input and output video modes that match in being odd or even + * modes (ie, AA.00 Hz modes can be synched to other BB.00 Hz modes and + * AA.XX Hz can match to BB.YY Hz where .XX and .YY are not .00) + */ + +#define NV_CTRL_GVO_CAPABILITIES 229 /* R-- */ +#define NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_IMMEDIATELY 0x00000001 +#define NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_TO_X_SCREEN 0x00000002 +#define NV_CTRL_GVO_CAPABILITIES_COMPOSITE_TERMINATION 0x00000004 +#define NV_CTRL_GVO_CAPABILITIES_SHARED_SYNC_BNC 0x00000008 +#define NV_CTRL_GVO_CAPABILITIES_MULTIRATE_SYNC 0x00000010 +#define NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW 0x00000020 + +/* + * NV_CTRL_GVO_COMPOSITE_TERMINATION - enable or disable 75 ohm + * termination of the SDI composite input signal. + */ + +#define NV_CTRL_GVO_COMPOSITE_TERMINATION 230 /* RW- */ +#define NV_CTRL_GVO_COMPOSITE_TERMINATION_ENABLE 1 +#define NV_CTRL_GVO_COMPOSITE_TERMINATION_DISABLE 0 + +/* + * NV_CTRL_ASSOCIATED_DISPLAY_DEVICES - display device mask indicating + * which display devices are "associated" with the specified X screen + * (ie: are available to the X screen for displaying the X screen). + */ + +#define NV_CTRL_ASSOCIATED_DISPLAY_DEVICES 231 /* RW- */ + +/* + * NV_CTRL_FRAMELOCK_SLAVES - get/set whether the display device(s) + * given should listen or ignore the master's sync signal. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_SLAVES 232 /* RW-G */ + +/* + * NV_CTRL_FRAMELOCK_MASTERABLE - Can any of the given display devices + * be set as master of the frame lock group. Returns a bitmask of the + * corresponding display devices that can be set as master. + * + * This attribute can only be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_FRAMELOCK_MASTERABLE 233 /* R-DG */ + +/* + * NV_CTRL_PROBE_DISPLAYS - re-probes the hardware to detect what + * display devices are connected to the GPU or GPU driving the + * specified X screen. Returns a display mask. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_PROBE_DISPLAYS 234 /* R--G */ + +/* + * NV_CTRL_REFRESH_RATE - Returns the refresh rate of the specified + * display device in 100 * Hz (ie. to get the refresh rate in Hz, divide + * the returned value by 100.) + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_REFRESH_RATE 235 /* R-DG */ + +/* + * NV_CTRL_GVO_FLIP_QUEUE_SIZE - The Graphics to Video Out interface + * exposed through NV-CONTROL and the GLX_NV_video_out extension uses + * an internal flip queue when pbuffers are sent to the video device + * (via glXSendPbufferToVideoNV()). The NV_CTRL_GVO_FLIP_QUEUE_SIZE + * can be used to query and assign the flip queue size. This + * attribute is applied to GLX when glXGetVideoDeviceNV() is called by + * the application. + */ + +#define NV_CTRL_GVO_FLIP_QUEUE_SIZE 236 /* RW- */ + +/* + * NV_CTRL_CURRENT_SCANLINE - query the current scanline for the + * specified display device. + */ + +#define NV_CTRL_CURRENT_SCANLINE 237 /* R-DG */ + +/* + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT - Controls where X pixmaps are initially + * created. + * + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM causes pixmaps to stay in + * system memory. These pixmaps can't be accelerated by the NVIDIA driver; this + * will cause blank windows if used with an OpenGL compositing manager. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM creates pixmaps in system memory + * initially, but allows them to migrate to video memory. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM creates pixmaps in video memory + * when enough resources are available. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_RESERVED is currently reserved for future + * use. Behavior is undefined. + * NV_CTRL_INITIAL_PIXMAP_PLACEMENT_GPU_SYSMEM creates pixmaps in GPU accessible + * system memory when enough resources are available. + */ + +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT 238 /* RW- */ +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM 0 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM 1 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM 2 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_RESERVED 3 +#define NV_CTRL_INITIAL_PIXMAP_PLACEMENT_GPU_SYSMEM 4 + +/* + * NV_CTRL_PCI_BUS - Returns the PCI bus number the specified device is using. + */ + +#define NV_CTRL_PCI_BUS 239 /* R--GI */ + +/* + * NV_CTRL_PCI_DEVICE - Returns the PCI device number the specified device is + * using. + */ + +#define NV_CTRL_PCI_DEVICE 240 /* R--GI */ + +/* + * NV_CTRL_PCI_FUNCTION - Returns the PCI function number the specified device + * is using. + */ + +#define NV_CTRL_PCI_FUNCTION 241 /* R--GI */ + +/* + * NV_CTRL_FRAMELOCK_FPGA_REVISION - Querys the FPGA revision of the + * Frame Lock device. + * + * This attribute must be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. + */ + +#define NV_CTRL_FRAMELOCK_FPGA_REVISION 242 /* R--F */ + +/* + * NV_CTRL_MAX_SCREEN_{WIDTH,HEIGHT} - the maximum allowable size, in + * pixels, of either the specified X screen (if the target_type of the + * query is an X screen), or any X screen on the specified GPU (if the + * target_type of the query is a GPU). + */ + +#define NV_CTRL_MAX_SCREEN_WIDTH 243 /* R--G */ +#define NV_CTRL_MAX_SCREEN_HEIGHT 244 /* R--G */ + +/* + * NV_CTRL_MAX_DISPLAYS - the maximum number of display devices that + * can be driven simultaneously on a GPU (e.g., that can be used in a + * MetaMode at once). Note that this does not indicate the maximum + * number of bits that can be set in NV_CTRL_CONNECTED_DISPLAYS, + * because more display devices can be connected than are actively in + * use. + */ + +#define NV_CTRL_MAX_DISPLAYS 245 /* R--G */ + +/* + * NV_CTRL_DYNAMIC_TWINVIEW - Returns whether or not the screen + * supports dynamic twinview. + */ + +#define NV_CTRL_DYNAMIC_TWINVIEW 246 /* R-- */ + +/* + * NV_CTRL_MULTIGPU_DISPLAY_OWNER - Returns the (NV-CONTROL) GPU ID of + * the GPU that has the display device(s) used for showing the X Screen. + */ + +#define NV_CTRL_MULTIGPU_DISPLAY_OWNER 247 /* R-- */ + +/* + * NV_CTRL_GPU_SCALING - not supported + */ + +#define NV_CTRL_GPU_SCALING 248 /* RWDG */ + +#define NV_CTRL_GPU_SCALING_TARGET_INVALID 0 +#define NV_CTRL_GPU_SCALING_TARGET_FLATPANEL_BEST_FIT 1 +#define NV_CTRL_GPU_SCALING_TARGET_FLATPANEL_NATIVE 2 + +#define NV_CTRL_GPU_SCALING_METHOD_INVALID 0 +#define NV_CTRL_GPU_SCALING_METHOD_STRETCHED 1 +#define NV_CTRL_GPU_SCALING_METHOD_CENTERED 2 +#define NV_CTRL_GPU_SCALING_METHOD_ASPECT_SCALED 3 + +/* + * NV_CTRL_FRONTEND_RESOLUTION - not supported + */ + +#define NV_CTRL_FRONTEND_RESOLUTION 249 /* R-DG */ + +/* + * NV_CTRL_BACKEND_RESOLUTION - not supported + */ + +#define NV_CTRL_BACKEND_RESOLUTION 250 /* R-DG */ + +/* + * NV_CTRL_FLATPANEL_NATIVE_RESOLUTION - Returns the dimensions of the + * native resolution of the flat panel as determined by the + * NVIDIA X Driver. + * + * The native resolution is the resolution at which a flat panel + * must display any image. All other resolutions must be scaled to this + * resolution through GPU scaling or the DFP's native scaling capabilities + * in order to be displayed. + * + * This attribute is only valid for flat panel (DFP) display devices. + * + * This attribute is a packed integer; the width is packed in the upper + * 16-bits and the height is packed in the lower 16-bits. + */ + +#define NV_CTRL_FLATPANEL_NATIVE_RESOLUTION 251 /* R-DG */ + +/* + * NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION - not supported + */ + +#define NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION 252 /* R-DG */ + +/* + * NV_CTRL_GPU_SCALING_ACTIVE - not supported + */ + +#define NV_CTRL_GPU_SCALING_ACTIVE 253 /* R-DG */ + +/* + * NV_CTRL_DFP_SCALING_ACTIVE - not supported + */ + +#define NV_CTRL_DFP_SCALING_ACTIVE 254 /* R-DG */ + +/* + * NV_CTRL_FSAA_APPLICATION_ENHANCED - Controls how the NV_CTRL_FSAA_MODE + * is applied when NV_CTRL_FSAA_APPLICATION_CONTROLLED is set to + * NV_CTRL_APPLICATION_CONTROLLED_DISABLED. When + * NV_CTRL_FSAA_APPLICATION_ENHANCED is _DISABLED, OpenGL applications will + * be forced to use the FSAA mode specified by NV_CTRL_FSAA_MODE. when set + * to _ENABLED, only those applications that have selected a multisample + * FBConfig will be made to use the NV_CTRL_FSAA_MODE specified. + * + * This attribute is ignored when NV_CTRL_FSAA_APPLICATION_CONTROLLED is + * set to NV_CTRL_FSAA_APPLICATION_CONTROLLED_ENABLED. + */ + +#define NV_CTRL_FSAA_APPLICATION_ENHANCED 255 /* RW-X */ +#define NV_CTRL_FSAA_APPLICATION_ENHANCED_ENABLED 1 +#define NV_CTRL_FSAA_APPLICATION_ENHANCED_DISABLED 0 + +/* + * NV_CTRL_FRAMELOCK_SYNC_RATE_4 - This is the refresh rate that the + * frame lock board is sending to the GPU with 4 digits of precision. + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK. + */ + +#define NV_CTRL_FRAMELOCK_SYNC_RATE_4 256 /* R--F */ + +/* + * NV_CTRL_GVO_LOCK_OWNER - indicates that the GVO device is available + * or in use (by GLX or an X screen). + * + * The GVO device is locked by GLX when either glXGetVideoDeviceNV + * (part of GLX_NV_video_out) or glXBindVideoDeviceNV (part of + * GLX_NV_present_video) is called. All GVO output resources are + * locked until released by the GLX_NV_video_out/GLX_NV_present_video + * client. + * + * The GVO device is locked/unlocked by an X screen, when the GVO device is + * used in a MetaMode on an X screen. + * + * When the GVO device is locked, setting of the following GVO NV-CONTROL + * attributes will not happen immediately and will instead be cached. The + * GVO resource will need to be disabled/released and re-enabled/claimed for + * the values to be flushed. These attributes are: + * + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT + * NV_CTRL_GVO_DATA_FORMAT + * NV_CTRL_GVO_FLIP_QUEUE_SIZE + */ + +#define NV_CTRL_GVO_LOCK_OWNER 257 /* R-- */ +#define NV_CTRL_GVO_LOCK_OWNER_NONE 0 +#define NV_CTRL_GVO_LOCK_OWNER_GLX 1 +#define NV_CTRL_GVO_LOCK_OWNER_CLONE /* no longer supported */ 2 +#define NV_CTRL_GVO_LOCK_OWNER_X_SCREEN 3 + +/* + * NV_CTRL_HWOVERLAY - when a workstation overlay is in use, reports + * whether the hardware overlay is used, or if the overlay is emulated. + */ + +#define NV_CTRL_HWOVERLAY 258 /* R-- */ +#define NV_CTRL_HWOVERLAY_FALSE 0 +#define NV_CTRL_HWOVERLAY_TRUE 1 + +/* + * NV_CTRL_NUM_GPU_ERRORS_RECOVERED - Returns the number of GPU errors + * occured. This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_NUM_GPU_ERRORS_RECOVERED 259 /* R--- */ + +/* + * NV_CTRL_REFRESH_RATE_3 - Returns the refresh rate of the specified + * display device in 1000 * Hz (ie. to get the refresh rate in Hz, divide + * the returned value by 1000.) + * + * This attribute may be queried through XNVCTRLQueryTargetAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_REFRESH_RATE_3 260 /* R-DG */ + +/* + * NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS - if the OnDemandVBlankInterrupts + * X driver option is set to true, this attribute can be used to + * determine if on-demand VBlank interrupt control is enabled on the + * specified GPU, as well as to enable or disable this feature. + */ + +#define NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS 261 /* RW-G */ +#define NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS_OFF 0 +#define NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS_ON 1 + +/* + * NV_CTRL_GPU_POWER_SOURCE reports the type of power source + * of the GPU driving the X screen. + */ + +#define NV_CTRL_GPU_POWER_SOURCE 262 /* R--G */ +#define NV_CTRL_GPU_POWER_SOURCE_AC 0 +#define NV_CTRL_GPU_POWER_SOURCE_BATTERY 1 + +/* + * NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE is deprecated + */ + +#define NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE 263 /* R--G */ +#define NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE_DESKTOP 0 +#define NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE_MAXPERF 1 + +/* NV_CTRL_GLYPH_CACHE - Enables RENDER Glyph Caching to VRAM */ + +#define NV_CTRL_GLYPH_CACHE 264 /* RW- */ +#define NV_CTRL_GLYPH_CACHE_DISABLED 0 +#define NV_CTRL_GLYPH_CACHE_ENABLED 1 + +/* + * NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL reports the current + * Performance level of the GPU driving the X screen. Each + * Performance level has associated NVClock and Mem Clock values. + */ + +#define NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL 265 /* R--G */ + +/* + * NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE reports if Adaptive Clocking + * is Enabled on the GPU driving the X screen. + */ + +#define NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE 266 /* R--G */ +#define NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE_DISABLED 0 +#define NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE_ENABLED 1 + +/* + * NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED - Returns whether or not the GVO output + * video is locked to the GPU. + */ + +#define NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED 267 /* R--- */ +#define NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED_FALSE 0 +#define NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED_TRUE 1 + +/* + * NV_CTRL_GVO_SYNC_LOCK_STATUS - Returns whether or not the GVO device + * is locked to the input ref signal. If the sync mode is set to + * NV_CTRL_GVO_SYNC_MODE_GENLOCK, then this returns the genlock + * sync status, and if the sync mode is set to NV_CTRL_GVO_SYNC_MODE_FRAMELOCK, + * then this reports the frame lock status. + */ + +#define NV_CTRL_GVO_SYNC_LOCK_STATUS 268 /* R--- */ +#define NV_CTRL_GVO_SYNC_LOCK_STATUS_UNLOCKED 0 +#define NV_CTRL_GVO_SYNC_LOCK_STATUS_LOCKED 1 + +/* + * NV_CTRL_GVO_ANC_TIME_CODE_GENERATION - Allows SDI device to generate + * time codes in the ANC region of the SDI video output stream. + */ + +#define NV_CTRL_GVO_ANC_TIME_CODE_GENERATION 269 /* RW-- */ +#define NV_CTRL_GVO_ANC_TIME_CODE_GENERATION_DISABLE 0 +#define NV_CTRL_GVO_ANC_TIME_CODE_GENERATION_ENABLE 1 + +/* + * NV_CTRL_GVO_COMPOSITE - Enables/Disables SDI compositing. This attribute + * is only available when an SDI input source is detected and is in genlock + * mode. + */ + +#define NV_CTRL_GVO_COMPOSITE 270 /* RW-- */ +#define NV_CTRL_GVO_COMPOSITE_DISABLE 0 +#define NV_CTRL_GVO_COMPOSITE_ENABLE 1 + +/* + * NV_CTRL_GVO_COMPOSITE_ALPHA_KEY - When compositing is enabled, this + * enables/disables alpha blending. + */ + +#define NV_CTRL_GVO_COMPOSITE_ALPHA_KEY 271 /* RW-- */ +#define NV_CTRL_GVO_COMPOSITE_ALPHA_KEY_DISABLE 0 +#define NV_CTRL_GVO_COMPOSITE_ALPHA_KEY_ENABLE 1 + +/* + * NV_CTRL_GVO_COMPOSITE_LUMA_KEY_RANGE - Set the values of a luma + * channel range. This is a packed int that has the following format + * (in order of high-bits to low bits): + * + * Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) + * + * To query the current values, pass the range # throught the display_mask + * variable. + */ + +#define NV_CTRL_GVO_COMPOSITE_LUMA_KEY_RANGE 272 /* RW-- */ + +#define NV_CTRL_GVO_COMPOSITE_MAKE_RANGE(range, enable, min, max) \ + ((((min)&0x3FF) << 0) | (((max)&0x3FF) << 10) | (((enable)&0x1) << 20) | \ + (((range)&0x7FF) << 21)) + +#define NV_CTRL_GVO_COMPOSITE_GET_RANGE(val, range, enable, min, max) \ + (min) = ((val) >> 0) & 0x3FF; \ + (max) = ((val) >> 10) & 0x3FF; \ + (enable) = ((val) >> 20) & 0x1; \ + (range) = ((val) >> 21) & 0x7FF; + +/* + * NV_CTRL_GVO_COMPOSITE_CR_KEY_RANGE - Set the values of a CR + * channel range. This is a packed int that has the following format + * (in order of high-bits to low bits): + * + * Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) + * + * To query the current values, pass the range # throught he display_mask + * variable. + */ + +#define NV_CTRL_GVO_COMPOSITE_CR_KEY_RANGE 273 /* RW-- */ + +/* + * NV_CTRL_GVO_COMPOSITE_CB_KEY_RANGE - Set the values of a CB + * channel range. This is a packed int that has the following format + * (in order of high-bits to low bits): + * + * Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) + * + * To query the current values, pass the range # throught he display_mask + * variable. + */ + +#define NV_CTRL_GVO_COMPOSITE_CB_KEY_RANGE 274 /* RW-- */ + +/* + * NV_CTRL_GVO_COMPOSITE_NUM_KEY_RANGES - Returns the number of ranges + * available for each channel (Y/Luma, Cr, and Cb.) + */ + +#define NV_CTRL_GVO_COMPOSITE_NUM_KEY_RANGES 275 /* R--- */ + +/* + * NV_CTRL_SWITCH_TO_DISPLAYS - Can be used to select which displays + * to switch to (as a hotkey event). + */ + +#define NV_CTRL_SWITCH_TO_DISPLAYS 276 /* -W- */ + +/* + * NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT - Event that notifies + * when a notebook lid change occurs (i.e. when the lid is opened or + * closed.) This attribute can be queried to retrieve the current + * notebook lid status (opened/closed.) + */ + +#define NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT 277 /* RW- */ +#define NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT_CLOSE 0 +#define NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT_OPEN 1 + +/* + * NV_CTRL_NOTEBOOK_INTERNAL_LCD - Returns the display device mask of + * the intenal LCD of a notebook. + */ + +#define NV_CTRL_NOTEBOOK_INTERNAL_LCD 278 /* R-- */ + +/* + * NV_CTRL_DEPTH_30_ALLOWED - returns whether the NVIDIA X driver supports + * depth 30 on the specified X screen or GPU. + */ + +#define NV_CTRL_DEPTH_30_ALLOWED 279 /* R--G */ + +/* + * NV_CTRL_MODE_SET_EVENT This attribute is sent as an event + * when hotkey, ctrl-alt-+/- or randr event occurs. Note that + * This attribute cannot be set or queried and is meant to + * be received by clients that wish to be notified of when + * mode set events occur. + */ + +#define NV_CTRL_MODE_SET_EVENT 280 /* --- */ + +/* + * NV_CTRL_OPENGL_AA_LINE_GAMMA_VALUE - the gamma value used by + * OpenGL when NV_CTRL_OPENGL_AA_LINE_GAMMA is enabled + */ + +#define NV_CTRL_OPENGL_AA_LINE_GAMMA_VALUE 281 /* RW-X */ + +/* + * NV_CTRL_VCSC_HIGH_PERF_MODE - Is used to both query High Performance Mode + * status on the Visual Computing System, and also to enable or disable High + * Performance Mode. + */ + +#define NV_CTRL_VCSC_HIGH_PERF_MODE 282 /* RW-V */ +#define NV_CTRL_VCSC_HIGH_PERF_MODE_DISABLE 0 +#define NV_CTRL_VCSC_HIGH_PERF_MODE_ENABLE 1 + +/* + * NV_CTRL_DISPLAYPORT_LINK_RATE - returns the negotiated lane bandwidth of the + * DisplayPort main link. + * This attribute is only available for DisplayPort flat panels. + */ + +#define NV_CTRL_DISPLAYPORT_LINK_RATE 291 /* R-DG */ +#define NV_CTRL_DISPLAYPORT_LINK_RATE_DISABLED 0x0 +#define NV_CTRL_DISPLAYPORT_LINK_RATE_1_62GBPS 0x6 +#define NV_CTRL_DISPLAYPORT_LINK_RATE_2_70GBPS 0xA + +/* + * NV_CTRL_STEREO_EYES_EXCHANGE - Controls whether or not the left and right + * eyes of a stereo image are flipped. + */ + +#define NV_CTRL_STEREO_EYES_EXCHANGE 292 /* RW-X */ +#define NV_CTRL_STEREO_EYES_EXCHANGE_OFF 0 +#define NV_CTRL_STEREO_EYES_EXCHANGE_ON 1 + +/* + * NV_CTRL_NO_SCANOUT - returns whether the special "NoScanout" mode is + * enabled on the specified X screen or GPU; for details on this mode, + * see the description of the "none" value for the "UseDisplayDevice" + * X configuration option in the NVIDIA driver README. + */ + +#define NV_CTRL_NO_SCANOUT 293 /* R--G */ +#define NV_CTRL_NO_SCANOUT_DISABLED 0 +#define NV_CTRL_NO_SCANOUT_ENABLED 1 + +/* + * NV_CTRL_GVO_CSC_CHANGED_EVENT This attribute is sent as an event + * when the color space conversion matrix has been altered by another + * client. + */ + +#define NV_CTRL_GVO_CSC_CHANGED_EVENT 294 /* --- */ + +/* + * NV_CTRL_FRAMELOCK_SLAVEABLE - Returns a bitmask of the display devices + * that are (currently) allowed to be selected as slave devices for the + * given GPU + */ + +#define NV_CTRL_FRAMELOCK_SLAVEABLE 295 /* R-DG */ + +/* + * NV_CTRL_GVO_SYNC_TO_DISPLAY This attribute controls whether or not + * the non-SDI display device will be sync'ed to the SDI display device + * (when configured in TwinView, Clone Mode or when using the SDI device + * with OpenGL). + */ + +#define NV_CTRL_GVO_SYNC_TO_DISPLAY 296 /* --- */ +#define NV_CTRL_GVO_SYNC_TO_DISPLAY_DISABLE 0 +#define NV_CTRL_GVO_SYNC_TO_DISPLAY_ENABLE 1 + +/* + * NV_CTRL_X_SERVER_UNIQUE_ID - returns a pseudo-unique identifier for this + * X server. Intended for use in cases where an NV-CONTROL client communicates + * with multiple X servers, and wants some level of confidence that two + * X Display connections correspond to the same or different X servers. + */ + +#define NV_CTRL_X_SERVER_UNIQUE_ID 297 /* R--- */ + +/* + * NV_CTRL_PIXMAP_CACHE - This attribute controls whether the driver attempts to + * store video memory pixmaps in a cache. The cache speeds up allocation and + * deallocation of pixmaps, but could use more memory than when the cache is + * disabled. + */ + +#define NV_CTRL_PIXMAP_CACHE 298 /* RW-X */ +#define NV_CTRL_PIXMAP_CACHE_DISABLE 0 +#define NV_CTRL_PIXMAP_CACHE_ENABLE 1 + +/* + * NV_CTRL_PIXMAP_CACHE_ROUNDING_SIZE_KB - When the pixmap cache is enabled and + * there is not enough free space in the cache to fit a new pixmap, the driver + * will round up to the next multiple of this number of kilobytes when + * allocating more memory for the cache. + */ + +#define NV_CTRL_PIXMAP_CACHE_ROUNDING_SIZE_KB 299 /* RW-X */ + +/* + * NV_CTRL_IS_GVO_DISPLAY - returns whether or not a given display is an + * SDI device. + */ + +#define NV_CTRL_IS_GVO_DISPLAY 300 /* R-D */ +#define NV_CTRL_IS_GVO_DISPLAY_FALSE 0 +#define NV_CTRL_IS_GVO_DISPLAY_TRUE 1 + +/* + * NV_CTRL_PCI_ID - Returns the PCI vendor and device ID of the specified + * device. + * + * NV_CTRL_PCI_ID is a "packed" integer attribute; the PCI vendor ID is stored + * in the upper 16 bits of the integer, and the PCI device ID is stored in the + * lower 16 bits of the integer. + */ + +#define NV_CTRL_PCI_ID 301 /* R--GI */ + +/* + * NV_CTRL_GVO_FULL_RANGE_COLOR - Allow full range color data [4-1019] + * without clamping to [64-940]. + */ + +#define NV_CTRL_GVO_FULL_RANGE_COLOR 302 /* RW- */ +#define NV_CTRL_GVO_FULL_RANGE_COLOR_DISABLED 0 +#define NV_CTRL_GVO_FULL_RANGE_COLOR_ENABLED 1 + +/* + * NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE - Returns whether or not + * SLI Mosaic Mode supported. + */ + +#define NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE 303 /* R-- */ +#define NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE_FALSE 0 +#define NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE_TRUE 1 + +/* + * NV_CTRL_GVO_ENABLE_RGB_DATA - Allows clients to specify when + * the GVO board should process colors as RGB when the output data + * format is one of the NV_CTRL_GVO_DATA_FORMAT_???_PASSTRHU modes. + */ + +#define NV_CTRL_GVO_ENABLE_RGB_DATA 304 /* RW- */ +#define NV_CTRL_GVO_ENABLE_RGB_DATA_DISABLE 0 +#define NV_CTRL_GVO_ENABLE_RGB_DATA_ENABLE 1 + +/* + * NV_CTRL_IMAGE_SHARPENING_DEFAULT - Returns default value of + * Image Sharpening. + */ + +#define NV_CTRL_IMAGE_SHARPENING_DEFAULT 305 /* R-- */ + +/* + * NV_CTRL_PCI_DOMAIN - Returns the PCI domain number the specified device is + * using. + */ + +#define NV_CTRL_PCI_DOMAIN 306 /* R--GI */ + +/* + * NV_CTRL_GVI_NUM_JACKS - Returns the number of input BNC jacks available + * on a GVI device. + */ + +#define NV_CTRL_GVI_NUM_JACKS 307 /* R--I */ + +/* + * NV_CTRL_GVI_MAX_LINKS_PER_STREAM - Returns the maximum supported number of + * links that can be tied to one stream. + */ + +#define NV_CTRL_GVI_MAX_LINKS_PER_STREAM 308 /* R--I */ + +/* + * NV_CTRL_GVI_DETECTED_CHANNEL_BITS_PER_COMPONENT - Returns the detected + * number of bits per component (BPC) of data on the given input jack+ + * channel. + * + * The jack number should be specified in the lower 16 bits of the + * "display_mask" parameter, while the channel number should be specified in + * the upper 16 bits. + */ + +#define NV_CTRL_GVI_DETECTED_CHANNEL_BITS_PER_COMPONENT 309 /* R--I */ +#define NV_CTRL_GVI_BITS_PER_COMPONENT_UNKNOWN 0 +#define NV_CTRL_GVI_BITS_PER_COMPONENT_8 1 +#define NV_CTRL_GVI_BITS_PER_COMPONENT_10 2 +#define NV_CTRL_GVI_BITS_PER_COMPONENT_12 3 + +/* + * NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT - Specify the number of + * bits per component (BPC) of data for the captured stream. + * The stream number should be specified in the "display_mask" parameter. + * + * Note: Setting this attribute may also result in the following + * NV-CONTROL attributes being reset on the GVI device (to ensure + * the configuration remains valid): + * NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING + */ + +#define NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT 310 /* RW-I */ + +/* + * NV_CTRL_GVI_DETECTED_CHANNEL_COMPONENT_SAMPLING - Returns the detected + * sampling format for the input jack+channel. + * + * The jack number should be specified in the lower 16 bits of the + * "display_mask" parameter, while the channel number should be specified in + * the upper 16 bits. + */ + +#define NV_CTRL_GVI_DETECTED_CHANNEL_COMPONENT_SAMPLING 311 /* R--I */ +#define NV_CTRL_GVI_COMPONENT_SAMPLING_UNKNOWN 0 +#define NV_CTRL_GVI_COMPONENT_SAMPLING_4444 1 +#define NV_CTRL_GVI_COMPONENT_SAMPLING_4224 2 +#define NV_CTRL_GVI_COMPONENT_SAMPLING_444 3 +#define NV_CTRL_GVI_COMPONENT_SAMPLING_422 4 +#define NV_CTRL_GVI_COMPONENT_SAMPLING_420 5 + +/* + * NV_CTRL_GVI_REQUESTED_COMPONENT_SAMPLING - Specify the sampling format for + * the captured stream. + * The possible values are the NV_CTRL_GVI_DETECTED_COMPONENT_SAMPLING + * constants. + * The stream number should be specified in the "display_mask" parameter. + */ + +#define NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING 312 /* RW-I */ + +/* + * NV_CTRL_GVI_CHROMA_EXPAND - Enable or disable 4:2:2 -> 4:4:4 chroma + * expansion for the captured stream. This value is ignored when a + * COMPONENT_SAMPLING format is selected that does not use chroma subsampling, + * or if a BITS_PER_COMPONENT value is selected that is not supported. + * The stream number should be specified in the "display_mask" parameter. + */ + +#define NV_CTRL_GVI_REQUESTED_STREAM_CHROMA_EXPAND 313 /* RW-I */ +#define NV_CTRL_GVI_CHROMA_EXPAND_FALSE 0 +#define NV_CTRL_GVI_CHROMA_EXPAND_TRUE 1 + +/* + * NV_CTRL_GVI_DETECTED_CHANNEL_COLOR_SPACE - Returns the detected color space + * of the input jack+channel. + * + * The jack number should be specified in the lower 16 bits of the + * "display_mask" parameter, while the channel number should be specified in + * the upper 16 bits. + */ + +#define NV_CTRL_GVI_DETECTED_CHANNEL_COLOR_SPACE 314 /* R--I */ +#define NV_CTRL_GVI_COLOR_SPACE_UNKNOWN 0 +#define NV_CTRL_GVI_COLOR_SPACE_GBR 1 +#define NV_CTRL_GVI_COLOR_SPACE_GBRA 2 +#define NV_CTRL_GVI_COLOR_SPACE_GBRD 3 +#define NV_CTRL_GVI_COLOR_SPACE_YCBCR 4 +#define NV_CTRL_GVI_COLOR_SPACE_YCBCRA 5 +#define NV_CTRL_GVI_COLOR_SPACE_YCBCRD 6 + +/* + * NV_CTRL_GVI_DETECTED_CHANNEL_LINK_ID - Returns the detected link identifier + * for the given input jack+channel. + * + * The jack number should be specified in the lower 16 bits of the + * "display_mask" parameter, while the channel number should be specified in + * the upper 16 bits. + */ + +#define NV_CTRL_GVI_DETECTED_CHANNEL_LINK_ID 315 /* R--I */ +#define NV_CTRL_GVI_LINK_ID_UNKNOWN 0xFFFF + +/* + * NV_CTRL_GVI_DETECTED_CHANNEL_SMPTE352_IDENTIFIER - Returns the 4-byte + * SMPTE 352 identifier from the given input jack+channel. + * + * The jack number should be specified in the lower 16 bits of the + * "display_mask" parameter, while the channel number should be specified in + * the upper 16 bits. + */ + +#define NV_CTRL_GVI_DETECTED_CHANNEL_SMPTE352_IDENTIFIER 316 /* R--I */ + +/* + * NV_CTRL_GVI_GLOBAL_IDENTIFIER - Returns a global identifier for the + * GVI device. This identifier can be used to relate GVI devices named + * in NV-CONTROL with those enumerated in OpenGL. + */ + +#define NV_CTRL_GVI_GLOBAL_IDENTIFIER 317 /* R--I */ + +/* + * NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION - Returns the number of nanoseconds + * that one unit of NV_CTRL_FRAMELOCK_SYNC_DELAY corresponds to. + */ +#define NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION 318 /* R-- */ + +/* + * NV_CTRL_GPU_COOLER_MANUAL_CONTROL - Query the current or set a new + * cooler control state; the value of this attribute controls the + * availability of additional cooler control attributes (see below). + * + * Note: this attribute is unavailable unless cooler control support + * has been enabled in the X server (by the user). + */ + +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL 319 /* RW-G */ +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE 0 +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE 1 + +/* + * NV_CTRL_THERMAL_COOLER_LEVEL - Returns cooler's current operating + * level. + */ + +#define NV_CTRL_THERMAL_COOLER_LEVEL 320 /* RW-C */ + +/* NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT - Sets default values of + * cooler. + */ + +#define NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT 321 /* -W-C */ + +/* + * NV_CTRL_THERMAL_COOLER_CONTROL_TYPE - + * Returns a cooler's control signal characteristics. + * The possible types are restricted, Variable and Toggle. + */ + +#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE 322 /* R--C */ +#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_NONE 0 +#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_TOGGLE 1 +#define NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_VARIABLE 2 + +/* + * NV_CTRL_THERMAL_COOLER_TARGET - Returns objects that cooler cools. + * Targets may be GPU, Memory, Power Supply or All of these. + * GPU_RELATED = GPU | MEMORY | POWER_SUPPLY + * + */ + +#define NV_CTRL_THERMAL_COOLER_TARGET 323 /* R--C */ +#define NV_CTRL_THERMAL_COOLER_TARGET_NONE 0 +#define NV_CTRL_THERMAL_COOLER_TARGET_GPU 1 +#define NV_CTRL_THERMAL_COOLER_TARGET_MEMORY 2 +#define NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY 4 +#define NV_CTRL_THERMAL_COOLER_TARGET_GPU_RELATED \ + (NV_CTRL_THERMAL_COOLER_TARGET_GPU | NV_CTRL_THERMAL_COOLER_TARGET_MEMORY | \ + NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY) + +/* + * NV_CTRL_GPU_ECC_SUPPORTED - Reports whether ECC is supported by the + * targeted GPU. + */ +#define NV_CTRL_GPU_ECC_SUPPORTED 324 /* R--G */ +#define NV_CTRL_GPU_ECC_SUPPORTED_FALSE 0 +#define NV_CTRL_GPU_ECC_SUPPORTED_TRUE 1 + +/* + * NV_CTRL_GPU_ECC_STATUS - Returns the current hardware ECC setting + * for the targeted GPU. + */ +#define NV_CTRL_GPU_ECC_STATUS 325 /* R--G */ +#define NV_CTRL_GPU_ECC_STATUS_DISABLED 0 +#define NV_CTRL_GPU_ECC_STATUS_ENABLED 1 + +/* + * NV_CTRL_GPU_ECC_CONFIGURATION - Reports whether ECC can be configured + * dynamically for the GPU in question. + */ +#define NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED 326 /* R--G */ +#define NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED_FALSE 0 +#define NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED_TRUE 1 + +/* + * NV_CTRL_GPU_ECC_CONFIGURATION_SETTING - Returns the current ECC + * configuration setting or specifies new settings. New settings do not + * take effect until the next POST. + */ +#define NV_CTRL_GPU_ECC_CONFIGURATION 327 /* RW-G */ +#define NV_CTRL_GPU_ECC_CONFIGURATION_DISABLED 0 +#define NV_CTRL_GPU_ECC_CONFIGURATION_ENABLED 1 + +/* + * NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_SETTING - Returns the default + * ECC configuration setting. + */ +#define NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION 328 /* R--G */ +#define NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_DISABLED 0 +#define NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_ENABLED 1 + +/* + * NV_CTRL_GPU_ECC_SINGLE_BIT_ERRORS - Returns the number of single-bit + * ECC errors detected by the targeted GPU since the last POST. + * Note: this attribute is a 64-bit integer attribute. + */ +#define NV_CTRL_GPU_ECC_SINGLE_BIT_ERRORS 329 /* R--GQ */ + +/* + * NV_CTRL_GPU_ECC_DOUBLE_BIT_ERRORS - Returns the number of double-bit + * ECC errors detected by the targeted GPU since the last POST. + * Note: this attribute is a 64-bit integer attribute. + */ +#define NV_CTRL_GPU_ECC_DOUBLE_BIT_ERRORS 330 /* R--GQ */ + +/* + * NV_CTRL_GPU_ECC_AGGREGATE_SINGLE_BIT_ERRORS - Returns the number of + * single-bit ECC errors detected by the targeted GPU since the + * last counter reset. + * Note: this attribute is a 64-bit integer attribute. + */ +#define NV_CTRL_GPU_ECC_AGGREGATE_SINGLE_BIT_ERRORS 331 /* R--GQ */ + +/* + * NV_CTRL_GPU_ECC_AGGREGATE_DOUBLE_BIT_ERRORS - Returns the number of + * double-bit ECC errors detected by the targeted GPU since the + * last counter reset. + * Note: this attribute is a 64-bit integer attribute. + */ +#define NV_CTRL_GPU_ECC_AGGREGATE_DOUBLE_BIT_ERRORS 332 /* R--GQ */ + +/* + * NV_CTRL_GPU_ECC_RESET_ERROR_STATUS - Resets the volatile/aggregate + * single-bit and double-bit error counters. This attribute is a + * bitmask attribute. + */ +#define NV_CTRL_GPU_ECC_RESET_ERROR_STATUS 333 /* -W-G */ +#define NV_CTRL_GPU_ECC_RESET_ERROR_STATUS_VOLATILE 0x00000001 +#define NV_CTRL_GPU_ECC_RESET_ERROR_STATUS_AGGREGATE 0x00000002 + +/* + * NV_CTRL_GPU_POWER_MIZER_MODE - Provides a hint to the driver + * as to how to manage the performance of the GPU. + * + * ADAPTIVE - adjust GPU clocks based on GPU + * utilization + * PREFER_MAXIMUM_PERFORMANCE - raise GPU clocks to favor + * maximum performance, to the extent + * that thermal and other constraints + * allow + */ +#define NV_CTRL_GPU_POWER_MIZER_MODE 334 /* RW-G */ +#define NV_CTRL_GPU_POWER_MIZER_MODE_ADAPTIVE 0 +#define NV_CTRL_GPU_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE 1 + +/* + * NV_CTRL_GVI_SYNC_OUTPUT_FORMAT - Returns the output sync signal + * from the GVI device. + */ + +#define NV_CTRL_GVI_SYNC_OUTPUT_FORMAT 335 /* R--I */ + +/* + * NV_CTRL_GVI_MAX_CHANNELS_PER_JACK - Returns the maximum + * supported number of (logical) channels within a single physical jack of + * a GVI device. For most SDI video formats, there is only one channel + * (channel 0). But for 3G video formats (as specified in SMPTE 425), + * as an example, there are two channels (channel 0 and channel 1) per + * physical jack. + */ + +#define NV_CTRL_GVI_MAX_CHANNELS_PER_JACK 336 /* R--I */ + +/* + * NV_CTRL_GVI_MAX_STREAMS - Returns the maximum number of streams + * that can be configured on the GVI device. + */ + +#define NV_CTRL_GVI_MAX_STREAMS 337 /* R--I */ + +/* + * NV_CTRL_GVI_NUM_CAPTURE_SURFACES - The GVI interface exposed through + * NV-CONTROL and the GLX_NV_video_input extension uses internal capture + * surfaces when frames are read from the GVI device. The + * NV_CTRL_GVI_NUM_CAPTURE_SURFACES can be used to query and assign the + * number of capture surfaces. This attribute is applied when + * glXBindVideoCaptureDeviceNV() is called by the application. + * + * A lower number of capture surfaces will mean less video memory is used, + * but can result in frames being dropped if the application cannot keep up + * with the capture device. A higher number will prevent frames from being + * dropped, making capture more reliable but will consume move video memory. + */ +#define NV_CTRL_GVI_NUM_CAPTURE_SURFACES 338 /* RW-I */ + +/* + * NV_CTRL_OVERSCAN_COMPENSATION - not supported + */ +#define NV_CTRL_OVERSCAN_COMPENSATION 339 /* RWDG */ + +/* + * NV_CTRL_GPU_PCIE_GENERATION - Reports the current PCIe generation. + */ +#define NV_CTRL_GPU_PCIE_GENERATION 341 /* R--GI */ +#define NV_CTRL_GPU_PCIE_GENERATION1 0x00000001 +#define NV_CTRL_GPU_PCIE_GENERATION2 0x00000002 +#define NV_CTRL_GPU_PCIE_GENERATION3 0x00000003 + +/* + * NV_CTRL_GVI_BOUND_GPU - Returns the NV_CTRL_TARGET_TYPE_GPU target_id of + * the GPU currently bound to the GVI device. Returns -1 if no GPU is + * currently bound to the GVI device. + */ +#define NV_CTRL_GVI_BOUND_GPU 342 /* R--I */ + +/* + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 - this attribute is only + * intended to be used to query the ValidValues for + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for VIDEO_FORMAT values between + * 64 and 95. See NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for details. + */ + +#define NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 343 /* ---GI */ + +/* + * NV_CTRL_ACCELERATE_TRAPEZOIDS - Toggles RENDER Trapezoid acceleration + */ + +#define NV_CTRL_ACCELERATE_TRAPEZOIDS 344 /* RW- */ +#define NV_CTRL_ACCELERATE_TRAPEZOIDS_DISABLE 0 +#define NV_CTRL_ACCELERATE_TRAPEZOIDS_ENABLE 1 + +/* + * NV_CTRL_GPU_CORES - Returns number of GPU cores supported by the graphics + * pipeline. + */ + +#define NV_CTRL_GPU_CORES 345 /* R--G */ + +/* + * NV_CTRL_GPU_MEMORY_BUS_WIDTH - Returns memory bus bandwidth on the associated + * subdevice. + */ + +#define NV_CTRL_GPU_MEMORY_BUS_WIDTH 346 /* R--G */ + +/* + * NV_CTRL_GVI_TEST_MODE - This attribute controls the GVI test mode. When + * enabled, the GVI device will generate fake data as quickly as possible. All + * GVI settings are still valid when this is enabled (e.g., the requested video + * format is honored and sets the video size). + * This may be used to test the pipeline. + */ + +#define NV_CTRL_GVI_TEST_MODE 347 /* R--I */ +#define NV_CTRL_GVI_TEST_MODE_DISABLE 0 +#define NV_CTRL_GVI_TEST_MODE_ENABLE 1 + +/* + * NV_CTRL_COLOR_SPACE - This option sets color space of the video + * signal. + */ +#define NV_CTRL_COLOR_SPACE 348 /* RWDG */ +#define NV_CTRL_COLOR_SPACE_RGB 0 +#define NV_CTRL_COLOR_SPACE_YCbCr422 1 +#define NV_CTRL_COLOR_SPACE_YCbCr444 2 + +/* + * NV_CTRL_COLOR_RANGE - This option sets color range of the video + * signal. + */ +#define NV_CTRL_COLOR_RANGE 349 /* RWDG */ +#define NV_CTRL_COLOR_RANGE_FULL 0 +#define NV_CTRL_COLOR_RANGE_LIMITED 1 + +/* + * NV_CTRL_GPU_SCALING_DEFAULT_TARGET - not supported + * + * NV_CTRL_GPU_SCALING_DEFAULT_METHOD - not supported + */ +#define NV_CTRL_GPU_SCALING_DEFAULT_TARGET 350 /* R-DG */ +#define NV_CTRL_GPU_SCALING_DEFAULT_METHOD 351 /* R-DG */ + +/* + * NV_CTRL_DITHERING_MODE - Controls the dithering mode, when + * NV_CTRL_CURRENT_DITHERING is Enabled. + * + * AUTO: allow the driver to choose the dithering mode automatically. + * + * DYNAMIC_2X2: use a 2x2 matrix to dither from the GPU's pixel + * pipeline to the bit depth of the flat panel. The matrix values + * are changed from frame to frame. + * + * STATIC_2X2: use a 2x2 matrix to dither from the GPU's pixel + * pipeline to the bit depth of the flat panel. The matrix values + * do not change from frame to frame. + * + * TEMPORAL: use a pseudorandom value from a uniform distribution calculated at + * every pixel to achieve stochastic dithering. This method produces a better + * visual result than 2x2 matrix approaches. + */ +#define NV_CTRL_DITHERING_MODE 352 /* RWDG */ +#define NV_CTRL_DITHERING_MODE_AUTO 0 +#define NV_CTRL_DITHERING_MODE_DYNAMIC_2X2 1 +#define NV_CTRL_DITHERING_MODE_STATIC_2X2 2 +#define NV_CTRL_DITHERING_MODE_TEMPORAL 3 + +/* + * NV_CTRL_CURRENT_DITHERING - Returns the current dithering state. + */ +#define NV_CTRL_CURRENT_DITHERING 353 /* R-DG */ +#define NV_CTRL_CURRENT_DITHERING_DISABLED 0 +#define NV_CTRL_CURRENT_DITHERING_ENABLED 1 + +/* + * NV_CTRL_CURRENT_DITHERING_MODE - Returns the current dithering + * mode. + */ +#define NV_CTRL_CURRENT_DITHERING_MODE 354 /* R-DG */ +#define NV_CTRL_CURRENT_DITHERING_MODE_NONE 0 +#define NV_CTRL_CURRENT_DITHERING_MODE_DYNAMIC_2X2 1 +#define NV_CTRL_CURRENT_DITHERING_MODE_STATIC_2X2 2 +#define NV_CTRL_CURRENT_DITHERING_MODE_TEMPORAL 3 + +/* + * NV_CTRL_THERMAL_SENSOR_READING - Returns the thermal sensor's current + * reading. + */ +#define NV_CTRL_THERMAL_SENSOR_READING 355 /* R--S */ + +/* + * NV_CTRL_THERMAL_SENSOR_PROVIDER - Returns the hardware device that + * provides the thermal sensor. + */ +#define NV_CTRL_THERMAL_SENSOR_PROVIDER 356 /* R--S */ +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_NONE 0 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_GPU_INTERNAL 1 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_ADM1032 2 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_ADT7461 3 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_MAX6649 4 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_MAX1617 5 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_LM99 6 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_LM89 7 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_LM64 8 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_G781 9 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_ADT7473 10 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_SBMAX6649 11 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_VBIOSEVT 12 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_OS 13 +#define NV_CTRL_THERMAL_SENSOR_PROVIDER_UNKNOWN 0xFFFFFFFF + +/* + * NV_CTRL_THERMAL_SENSOR_TARGET - Returns what hardware component + * the thermal sensor is measuring. + */ +#define NV_CTRL_THERMAL_SENSOR_TARGET 357 /* R--S */ +#define NV_CTRL_THERMAL_SENSOR_TARGET_NONE 0 +#define NV_CTRL_THERMAL_SENSOR_TARGET_GPU 1 +#define NV_CTRL_THERMAL_SENSOR_TARGET_MEMORY 2 +#define NV_CTRL_THERMAL_SENSOR_TARGET_POWER_SUPPLY 4 +#define NV_CTRL_THERMAL_SENSOR_TARGET_BOARD 8 +#define NV_CTRL_THERMAL_SENSOR_TARGET_UNKNOWN 0xFFFFFFFF + +/* + * NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR - when TRUE, OpenGL will + * draw information about the current MULTIGPU mode. + */ +#define NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR 358 /* RW-X */ +#define NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR_FALSE 0 +#define NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR_TRUE 1 + +/* + * NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS - Returns GPU's processor + * clock freqs. + */ +#define NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS 359 /* RW-G */ + +/* + * NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS - query the flags (various information + * for the specified NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be + * queried with existing interfaces, the video format should be specified + * in the display_mask field; eg: + * + * XNVCTRLQueryTargetAttribute(dpy, + * NV_CTRL_TARGET_TYPE_GVI, + * gvi, + * NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296, + * NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS, + * &flags); + * + * Note: The NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_1080P_NO_12BPC flag is set + * for those 1080P 3G modes (level A and B) that do not support + * 12 bits per component (when configuring a GVI stream.) + */ + +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS 360 /* R--I */ +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_NONE 0x00000000 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_INTERLACED 0x00000001 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_PROGRESSIVE 0x00000002 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_PSF 0x00000004 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_A 0x00000008 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_B 0x00000010 +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G \ + ((NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_A) | (NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_B)) +#define NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_1080P_NO_12BPC 0x00000020 + +/* + * NV_CTRL_GPU_PCIE_MAX_LINK_SPEED - returns maximum PCIe link speed, + * in gigatransfers per second (GT/s). + */ + +#define NV_CTRL_GPU_PCIE_MAX_LINK_SPEED 361 /* R--GI */ + +/* + * NV_CTRL_3D_VISION_PRO_RESET_TRANSCEIVER_TO_FACTORY_SETTINGS - Resets the + * 3D Vision Pro transceiver to its factory settings. + */ +#define NV_CTRL_3D_VISION_PRO_RESET_TRANSCEIVER_TO_FACTORY_SETTINGS 363 /* -W-T */ + +/* + * NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL - Controls the channel that is + * currently used by the 3D Vision Pro transceiver. + */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL 364 /* RW-T */ + +/* + * NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE - Controls the mode in which the + * 3D Vision Pro transceiver operates. + * NV_CTRL_3D_VISION_PRO_TM_LOW_RANGE is bidirectional + * NV_CTRL_3D_VISION_PRO_TM_MEDIUM_RANGE is bidirectional + * NV_CTRL_3D_VISION_PRO_TM_HIGH_RANGE may be bidirectional just up to a + * given range, and unidirectional beyond it + * NV_CTRL_3D_VISION_PRO_TM_COUNT is the total number of + * 3D Vision Pro transceiver modes + */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE 365 /* RW-T */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_INVALID 0 +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_LOW_RANGE 1 +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_MEDIUM_RANGE 2 +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_HIGH_RANGE 3 +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_COUNT 4 + +/* + * NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES - controls whether updates to the color + * lookup table (LUT) are synchronous with respect to X rendering. For example, + * if an X client sends XStoreColors followed by XFillRectangle, the driver will + * guarantee that the FillRectangle request is not processed until after the + * updated LUT colors are actually visible on the screen if + * NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES is enabled. Otherwise, the rendering may + * occur first. + * + * This makes a difference for applications that use the LUT to animate, such as + * XPilot. If you experience flickering in applications that use LUT + * animations, try enabling this attribute. + * + * When synchronous updates are enabled, XStoreColors requests will be processed + * at your screen's refresh rate. + */ + +#define NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES 367 /* RWDG */ +#define NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES_DISABLE 0 +#define NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES_ENABLE 1 + +/* + * NV_CTRL_DITHERING_DEPTH - Controls the dithering depth when + * NV_CTRL_CURRENT_DITHERING is ENABLED. Some displays connected + * to the GPU via the DVI or LVDS interfaces cannot display the + * full color range of ten bits per channel, so the GPU will + * dither to either 6 or 8 bits per channel. + */ +#define NV_CTRL_DITHERING_DEPTH 368 /* RWDG */ +#define NV_CTRL_DITHERING_DEPTH_AUTO 0 +#define NV_CTRL_DITHERING_DEPTH_6_BITS 1 +#define NV_CTRL_DITHERING_DEPTH_8_BITS 2 + +/* + * NV_CTRL_CURRENT_DITHERING_DEPTH - Returns the current dithering + * depth value. + */ +#define NV_CTRL_CURRENT_DITHERING_DEPTH 369 /* R-DG */ +#define NV_CTRL_CURRENT_DITHERING_DEPTH_NONE 0 +#define NV_CTRL_CURRENT_DITHERING_DEPTH_6_BITS 1 +#define NV_CTRL_CURRENT_DITHERING_DEPTH_8_BITS 2 + +/* + * NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_FREQUENCY - Returns the + * frequency of the channel(in kHz) of the 3D Vision Pro transceiver. + * Use the display_mask parameter to specify the channel number. + */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_FREQUENCY 370 /* R--T */ + +/* + * NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_QUALITY - Returns the + * quality of the channel(in percentage) of the 3D Vision Pro transceiver. + * Use the display_mask parameter to specify the channel number. + */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_QUALITY 371 /* R--T */ + +/* + * NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_COUNT - Returns the number of + * channels on the 3D Vision Pro transceiver. + */ +#define NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_COUNT 372 /* R--T */ + +/* + * NV_CTRL_3D_VISION_PRO_PAIR_GLASSES - Puts the 3D Vision Pro + * transceiver into pairing mode to gather additional glasses. + * NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_STOP - stops any pairing + * NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON - starts continuous + * pairing via beacon mode + * Any other value, N - Puts the 3D Vision Pro transceiver into + * authenticated pairing mode for N seconds. + */ +#define NV_CTRL_3D_VISION_PRO_PAIR_GLASSES 373 /* -W-T */ +#define NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_STOP 0 +#define NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON 0xFFFFFFFF + +/* + * NV_CTRL_3D_VISION_PRO_UNPAIR_GLASSES - Tells a specific pair + * of glasses to unpair. The glasses will "forget" the address + * of the 3D Vision Pro transceiver to which they have been paired. + * To unpair all the currently paired glasses, specify + * the glasses id as 0. + */ +#define NV_CTRL_3D_VISION_PRO_UNPAIR_GLASSES 374 /* -W-T */ + +/* + * NV_CTRL_3D_VISION_PRO_DISCOVER_GLASSES - Tells the 3D Vision Pro + * transceiver about the glasses that have been paired using + * NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON. Unless this is done, + * the 3D Vision Pro transceiver will not know about glasses paired in + * beacon mode. + */ +#define NV_CTRL_3D_VISION_PRO_DISCOVER_GLASSES 375 /* -W-T */ + +/* + * NV_CTRL_3D_VISION_PRO_IDENTIFY_GLASSES - Causes glasses LEDs to + * flash for a short period of time. + */ +#define NV_CTRL_3D_VISION_PRO_IDENTIFY_GLASSES 376 /* -W-T */ + +/* + * NV_CTRL_3D_VISION_PRO_GLASSES_SYNC_CYCLE - Controls the + * sync cycle duration(in milliseconds) of the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_3D_VISION_PRO_GLASSES_SYNC_CYCLE 378 /* RW-T */ + +/* + * NV_CTRL_3D_VISION_PRO_GLASSES_MISSED_SYNC_CYCLES - Returns the + * number of state sync cycles recently missed by the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_3D_VISION_PRO_GLASSES_MISSED_SYNC_CYCLES 379 /* R--T */ + +/* + * NV_CTRL_3D_VISION_PRO_GLASSES_BATTERY_LEVEL - Returns the + * battery level(in percentage) of the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_3D_VISION_PRO_GLASSES_BATTERY_LEVEL 380 /* R--T */ + +/* + * NV_CTRL_GVO_ANC_PARITY_COMPUTATION - Controls the SDI device's computation + * of the parity bit (bit 8) for ANC data words. + */ + +#define NV_CTRL_GVO_ANC_PARITY_COMPUTATION 381 /* RW--- */ +#define NV_CTRL_GVO_ANC_PARITY_COMPUTATION_AUTO 0 +#define NV_CTRL_GVO_ANC_PARITY_COMPUTATION_ON 1 +#define NV_CTRL_GVO_ANC_PARITY_COMPUTATION_OFF 2 + +/* + * NV_CTRL_3D_VISION_PRO_GLASSES_PAIR_EVENT - This attribute is sent + * as an event when glasses get paired in response to pair command + * from any of the clients. + */ +#define NV_CTRL_3D_VISION_PRO_GLASSES_PAIR_EVENT 382 /* ---T */ + +/* + * NV_CTRL_3D_VISION_PRO_GLASSES_UNPAIR_EVENT - This attribute is sent + * as an event when glasses get unpaired in response to unpair command + * from any of the clients. + */ +#define NV_CTRL_3D_VISION_PRO_GLASSES_UNPAIR_EVENT 383 /* ---T */ + +/* + * NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH - returns the current + * PCIe link width, in number of lanes. + */ +#define NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH 384 /* R--GI */ + +/* + * NV_CTRL_GPU_PCIE_CURRENT_LINK_SPEED - returns the current + * PCIe link speed, in megatransfers per second (GT/s). + */ +#define NV_CTRL_GPU_PCIE_CURRENT_LINK_SPEED 385 /* R--GI */ + +/* + * NV_CTRL_GVO_AUDIO_BLANKING - specifies whether the GVO device should delete + * audio ancillary data packets when frames are repeated. + * + * When a new frame is not ready in time, the current frame, including all + * ancillary data packets, is repeated. When this data includes audio packets, + * this can result in stutters or clicks. When this option is enabled, the GVO + * device will detect when frames are repeated, identify audio ancillary data + * packets, and mark them for deletion. + * + * This option is applied when the GVO device is bound. + */ +#define NV_CTRL_GVO_AUDIO_BLANKING 386 /* RW- */ +#define NV_CTRL_GVO_AUDIO_BLANKING_DISABLE 0 +#define NV_CTRL_GVO_AUDIO_BLANKING_ENABLE 1 + +/* + * NV_CTRL_CURRENT_METAMODE_ID - switch modes to the MetaMode with + * the specified ID. + */ +#define NV_CTRL_CURRENT_METAMODE_ID 387 /* RW- */ + +/* + * NV_CTRL_DISPLAY_ENABLED - Returns whether or not the display device + * is currently enabled. + */ +#define NV_CTRL_DISPLAY_ENABLED 388 /* R-D */ +#define NV_CTRL_DISPLAY_ENABLED_TRUE 1 +#define NV_CTRL_DISPLAY_ENABLED_FALSE 0 + +#define NV_CTRL_LAST_ATTRIBUTE NV_CTRL_DISPLAY_ENABLED + +/**************************************************************************/ + +/* + * String Attributes: + * + * String attributes can be queryied through the XNVCTRLQueryStringAttribute() + * and XNVCTRLQueryTargetStringAttribute() function calls. + * + * String attributes can be set through the XNVCTRLSetStringAttribute() + * function call. (There are currently no string attributes that can be + * set on non-X Screen targets.) + * + * Unless otherwise noted, all string attributes can be queried/set using an + * NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take an + * NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried/set through + * XNVCTRLQueryStringAttribute()/XNVCTRLSetStringAttribute() (Since + * these assume an X Screen target). + */ + +/* + * NV_CTRL_STRING_PRODUCT_NAME - the GPU product name on which the + * specified X screen is running. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_PRODUCT_NAME 0 /* R--G */ + +/* + * NV_CTRL_STRING_VBIOS_VERSION - the video bios version on the GPU on + * which the specified X screen is running. + */ + +#define NV_CTRL_STRING_VBIOS_VERSION 1 /* R--G */ + +/* + * NV_CTRL_STRING_NVIDIA_DRIVER_VERSION - string representation of the + * NVIDIA driver version number for the NVIDIA X driver in use. + */ + +#define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION 3 /* R--G */ + +/* + * NV_CTRL_STRING_DISPLAY_DEVICE_NAME - name of the display device + * specified in the display_mask argument. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_DISPLAY_DEVICE_NAME 4 /* R-DG */ + +/* + * NV_CTRL_STRING_TV_ENCODER_NAME - name of the TV encoder used by the + * specified display device; only valid if the display device is a TV. + */ + +#define NV_CTRL_STRING_TV_ENCODER_NAME 5 /* R-DG */ + +/* + * NV_CTRL_STRING_GVIO_FIRMWARE_VERSION - indicates the version of the + * Firmware on the GVIO device. + */ + +#define NV_CTRL_STRING_GVIO_FIRMWARE_VERSION 8 /* R--I */ + +/* + * The following is deprecated; use NV_CTRL_STRING_GVIO_FIRMWARE_VERSION, + * instead + */ +#define NV_CTRL_STRING_GVO_FIRMWARE_VERSION 8 /* R-- */ + +/* + * NV_CTRL_STRING_CURRENT_MODELINE - Return the ModeLine currently + * being used by the specified display device. + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * + * The ModeLine string may be prepended with a comma-separated list of + * "token=value" pairs, separated from the ModeLine string by "::". + * This "token=value" syntax is the same as that used in + * NV_CTRL_BINARY_DATA_MODELINES + */ + +#define NV_CTRL_STRING_CURRENT_MODELINE 9 /* R-DG */ + +/* + * NV_CTRL_STRING_ADD_MODELINE - Adds a ModeLine to the specified + * display device. The ModeLine is not added if validation fails. + * + * The ModeLine string should have the same syntax as a ModeLine in + * the X configuration file; e.g., + * + * "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync + */ + +#define NV_CTRL_STRING_ADD_MODELINE 10 /* -WDG */ + +/* + * NV_CTRL_STRING_DELETE_MODELINE - Deletes an existing ModeLine + * from the specified display device. The currently selected + * ModeLine cannot be deleted. (This also means you cannot delete + * the last ModeLine.) + * + * The ModeLine string should have the same syntax as a ModeLine in + * the X configuration file; e.g., + * + * "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync + */ + +#define NV_CTRL_STRING_DELETE_MODELINE 11 /* -WDG */ + +/* + * NV_CTRL_STRING_CURRENT_METAMODE - Returns the metamode currently + * being used by the specified X screen. The MetaMode string has the + * same syntax as the MetaMode X configuration option, as documented + * in the NVIDIA driver README. + * + * The returned string may be prepended with a comma-separated list of + * "token=value" pairs, separated from the MetaMode string by "::". + * This "token=value" syntax is the same as that used in + * NV_CTRL_BINARY_DATA_METAMODES. + */ + +#define NV_CTRL_STRING_CURRENT_METAMODE 12 /* RW-- */ +#define NV_CTRL_STRING_CURRENT_METAMODE_VERSION_1 NV_CTRL_STRING_CURRENT_METAMODE + +/* + * NV_CTRL_STRING_ADD_METAMODE - Adds a MetaMode to the specified + * X Screen. + * + * It is recommended to not use this attribute, but instead use + * NV_CTRL_STRING_OPERATION_ADD_METAMODE. + */ + +#define NV_CTRL_STRING_ADD_METAMODE 13 /* -W-- */ + +/* + * NV_CTRL_STRING_DELETE_METAMODE - Deletes an existing MetaMode from + * the specified X Screen. The currently selected MetaMode cannot be + * deleted. (This also means you cannot delete the last MetaMode). + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + */ + +#define NV_CTRL_STRING_DELETE_METAMODE 14 /* -WD-- */ + +/* + * NV_CTRL_STRING_VCSC_PRODUCT_NAME - Querys the product name of the + * VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_PRODUCT_NAME 15 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_PRODUCT_ID - Querys the product ID of the VCSC device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_PRODUCT_ID 16 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_SERIAL_NUMBER - Querys the unique serial number + * of the VCS device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_SERIAL_NUMBER 17 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_BUILD_DATE - Querys the date of the VCS device. + * the returned string is in the following format: "Week.Year" + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_BUILD_DATE 18 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_FIRMWARE_VERSION - Querys the firmware version + * of the VCS device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_FIRMWARE_VERSION 19 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_FIRMWARE_REVISION - Querys the firmware revision + * of the VCS device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCS target. + */ + +#define NV_CTRL_STRING_VCSC_FIRMWARE_REVISION 20 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_HARDWARE_VERSION - Querys the hardware version + * of the VCS device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_HARDWARE_VERSION 21 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_HARDWARE_REVISION - Querys the hardware revision + * of the VCS device. + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + */ + +#define NV_CTRL_STRING_VCSC_HARDWARE_REVISION 22 /* R---V */ + +/* + * NV_CTRL_STRING_MOVE_METAMODE - Moves a MetaMode to the specified + * index location. The MetaMode must already exist in the X Screen's + * list of MetaModes (as returned by the NV_CTRL_BINARY_DATA_METAMODES + * attribute). If the index is larger than the number of MetaModes in + * the list, the MetaMode is moved to the end of the list. The + * MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + + * The MetaMode string must be prepended with a comma-separated list + * of "token=value" pairs, separated from the MetaMode string by "::". + * Currently, the only valid token is "index", which indicates where + * in the MetaMode list the MetaMode should be moved to. + * + * Other tokens may be added in the future. + * + * E.g., + * "index=5 :: CRT-0: 1024x768 @1024x768 +0+0" + */ + +#define NV_CTRL_STRING_MOVE_METAMODE 23 /* -W-- */ + +/* + * NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES - returns the valid + * horizontal sync ranges used to perform mode validation for the + * specified display device. The ranges are in the same format as the + * "HorizSync" X config option: + * + * "horizsync-range may be a comma separated list of either discrete + * values or ranges of values. A range of values is two values + * separated by a dash." + * + * The values are in kHz. + * + * Additionally, the string may be prepended with a comma-separated + * list of "token=value" pairs, separated from the HorizSync string by + * "::". Valid tokens: + * + * Token Value + * "source" "edid" - HorizSync is from the display device's EDID + * "xconfig" - HorizSync is from the "HorizSync" entry in + * the Monitor section of the X config file + * "option" - HorizSync is from the "HorizSync" NVIDIA X + * config option + * "twinview" - HorizSync is from the "SecondMonitorHorizSync" + * NVIDIA X config option + * "builtin" - HorizSync is from NVIDIA X driver builtin + * default values + * + * Additional tokens and/or values may be added in the future. + * + * Example: "source=edid :: 30.000-62.000" + */ + +#define NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES 24 /* R-DG */ + +/* + * NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES - returns the valid + * vertical refresh ranges used to perform mode validation for the + * specified display device. The ranges are in the same format as the + * "VertRefresh" X config option: + * + * "vertrefresh-range may be a comma separated list of either discrete + * values or ranges of values. A range of values is two values + * separated by a dash." + * + * The values are in Hz. + * + * Additionally, the string may be prepended with a comma-separated + * list of "token=value" pairs, separated from the VertRefresh string by + * "::". Valid tokens: + * + * Token Value + * "source" "edid" - VertRefresh is from the display device's EDID + * "xconfig" - VertRefresh is from the "VertRefresh" entry in + * the Monitor section of the X config file + * "option" - VertRefresh is from the "VertRefresh" NVIDIA X + * config option + * "twinview" - VertRefresh is from the "SecondMonitorVertRefresh" + * NVIDIA X config option + * "builtin" - VertRefresh is from NVIDIA X driver builtin + * default values + * + * Additional tokens and/or values may be added in the future. + * + * Example: "source=edid :: 50.000-75.000" + */ + +#define NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES 25 /* R-DG */ + +/* + * NV_CTRL_STRING_XINERAMA_SCREEN_INFO - returns the physical X Screen's + * initial position and size (in absolute coordinates) within the Xinerama + * desktop as the "token=value" string: "x=#, y=#, width=#, height=#" + * + * Querying this attribute returns FALSE if NV_CTRL_XINERAMA is not + * NV_CTRL_XINERAMA_ON. + */ + +#define NV_CTRL_STRING_XINERAMA_SCREEN_INFO 26 /* R--- */ + +/* + * NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER - used to specify the + * order that display devices will be returned via Xinerama when + * nvidiaXineramaInfo is enabled. Follows the same syntax as the + * nvidiaXineramaInfoOrder X config option. + */ + +#define NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER 27 /* RW-- */ + +#define NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER \ + NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER /* for backwards compatibility: */ + +/* + * NV_CTRL_STRING_SLI_MODE - returns a string describing the current + * SLI mode, if any, or FALSE if SLI is not currently enabled. + * + * This string should be used for informational purposes only, and + * should not be used to distinguish between SLI modes, other than to + * recognize when SLI is disabled (FALSE is returned) or + * enabled (the returned string is non-NULL and describes the current + * SLI configuration). + */ + +#define NV_CTRL_STRING_SLI_MODE 28 /* R---*/ + +/* + * NV_CTRL_STRING_PERFORMANCE_MODES - returns a string with all the + * performance modes defined for this GPU along with their associated + * NV Clock and Memory Clock values. + * + * Each performance modes are returned as a comma-separated list of + * "token=value" pairs. Each set of performance mode tokens are separated + * by a ";". Valid tokens: + * + * Token Value + * "perf" integer - the Performance level + * "nvclock" integer - the GPU clocks (in MHz) for the perf level + * "memclock" integer - the memory clocks (in MHz) for the perf level + * + * + * Example: + * + * perf=0, nvclock=500, memclock=505 ; perf=1, nvclock=650, memclock=505 + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_PERFORMANCE_MODES 29 /* R--G */ + +/* + * NV_CTRL_STRING_VCSC_FAN_STATUS - returns a string with status of all the + * fans in the Visual Computing System, if such a query is supported. Fan + * information is reported along with its tachometer reading (in RPM) and a + * flag indicating whether the fan has failed or not. + * + * Valid tokens: + * + * Token Value + * "fan" integer - the Fan index + * "speed" integer - the tachometer reading of the fan in rpm + * "fail" integer - flag to indicate whether the fan has failed + * + * Example: + * + * fan=0, speed=694, fail=0 ; fan=1, speed=693, fail=0 + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + * + */ + +#define NV_CTRL_STRING_VCSC_FAN_STATUS 30 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_TEMPERATURES - returns a string with all Temperature + * readings in the Visual Computing System, if such a query is supported. + * Intake, Exhaust and Board Temperature values are reported in Celcius. + * + * Valid tokens: + * + * Token Value + * "intake" integer - the intake temperature for the VCS + * "exhaust" integer - the exhaust temperature for the VCS + * "board" integer - the board temperature of the VCS + * + * Example: + * + * intake=29, exhaust=46, board=41 + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + * + */ + +#define NV_CTRL_STRING_VCSC_TEMPERATURES 31 /* R---V */ + +/* + * NV_CTRL_STRING_VCSC_PSU_INFO - returns a string with all Power Supply Unit + * related readings in the Visual Computing System, if such a query is + * supported. Current in amperes, Power in watts, Voltage in volts and PSU + * state may be reported. Not all PSU types support all of these values, and + * therefore some readings may be unknown. + * + * Valid tokens: + * + * Token Value + * "current" integer - the current drawn in amperes by the VCS + * "power" integer - the power drawn in watts by the VCS + * "voltage" integer - the voltage reading of the VCS + * "state" integer - flag to indicate whether PSU is operating normally + * + * Example: + * + * current=10, power=15, voltage=unknown, state=normal + * + * This attribute must be queried through XNVCTRLQueryTargetStringAttribute() + * using a NV_CTRL_TARGET_TYPE_VCSC target. + * + */ + +#define NV_CTRL_STRING_VCSC_PSU_INFO 32 /* R---V */ + +/* + * NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME - query the name for the specified + * NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be queried with existing + * interfaces, XNVCTRLQueryStringAttribute() should be used, and the video + * format specified in the display_mask field; eg: + * + * XNVCTRLQueryStringAttribute(dpy, + * screen, + * NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296, + * NV_CTRL_GVIO_VIDEO_FORMAT_NAME, + * &name); + */ + +#define NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME 33 /* R--GI */ + +/* + * The following is deprecated; use NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME, + * instead + */ +#define NV_CTRL_STRING_GVO_VIDEO_FORMAT_NAME 33 /* R--- */ + +/* + * NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS - returns a string with the + * associated NV Clock, Memory Clock and Processor Clock values. + * + * Current valid tokens are "nvclock", "memclock", and "processorclock". + * Not all tokens will be reported on all GPUs, and additional tokens + * may be added in the future. + * + * Clock values are returned as a comma-separated list of + * "token=value" pairs. + * Valid tokens: + * + * Token Value + * "nvclock" integer - the GPU clocks (in MHz) for the current + * perf level + * "memclock" integer - the memory clocks (in MHz) for the current + * perf level + * "processorclock" integer - the processor clocks (in MHz) for the perf level + * + * + * Example: + * + * nvclock=459, memclock=400, processorclock=918 + * + * This attribute may be queried through XNVCTRLQueryTargetStringAttribute() + * using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS 34 /* RW-G */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_HARDWARE_REVISION - Returns the + * hardware revision of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_HARDWARE_REVISION 35 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_A - Returns the + * firmware version of chip A of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_A 36 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_A - Returns the + * date of the firmware of chip A of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_A 37 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_B - Returns the + * firmware version of chip B of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_B 38 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_B - Returns the + * date of the firmware of chip B of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_B 39 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_ADDRESS - Returns the RF address + * of the 3D Vision Pro transceiver. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_ADDRESS 40 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_VERSION_A - Returns the + * firmware version of chip A of the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_VERSION_A 41 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_DATE_A - Returns the + * date of the firmware of chip A of the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_DATE_A 42 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_GLASSES_ADDRESS - Returns the RF address + * of the glasses. + * Use the display_mask parameter to specify the glasses id. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_GLASSES_ADDRESS 43 /* R--T */ + +/* + * NV_CTRL_STRING_3D_VISION_PRO_GLASSES_NAME - Controls the name the + * glasses should use. + * Use the display_mask parameter to specify the glasses id. + * Glasses' name should start and end with an alpha-numeric character. + */ +#define NV_CTRL_STRING_3D_VISION_PRO_GLASSES_NAME 44 /* RW-T */ + +/* + * NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2 - Returns the metamode currently + * being used by the specified X screen. The MetaMode string has the same + * syntax as the MetaMode X configuration option, as documented in the NVIDIA + * driver README. Also, see NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 for more + * details on the base syntax. + * + * The returned string may also be prepended with a comma-separated list of + * "token=value" pairs, separated from the MetaMode string by "::". + */ +#define NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2 45 /* RW-- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME - Returns a type name for the + * display device ("CRT", "DFP", or "TV"). However, note that the determination + * of the name is based on the protocol through which the X driver communicates + * to the display device. E.g., if the driver communicates using VGA ,then the + * basename is "CRT"; if the driver communicates using TMDS, LVDS, or DP, then + * the name is "DFP". + */ +#define NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME 46 /* R-D- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_TYPE_ID - Returns the type-based name + ID for + * the display device, e.g. "CRT-0", "DFP-1", "TV-2". If this device is a + * DisplayPort 1.2 device, then this name will also be prepended with the + * device's port address like so: "DFP-1.0.1.2.3". See + * NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME for more information about the + * construction of type-based names. + */ +#define NV_CTRL_STRING_DISPLAY_NAME_TYPE_ID 47 /* R-D- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_DP_GUID - Returns the GUID of the DisplayPort + * display device. e.g. "DP-GUID-f16a5bde-79f3-11e1-b2ae-8b5a8969ba9c" + * + * The display device must be a DisplayPort 1.2 device. + */ +#define NV_CTRL_STRING_DISPLAY_NAME_DP_GUID 48 /* R-D- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_EDID_HASH - Returns the SHA-1 hash of the + * display device's EDID in 8-4-4-4-12 UID format. e.g. + * "DPY-EDID-f16a5bde-79f3-11e1-b2ae-8b5a8969ba9c" + * + * The display device must have a valid EDID. + */ +#define NV_CTRL_STRING_DISPLAY_NAME_EDID_HASH 49 /* R-D- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX - Returns the current NV-CONTROL + * target ID (name) of the display device. e.g. "DPY-1", "DPY-4" + * + * This name for the display device is not guarenteed to be the same between + * different runs of the X server. + */ +#define NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX 50 /* R-D- */ + +/* + * NV_CTRL_STRING_DISPLAY_NAME_RANDR - Returns the RandR output name for the + * display device. e.g. "VGA-1", "DVI-I-0", "DVI-D-3", "LVDS-1", "DP-2", + * "HDMI-3", "eDP-6". This name should match If this device is a DisplayPort + * 1.2 device, then this name will also be prepended with the device's port + * address like so: "DVI-I-3.0.1.2.3" + */ +#define NV_CTRL_STRING_DISPLAY_NAME_RANDR 51 /* R-D- */ + +#define NV_CTRL_STRING_LAST_ATTRIBUTE NV_CTRL_STRING_DISPLAY_NAME_RANDR + +/**************************************************************************/ + +/* + * Binary Data Attributes: + * + * Binary data attributes can be queryied through the XNVCTRLQueryBinaryData() + * and XNVCTRLQueryTargetBinaryData() function calls. + * + * There are currently no binary data attributes that can be set. + * + * Unless otherwise noted, all Binary data attributes can be queried + * using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take + * an NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried through + * XNVCTRLQueryBinaryData() (Since an X Screen target is assumed). + */ + +/* + * NV_CTRL_BINARY_DATA_EDID - Returns a display device's EDID information + * data. + * + * This attribute may be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_BINARY_DATA_EDID 0 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_MODELINES - Returns a display device's supported + * ModeLines. ModeLines are returned in a buffer, separated by a single + * '\0' and terminated by two consecutive '\0' s like so: + * + * "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0" + * + * This attribute may be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. + * + * Each ModeLine string may be prepended with a comma-separated list + * of "token=value" pairs, separated from the ModeLine string with a + * "::". Valid tokens: + * + * Token Value + * "source" "xserver" - the ModeLine is from the core X server + * "xconfig" - the ModeLine was specified in the X config file + * "builtin" - the NVIDIA driver provided this builtin ModeLine + * "vesa" - this is a VESA standard ModeLine + * "edid" - the ModeLine was in the display device's EDID + * "nv-control" - the ModeLine was specified via NV-CONTROL + * + * "xconfig-name" - for ModeLines that were specified in the X config + * file, this is the name the X config file + * gave for the ModeLine. + * + * Note that a ModeLine can have several sources; the "source" token + * can appear multiple times in the "token=value" pairs list. + * Additional source values may be specified in the future. + * + * Additional tokens may be added in the future, so it is recommended + * that any token parser processing the returned string from + * NV_CTRL_BINARY_DATA_MODELINES be implemented to gracefully ignore + * unrecognized tokens. + * + * E.g., + * + * "source=xserver, source=vesa, source=edid :: "1024x768_70" 75.0 1024 1048 1184 1328 768 771 + * 777 806 -HSync -VSync" + * "source=xconfig, xconfig-name=1600x1200_60.00 :: "1600x1200_60_0" 161.0 1600 1704 1880 2160 + * 1200 1201 1204 1242 -HSync +VSync" + */ + +#define NV_CTRL_BINARY_DATA_MODELINES 1 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_METAMODES - Returns an X Screen's supported + * MetaModes. MetaModes are returned in a buffer separated by a + * single '\0' and terminated by two consecutive '\0' s like so: + * + * "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" + * + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + + * Each MetaMode string may be prepended with a comma-separated list + * of "token=value" pairs, separated from the MetaMode string with + * "::". Currently, valid tokens are: + * + * Token Value + * "id" - the id of this MetaMode; this is stored in + * the Vertical Refresh field, as viewed + * by the XRandR and XF86VidMode X * + * extensions. + * + * "switchable" "yes"/"no" - whether this MetaMode may be switched to via + * ctrl-alt-+/-; Implicit MetaModes (see + * the "IncludeImplicitMetaModes" X + * config option), for example, are not + * normally made available through + * ctrl-alt-+/-. + * + * "source" "xconfig" - the MetaMode was specified in the X + * config file. + * "implicit" - the MetaMode was implicitly added; see the + * "IncludeImplicitMetaModes" X config option + * for details. + * "nv-control" - the MetaMode was added via the NV-CONTROL X + * extension to the currently running X server. + * "RandR" - the MetaMode was modified in response to an + * RandR RRSetCrtcConfig request. + * + * Additional tokens may be added in the future, so it is recommended + * that any token parser processing the returned string from + * NV_CTRL_BINARY_DATA_METAMODES be implemented to gracefully ignore + * unrecognized tokens. + * + * E.g., + * + * "id=50, switchable=yes, source=xconfig :: CRT-0: 1024x768 @1024x768 +0+0" + */ + +#define NV_CTRL_BINARY_DATA_METAMODES 2 /* R-D- */ +#define NV_CTRL_BINARY_DATA_METAMODES_VERSION_1 NV_CTRL_BINARY_DATA_METAMODES + +/* + * NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU - Returns the list of X + * screens currently driven by the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of screens + * 4 * n CARD32 screen indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU 3 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN - Returns the list of GPUs + * currently in use by the given X screen. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + */ + +#define NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN 4 /* R--- */ + +/* + * NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK - Returns the list of + * GPUs currently connected to the given frame lock board. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK 5 /* R-DF */ + +/* + * NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT - Returns the Display Device's + * viewport box into the given X Screen (in X Screen coordinates.) + * + * The format of the returned data is: + * + * 4 CARD32 Offset X + * 4 CARD32 Offset Y + * 4 CARD32 Width + * 4 CARD32 Height + */ + +#define NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT 6 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU - Returns the list of + * Framelock devices currently connected to the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of Framelocks + * 4 * n CARD32 Framelock indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. + */ + +#define NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU 7 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_GPUS_USING_VCSC - Returns the list of + * GPU devices connected to the given VCS. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_VCSC target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN and cannot be queried using + * a NV_CTRL_TARGET_TYPE_X_GPU + */ + +#define NV_CTRL_BINARY_DATA_GPUS_USING_VCSC 8 /* R-DV */ + +/* + * NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU - Returns the VCSC device + * that is controlling the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of VCS (always 1) + * 4 * n CARD32 VCS indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN + */ + +#define NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU 9 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU - Returns the coolers that + * are cooling the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of COOLER + * 4 * n CARD32 COOLER indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN + */ + +#define NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU 10 /* R-DG */ + +/* + * NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN - Returns the list of + * GPUs currently driving the given X screen. If Xinerama is enabled, this + * will return all GPUs that are driving any X screen. + * + * The format of the returned data is: + * + * 4 CARD32 number of GPUs + * 4 * n CARD32 GPU indices + */ + +#define NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN 11 /* R--- */ + +/* + * NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU - Returns the sensors that + * are attached to the given GPU. + * + * The format of the returned data is: + * + * 4 CARD32 number of SENSOR + * 4 * n CARD32 SENSOR indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be + * queried using a NV_CTRL_TARGET_TYPE_X_SCREEN + */ + +#define NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU 12 /* R--G */ + +/* + * NV_CTRL_BINARY_DATA_GLASSES_PAIRED_TO_3D_VISION_PRO_TRANSCEIVER - Returns + * the id of the glasses that are currently paired to the given + * 3D Vision Pro transceiver. + * + * The format of the returned data is: + * + * 4 CARD32 number of glasses + * 4 * n CARD32 id of glasses + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER target. + */ +#define NV_CTRL_BINARY_DATA_GLASSES_PAIRED_TO_3D_VISION_PRO_TRANSCEIVER 13 /* R--T */ + +/* + * NV_CTRL_BINARY_DATA_DISPLAY_TARGETS - Returns all the display devices + * currently connected to any GPU on the X server. + * + * The format of the returned data is: + * + * 4 CARD32 number of display devices + * 4 * n CARD32 display device indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData(). + */ + +#define NV_CTRL_BINARY_DATA_DISPLAY_TARGETS 14 /* R--- */ + +/* + * NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU - Returns the list of + * display devices that are connected to the GPU target. + * + * The format of the returned data is: + * + * 4 CARD32 number of display devices + * 4 * n CARD32 display device indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_GPU target. + */ + +#define NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU 15 /* R--G */ + +/* + * NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 - Returns values similar to + * NV_CTRL_BINARY_DATA_METAMODES(_VERSION_1) but also returns extended syntax + * information to indicate a specific display device, as well as other per- + * display deviceflags as "token=value" pairs. For example: + * + * "DPY-1: 1280x1024 {Stereo=PassiveLeft}, + * DPY-2: 1280x1024 {Stereo=PassiveRight}," + * + * The display device names have the form "DPY-%d", where the integer + * part of the name is the NV-CONTROL target ID for that display device + * for this instance of the X server. Note that display device NV-CONTROL + * target IDs are not guaranteed to be the same from one run of the X + * server to the next. + */ + +#define NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 16 /* R-D- */ + +/* + * NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN - Returns the list of + * display devices that are currently scanning out the X screen target. + * + * The format of the returned data is: + * + * 4 CARD32 number of display devices + * 4 * n CARD32 display device indices + * + * This attribute can only be queried through XNVCTRLQueryTargetBinaryData() + * using a NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +#define NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN 17 /* R--- */ + +#define NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN + +/**************************************************************************/ + +/* + * String Operation Attributes: + * + * These attributes are used with the XNVCTRLStringOperation() + * function; a string is specified as input, and a string is returned + * as output. + * + * Unless otherwise noted, all attributes can be operated upon using + * an NV_CTRL_TARGET_TYPE_X_SCREEN target. + */ + +/* + * NV_CTRL_STRING_OPERATION_ADD_METAMODE - provide a MetaMode string + * as input, and returns a string containing comma-separated list of + * "token=value" pairs as output. Currently, the only output token is + * "id", which indicates the id that was assigned to the MetaMode. + * + * All ModeLines referenced in the MetaMode must already exist for + * each display device (as returned by the + * NV_CTRL_BINARY_DATA_MODELINES attribute). + * + * The MetaMode string should have the same syntax as the MetaMode X + * configuration option, as documented in the NVIDIA driver README. + * + * The input string can optionally be prepended with a string of + * comma-separated "token=value" pairs, separated from the MetaMode + * string by "::". Currently, the only valid token is "index" which + * indicates the insertion index for the MetaMode. + * + * E.g., + * + * Input: "index=5 :: 1600x1200+0+0, 1600x1200+1600+0" + * Output: "id=58" + * + * which causes the MetaMode to be inserted at position 5 in the + * MetaMode list (all entries after 5 will be shifted down one slot in + * the list), and the X server's containing mode stores 58 as the + * VRefresh, so that the MetaMode can be uniquely identifed through + * XRandR and XF86VidMode. + */ + +#define NV_CTRL_STRING_OPERATION_ADD_METAMODE 0 + +/* + * NV_CTRL_STRING_OPERATION_GTF_MODELINE - provide as input a string + * of comma-separated "token=value" pairs, and returns a ModeLine + * string, computed using the GTF formula using the parameters from + * the input string. Valid tokens for the input string are "width", + * "height", and "refreshrate". + * + * E.g., + * + * Input: "width=1600, height=1200, refreshrate=60" + * Output: "160.96 1600 1704 1880 2160 1200 1201 1204 1242 -HSync +VSync" + * + * This operation does not have any impact on any display device's + * modePool, and the ModeLine is not validated; it is simply intended + * for generating ModeLines. + */ + +#define NV_CTRL_STRING_OPERATION_GTF_MODELINE 1 + +/* + * NV_CTRL_STRING_OPERATION_CVT_MODELINE - provide as input a string + * of comma-separated "token=value" pairs, and returns a ModeLine + * string, computed using the CVT formula using the parameters from + * the input string. Valid tokens for the input string are "width", + * "height", "refreshrate", and "reduced-blanking". The + * "reduced-blanking" argument can be "0" or "1", to enable or disable + * use of reduced blanking for the CVT formula. + * + * E.g., + * + * Input: "width=1600, height=1200, refreshrate=60, reduced-blanking=1" + * Output: "130.25 1600 1648 1680 1760 1200 1203 1207 1235 +HSync -VSync" + * + * This operation does not have any impact on any display device's + * modePool, and the ModeLine is not validated; it is simply intended + * for generating ModeLines. + */ + +#define NV_CTRL_STRING_OPERATION_CVT_MODELINE 2 + +/* + * NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL - build a ModePool for the + * specified display device on the specified target (either an X + * screen or a GPU). This is typically used to generate a ModePool + * for a display device on a GPU on which no X screens are present. + * + * Currently, a display device's ModePool is static for the life of + * the X server, so XNVCTRLStringOperation will return FALSE if + * requested to build a ModePool on a display device that already has + * a ModePool. + * + * The string input to BUILD_MODEPOOL may be NULL. If it is not NULL, + * then it is interpreted as a double-colon ("::") separated list + * of "option=value" pairs, where the options and the syntax of their + * values are the X configuration options that impact the behavior of + * modePool construction; namely: + * + * "ModeValidation" + * "HorizSync" + * "VertRefresh" + * "FlatPanelProperties" + * "TVStandard" + * "ExactModeTimingsDVI" + * "UseEdidFreqs" + * + * An example input string might look like: + * + * "ModeValidation=NoVesaModes :: HorizSync=50-110 :: VertRefresh=50-150" + * + * This request currently does not return a string. + */ + +#define NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL 3 /* DG */ + +/* + * NV_CTRL_STRING_OPERATION_GVI_CONFIGURE_STREAMS - Configure the streams- + * to-jack+channel topology for a GVI (Graphics capture board). + * + * The string input to GVI_CONFIGURE_STREAMS may be NULL. If this is the + * case, then the current topology is returned. + * + * If the input string to GVI_CONFIGURE_STREAMS is not NULL, the string + * is interpreted as a semicolon (";") separated list of comma-separated + * lists of "option=value" pairs that define a stream's composition. The + * available options and their values are: + * + * "stream": Defines which stream this comma-separated list describes. + * Valid values are the integers between 0 and + * NV_CTRL_GVI_NUM_STREAMS-1 (inclusive). + * + * "linkN": Defines a jack+channel pair to use for the given link N. + * Valid options are the string "linkN", where N is an integer + * between 0 and NV_CTRL_GVI_MAX_LINKS_PER_STREAM-1 (inclusive). + * Valid values for these options are strings of the form + * "jackX" and/or "jackX.Y", where X is an integer between 0 and + * NV_CTRL_GVI_NUM_JACKS-1 (inclusive), and Y (optional) is an + * integer between 0 and NV_CTRL_GVI_MAX_CHANNELS_PER_JACK-1 + * (inclusive). + * + * An example input string might look like: + * + * "stream=0, link0=jack0, link1=jack1; stream=1, link0=jack2.1" + * + * This example specifies two streams, stream 0 and stream 1. Stream 0 + * is defined to capture link0 data from the first channel (channel 0) of + * BNC jack 0 and link1 data from the first channel of BNC jack 1. The + * second stream (Stream 1) is defined to capture link0 data from channel 1 + * (second channel) of BNC jack 2. + * + * This example shows a possible configuration for capturing 3G input: + * + * "stream=0, link0=jack0.0, link1=jack0.1" + * + * Applications should query the following attributes to determine + * possible combinations: + * + * NV_CTRL_GVI_MAX_STREAMS + * NV_CTRL_GVI_MAX_LINKS_PER_STREAM + * NV_CTRL_GVI_NUM_JACKS + * NV_CTRL_GVI_MAX_CHANNELS_PER_JACK + * + * Note: A jack+channel pair can only be tied to one link/stream. + * + * Upon successful configuration or querying of this attribute, a string + * representing the current topology for all known streams on the device + * will be returned. On failure, NULL is returned. + * + * Note: Setting this attribute may also result in the following + * NV-CONTROL attributes being reset on the GVI device (to ensure + * the configuration remains valid): + * NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT + * NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT + * NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING + */ + +#define NV_CTRL_STRING_OPERATION_GVI_CONFIGURE_STREAMS 4 /* RW-I */ + +#define NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE NV_CTRL_STRING_OPERATION_GVI_CONFIGURE_STREAMS + +/**************************************************************************/ + +/* + * CTRLAttributeValidValuesRec - + * + * structure and related defines used by + * XNVCTRLQueryValidAttributeValues() to describe the valid values of + * a particular attribute. The type field will be one of: + * + * ATTRIBUTE_TYPE_INTEGER : the attribute is an integer value; there + * is no fixed range of valid values. + * + * ATTRIBUTE_TYPE_BITMASK : the attribute is an integer value, + * interpretted as a bitmask. + * + * ATTRIBUTE_TYPE_BOOL : the attribute is a boolean, valid values are + * either 1 (on/true) or 0 (off/false). + * + * ATTRIBUTE_TYPE_RANGE : the attribute can have any integer value + * between NVCTRLAttributeValidValues.u.range.min and + * NVCTRLAttributeValidValues.u.range.max (inclusive). + * + * ATTRIBUTE_TYPE_INT_BITS : the attribute can only have certain + * integer values, indicated by which bits in + * NVCTRLAttributeValidValues.u.bits.ints are on (for example: if bit + * 0 is on, then 0 is a valid value; if bit 5 is on, then 5 is a valid + * value, etc). This is useful for attributes like NV_CTRL_FSAA_MODE, + * which can only have certain values, depending on GPU. + * + * ATTRIBUTE_TYPE_64BIT_INTEGER : the attribute is a 64 bit integer value; + * there is no fixed range of valid values. + * + * ATTRIBUTE_TYPE_STRING : the attribute is a string value; there is no fixed + * range of valid values. + * + * ATTRIBUTE_TYPE_BINARY_DATA : the attribute is binary data; there is + * no fixed range of valid values. + * + * ATTRIBUTE_TYPE_STRING_OPERATION : the attribute is a string; there is + * no fixed range of valid values. + * + * + * The permissions field of NVCTRLAttributeValidValuesRec is a bitmask + * that may contain: + * + * ATTRIBUTE_TYPE_READ - Attribute may be read (queried.) + * ATTRIBUTE_TYPE_WRITE - Attribute may be written to (set.) + * ATTRIBUTE_TYPE_DISPLAY - Attribute is valid for display target types + * (requires a display_mask if queried via + * a GPU or X screen.) + * ATTRIBUTE_TYPE_GPU - Attribute is valid for GPU target types. + * ATTRIBUTE_TYPE_FRAMELOCK - Attribute is valid for Frame Lock target types. + * ATTRIBUTE_TYPE_X_SCREEN - Attribute is valid for X Screen target types. + * ATTRIBUTE_TYPE_XINERAMA - Attribute will be made consistent for all + * X Screens when the Xinerama extension is enabled. + * ATTRIBUTE_TYPE_VCSC - Attribute is valid for Visual Computing System + * target types. + * ATTRIBUTE_TYPE_GVI - Attribute is valid for Graphics Video In target + * types. + * ATTRIBUTE_TYPE_COOLER - Attribute is valid for Cooler target types. + * ATTRIBUTE_TYPE_3D_VISION_PRO_TRANSCEIVER - Attribute is valid for 3D Vision + * Pro Transceiver target types. + * + * See 'Key to Integer Attribute "Permissions"' at the top of this + * file for a description of what these permission bits mean. + */ + +#define ATTRIBUTE_TYPE_UNKNOWN 0 +#define ATTRIBUTE_TYPE_INTEGER 1 +#define ATTRIBUTE_TYPE_BITMASK 2 +#define ATTRIBUTE_TYPE_BOOL 3 +#define ATTRIBUTE_TYPE_RANGE 4 +#define ATTRIBUTE_TYPE_INT_BITS 5 +#define ATTRIBUTE_TYPE_64BIT_INTEGER 6 +#define ATTRIBUTE_TYPE_STRING 7 +#define ATTRIBUTE_TYPE_BINARY_DATA 8 +#define ATTRIBUTE_TYPE_STRING_OPERATION 9 + +#define ATTRIBUTE_TYPE_READ 0x001 +#define ATTRIBUTE_TYPE_WRITE 0x002 +#define ATTRIBUTE_TYPE_DISPLAY 0x004 +#define ATTRIBUTE_TYPE_GPU 0x008 +#define ATTRIBUTE_TYPE_FRAMELOCK 0x010 +#define ATTRIBUTE_TYPE_X_SCREEN 0x020 +#define ATTRIBUTE_TYPE_XINERAMA 0x040 +#define ATTRIBUTE_TYPE_VCSC 0x080 +#define ATTRIBUTE_TYPE_GVI 0x100 +#define ATTRIBUTE_TYPE_COOLER 0x200 +#define ATTRIBUTE_TYPE_THERMAL_SENSOR 0x400 +#define ATTRIBUTE_TYPE_3D_VISION_PRO_TRANSCEIVER 0x800 + +#define ATTRIBUTE_TYPE_ALL_TARGETS \ + ((ATTRIBUTE_TYPE_DISPLAY) | (ATTRIBUTE_TYPE_GPU) | (ATTRIBUTE_TYPE_FRAMELOCK) | \ + (ATTRIBUTE_TYPE_X_SCREEN) | (ATTRIBUTE_TYPE_VCSC) | (ATTRIBUTE_TYPE_GVI) | \ + (ATTRIBUTE_TYPE_COOLER) | (ATTRIBUTE_TYPE_THERMAL_SENSOR) | \ + (ATTRIBUTE_TYPE_3D_VISION_PRO_TRANSCEIVER)) + +typedef struct _NVCTRLAttributeValidValues +{ + int type; + union + { + struct + { + int64_t min; + int64_t max; + } range; + struct + { + unsigned int ints; + } bits; + } u; + unsigned int permissions; +} NVCTRLAttributeValidValuesRec; + +typedef struct _NVCTRLAttributePermissions +{ + int type; + unsigned int permissions; +} NVCTRLAttributePermissionsRec; + +/**************************************************************************/ + +/* + * NV-CONTROL X event notification. + * + * To receive X event notifications dealing with NV-CONTROL, you should + * call XNVCtrlSelectNotify() with one of the following set as the type + * of event to receive (see NVCtrlLib.h for more information): + */ + +#define ATTRIBUTE_CHANGED_EVENT 0 +#define TARGET_ATTRIBUTE_CHANGED_EVENT 1 +#define TARGET_ATTRIBUTE_AVAILABILITY_CHANGED_EVENT 2 +#define TARGET_STRING_ATTRIBUTE_CHANGED_EVENT 3 +#define TARGET_BINARY_ATTRIBUTE_CHANGED_EVENT 4 + +#endif /* __NVCTRL_H */ diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrlLib.h b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrlLib.h new file mode 100644 index 0000000000..1a5d5decfa --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/NVCtrlLib.h @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2008 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __NVCTRLLIB_H +#define __NVCTRLLIB_H + +#include "NVCtrl.h" + +#if defined __cplusplus +extern "C" { +#endif + +/* + * XNVCTRLQueryExtension - + * + * Returns True if the extension exists, returns False otherwise. + * event_basep and error_basep are the extension event and error + * bases. Currently, no extension specific errors or events are + * defined. + */ + +Bool XNVCTRLQueryExtension(Display *dpy, int *event_basep, int *error_basep); + +/* + * XNVCTRLQueryVersion - + * + * Returns True if the extension exists, returns False otherwise. + * major and minor are the extension's major and minor version + * numbers. + */ + +Bool XNVCTRLQueryVersion(Display *dpy, int *major, int *minor); + +/* + * XNVCTRLIsNvScreen + * + * Returns True is the specified screen is controlled by the NVIDIA + * driver. Returns False otherwise. + */ + +Bool XNVCTRLIsNvScreen(Display *dpy, int screen); + +/* + * XNVCTRLQueryTargetCount - + * + * Returns True if the target type exists. Returns False otherwise. + * If XNVCTRLQueryTargetCount returns True, value will contain the + * count of existing targets on the server of the specified target + * type. + * + * Please see "Attribute Targets" in NVCtrl.h for the list of valid + * target types. + * + * Possible errors: + * BadValue - The target doesn't exist. + */ + +Bool XNVCTRLQueryTargetCount(Display *dpy, int target_type, int *value); + +/* + * XNVCTRLSetAttribute - + * + * Sets the attribute to the given value. The attributes and their + * possible values are listed in NVCtrl.h. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Calling this function is equivalent to calling XNVCTRLSetTargetAttribute() + * with the target_type set to NV_CTRL_TARGET_TYPE_X_SCREEN and + * target_id set to 'screen'. + * + * Possible errors: + * BadValue - The screen or attribute doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + */ + +void XNVCTRLSetAttribute(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int value); + +/* + * XNVCTRLSetTargetAttribute - + * + * Sets the attribute to the given value. The attributes and their + * possible values are listed in NVCtrl.h. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Possible errors: + * BadValue - The target or attribute doesn't exist. + * BadMatch - The NVIDIA driver is not present on that target. + */ + +void XNVCTRLSetTargetAttribute(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int value); + +/* + * XNVCTRLSetAttributeAndGetStatus - + * + * Same as XNVCTRLSetAttribute(). + * In addition, XNVCTRLSetAttributeAndGetStatus() returns + * True if the operation succeeds, False otherwise. + * + */ + +Bool XNVCTRLSetAttributeAndGetStatus(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int value); + +/* + * XNVCTRLSetTargetAttributeAndGetStatus - + * + * Same as XNVCTRLSetTargetAttribute(). + * In addition, XNVCTRLSetTargetAttributeAndGetStatus() returns + * True if the operation succeeds, False otherwise. + * + */ + +Bool XNVCTRLSetTargetAttributeAndGetStatus(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int value); + +/* + * XNVCTRLQueryAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryAttribute returns True, value will contain the + * value of the specified attribute. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetAttribute() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * + * Possible errors: + * BadValue - The screen doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + */ + +Bool XNVCTRLQueryAttribute(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + int *value); + +/* + * XNVCTRLQueryTargetAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetAttribute returns True, value will contain the + * value of the specified attribute. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + */ + +Bool XNVCTRLQueryTargetAttribute(Display *dpy, + int target_Type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int *value); + +/* + * XNVCTRLQueryTargetAttribute64 - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetAttribute returns True, value will contain the + * value of the specified attribute. + * + * Not all attributes require the display_mask parameter; see + * NVCtrl.h for details. + * + * Note: this function behaves like XNVCTRLQueryTargetAttribute(), + * but supports 64-bit integer attributes. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + */ + +Bool XNVCTRLQueryTargetAttribute64(Display *dpy, + int target_Type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + int64_t *value); + +/* + * XNVCTRLQueryStringAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryStringAttribute returns True, *ptr will point to an + * allocated string containing the string attribute requested. It is + * the caller's responsibility to free the string when done. + * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetStringAttribute() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * + * Possible errors: + * BadValue - The screen doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryStringAttribute(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + char **ptr); + +/* + * XNVCTRLQueryTargetStringAttribute - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetStringAttribute returns True, *ptr will point + * to an allocated string containing the string attribute requested. + * It is the caller's responsibility to free the string when done. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryTargetStringAttribute(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char **ptr); + +/* + * XNVCTRLSetStringAttribute - + * + * Returns True if the operation succeded. Returns False otherwise. + * + * Possible X errors: + * BadValue - The screen doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLSetStringAttribute(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + char *ptr); + +/* + * XNVCTRLSetTargetStringAttribute - + * + * Returns True if the operation succeded. Returns False otherwise. + * + * Possible X errors: + * BadValue - The screen doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLSetTargetStringAttribute(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *ptr); + +/* + * XNVCTRLQueryValidAttributeValues - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryValidAttributeValues returns True, values will indicate + * the valid values for the specified attribute; see the description + * of NVCTRLAttributeValidValues in NVCtrl.h. + * + * Calling this function is equivalent to calling + * XNVCTRLQueryValidTargetAttributeValues() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + */ + +Bool XNVCTRLQueryValidAttributeValues(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values); + +/* + * XNVCTRLQueryValidTargetAttributeValues - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryValidTargetAttributeValues returns True, values will indicate + * the valid values for the specified attribute. + */ + +Bool XNVCTRLQueryValidTargetAttributeValues(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values); + +/* + * XNVCTRLQueryValidTargetStringAttributeValues - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryValidTargetStringAttributeValues returns True, values will + * indicate the valid values for the specified attribute. + */ + +Bool XNVCTRLQueryValidTargetStringAttributeValues(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + NVCTRLAttributeValidValuesRec *values); + +/* + * XNVCTRLQueryAttributePermissions - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryAttributePermissions returns True, permissions will + * indicate the permission flags for the attribute. + */ + +Bool XNVCTRLQueryAttributePermissions(Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions); + +/* + * XNVCTRLQueryStringAttributePermissions - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryStringAttributePermissions returns True, permissions will + * indicate the permission flags for the attribute. + */ + +Bool XNVCTRLQueryStringAttributePermissions(Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions); + +/* + * XNVCTRLQueryBinaryDataAttributePermissions - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryBinaryDataAttributePermissions returns True, permissions + * will indicate the permission flags for the attribute. + */ + +Bool XNVCTRLQueryBinaryDataAttributePermissions(Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions); + +/* + * XNVCTRLQueryStringOperationAttributePermissions - + * + * Returns True if the attribute exists. Returns False otherwise. If + * XNVCTRLQueryStringOperationAttributePermissions returns True, + * permissions will indicate the permission flags for the attribute. + */ + +Bool XNVCTRLQueryStringOperationAttributePermissions(Display *dpy, + unsigned int attribute, + NVCTRLAttributePermissionsRec *permissions); + +/* + * XNVCTRLSetGvoColorConversion - + * + * Sets the color conversion matrix, offset, and scale that should be + * used for GVO (Graphic to Video Out). + * + * The Color Space Conversion data is ordered like this: + * + * colorMatrix[0][0] // r.Y + * colorMatrix[0][1] // g.Y + * colorMatrix[0][2] // b.Y + * + * colorMatrix[1][0] // r.Cr + * colorMatrix[1][1] // g.Cr + * colorMatrix[1][2] // b.Cr + * + * colorMatrix[2][0] // r.Cb + * colorMatrix[2][1] // g.Cb + * colorMatrix[2][2] // b.Cb + * + * colorOffset[0] // Y + * colorOffset[1] // Cr + * colorOffset[2] // Cb + * + * colorScale[0] // Y + * colorScale[1] // Cr + * colorScale[2] // Cb + * + * where the data is used according to the following formulae: + * + * Y = colorOffset[0] + colorScale[0] * + * (R * colorMatrix[0][0] + + * G * colorMatrix[0][1] + + * B * colorMatrix[0][2]); + * + * Cr = colorOffset[1] + colorScale[1] * + * (R * colorMatrix[1][0] + + * G * colorMatrix[1][1] + + * B * colorMatrix[1][2]); + * + * Cb = colorOffset[2] + colorScale[2] * + * (R * colorMatrix[2][0] + + * G * colorMatrix[2][1] + + * B * colorMatrix[2][2]); + * + * Possible errors: + * BadMatch - The NVIDIA driver is not present on that screen. + * BadImplementation - GVO is not available on that screen. + */ + +void XNVCTRLSetGvoColorConversion(Display *dpy, + int screen, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]); + +/* + * XNVCTRLQueryGvoColorConversion - + * + * Retrieves the color conversion matrix and color offset + * that are currently being used for GVO (Graphic to Video Out). + * + * The values are ordered within the arrays according to the comments + * for XNVCTRLSetGvoColorConversion(). + * + * Possible errors: + * BadMatch - The NVIDIA driver is not present on that screen. + * BadImplementation - GVO is not available on that screen. + */ + +Bool XNVCTRLQueryGvoColorConversion(Display *dpy, + int screen, + float colorMatrix[3][3], + float colorOffset[3], + float colorScale[3]); + +/* + * XNVCTRLQueryBinaryData - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryBinaryData returns True, *ptr will point to an + * allocated block of memory containing the binary data attribute + * requested. It is the caller's responsibility to free the data + * when done. len will list the length of the binary data. + * + * Calling this function is equivalent to calling + * XNVCTRLQueryTargetBinaryData() with the target_type set to + * NV_CTRL_TARGET_TYPE_X_SCREEN and target_id set to 'screen'. + * + * Possible errors: + * BadValue - The screen doesn't exist. + * BadMatch - The NVIDIA driver is not present on that screen. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryBinaryData(Display *dpy, + int screen, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len); + +/* + * XNVCTRLQueryTargetBinaryData - + * + * Returns True if the attribute exists. Returns False otherwise. + * If XNVCTRLQueryTargetBinaryData returns True, *ptr will point to an + * allocated block of memory containing the binary data attribute + * requested. It is the caller's responsibility to free the data + * when done. len will list the length of the binary data. + * + * Possible errors: + * BadValue - The target doesn't exist. + * BadMatch - The NVIDIA driver does not control the target. + * BadAlloc - Insufficient resources to fulfill the request. + */ + +Bool XNVCTRLQueryTargetBinaryData(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + unsigned char **ptr, + int *len); + +/* + * XNVCTRLStringOperation - + * + * Takes a string as input and returns a Xmalloc'ed string as output. + * Returns True on success and False on failure. + */ + +Bool XNVCTRLStringOperation(Display *dpy, + int target_type, + int target_id, + unsigned int display_mask, + unsigned int attribute, + char *pIn, + char **ppOut); + +/* + * XNVCtrlSelectNotify - + * + * This enables/disables receiving of NV-CONTROL events. The type + * specifies the type of event to enable (currently, the only + * type that can be requested per-screen with XNVCtrlSelectNotify() + * is ATTRIBUTE_CHANGED_EVENT); onoff controls whether receiving this + * type of event should be enabled (True) or disabled (False). + * + * Returns True if successful, or False if the screen is not + * controlled by the NVIDIA driver. + */ + +Bool XNVCtrlSelectNotify(Display *dpy, int screen, int type, Bool onoff); + +/* + * XNVCtrlSelectTargetNotify - + * + * This enables/disables receiving of NV-CONTROL events that happen on + * the specified target. The notify_type specifies the type of event to + * enable (currently, the only type that can be requested per-target with + * XNVCtrlSelectTargetNotify() is TARGET_ATTRIBUTE_CHANGED_EVENT); onoff + * controls whether receiving this type of event should be enabled (True) + * or disabled (False). + * + * Returns True if successful, or False if the target is not + * controlled by the NVIDIA driver. + */ + +Bool XNVCtrlSelectTargetNotify(Display *dpy, + int target_type, + int target_id, + int notify_type, + Bool onoff); + +/* + * XNVCtrlEvent structure + */ + +typedef struct +{ + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int screen; + unsigned int display_mask; + unsigned int attribute; + int value; +} XNVCtrlAttributeChangedEvent; + +typedef union +{ + int type; + XNVCtrlAttributeChangedEvent attribute_changed; + long pad[24]; +} XNVCtrlEvent; + +/* + * XNVCtrlEventTarget structure + */ + +typedef struct +{ + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int target_type; + int target_id; + unsigned int display_mask; + unsigned int attribute; + int value; +} XNVCtrlAttributeChangedEventTarget; + +typedef union +{ + int type; + XNVCtrlAttributeChangedEventTarget attribute_changed; + long pad[24]; +} XNVCtrlEventTarget; + +/* + * XNVCtrlEventTargetAvailability structure + */ + +typedef struct +{ + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int target_type; + int target_id; + unsigned int display_mask; + unsigned int attribute; + int value; + Bool availability; +} XNVCtrlAttributeChangedEventTargetAvailability; + +typedef union +{ + int type; + XNVCtrlAttributeChangedEventTargetAvailability attribute_changed; + long pad[24]; +} XNVCtrlEventTargetAvailability; + +/* + * XNVCtrlStringEventTarget structure + */ + +typedef struct +{ + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int target_type; + int target_id; + unsigned int display_mask; + unsigned int attribute; +} XNVCtrlStringAttributeChangedEventTarget; + +typedef union +{ + int type; + XNVCtrlStringAttributeChangedEventTarget attribute_changed; + long pad[24]; +} XNVCtrlStringEventTarget; + +/* + * XNVCtrlBinaryEventTarget structure + */ + +typedef struct +{ + int type; + unsigned long serial; + Bool send_event; /* always FALSE, we don't allow send_events */ + Display *display; + Time time; + int target_type; + int target_id; + unsigned int display_mask; + unsigned int attribute; +} XNVCtrlBinaryAttributeChangedEventTarget; + +typedef union +{ + int type; + XNVCtrlBinaryAttributeChangedEventTarget attribute_changed; + long pad[24]; +} XNVCtrlBinaryEventTarget; + +#if defined __cplusplus +} /* extern "C" */ +#endif + +#endif /* __NVCTRLLIB_H */ diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/README.angle b/src/3rdparty/angle/src/third_party/libXNVCtrl/README.angle new file mode 100644 index 0000000000..22b9bd0aac --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/README.angle @@ -0,0 +1,14 @@ +Name: NVidia Control X Extension Library +Short Name: libXNVCtrl +URL: http://cgit.freedesktop.org/~aplattner/nvidia-settings/ +Version: unknown +Date: 2008 +License: MIT +Security Critical: no + +Description: +This package provides access to NVidia Control X Extension. It is used to determine the version of the NVIDIA driver in use. + +The current version is pulled from nvidia-settings-302.17. + +Local Modifications: diff --git a/src/3rdparty/angle/src/third_party/libXNVCtrl/nv_control.h b/src/3rdparty/angle/src/third_party/libXNVCtrl/nv_control.h new file mode 100644 index 0000000000..5023c9b58c --- /dev/null +++ b/src/3rdparty/angle/src/third_party/libXNVCtrl/nv_control.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2008 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + * NV-CONTROL Protocol Version History + * + * 1.0 - 1.5 NVIDIA Internal development versions + * 1.6 Initial public version + * 1.7 Added QueryBinaryData request + * 1.8 Added TargetTypes + * 1.9 Added QueryTargetCount request + * 1.10 Fixed target type/id byte ordering for compatibility with + * pre-1.8 NV-CONTROL clients + * 1.11 NVIDIA Internal development version + * 1.12 Added StringOperation request + * 1.13 NVIDIA Internal development version + * 1.14 Fixed an NV_CTRL_BINARY_DATA_MODELINES double scan modeline + * reporting bug (vsyncstart, vsyncend, and vtotal were incorrectly + * doubled) + * 1.15 Added AVAILABILITY_TARGET_ATTRIBUTE_CHANGED_EVENT + * 1.16 Added TARGET_STRING_ATTRIBUTE_CHANGED_EVENT + * 1.17 Added TARGET_BINARY_ATTRIBUTE_CHANGED_EVENT + * 1.18 Updated QueryTargetCount to return a count of 0, rather than + * BadMatch, if an unknown TargetType is specified + * 1.19 Added TargetType support for SetAttributeAndGetStatus and + * SetStringAttribute requests + * 1.20 Added COOLER TargetType + * 1.21 Added initial 64-bit integer attribute support (read-only) + * 1.22 Added X_nvCtrlQueryValidStringAttributeValues to check + * string attribute permissions. + * 1.23 Added SENSOR TargetType + * 1.24 Fixed a bug where SLI_MOSAIC_MODE_AVAILABLE attribute would + * report false positives via the GPU and X screen target types + * 1.25 Added 3D_VISION_PRO_TRANSCEIVER TargetType + * 1.26 Added XNVCTRLQueryXXXAttributePermissions. + * 1.27 Added DISPLAY TargetType + * 1.28 Added NV_CTRL_CURRENT_METAMODE_ID: clients should use this + * attribute to switch MetaModes, rather than pass the MetaMode ID + * through the RRSetScreenConfig protocol request. + */ + +#ifndef __NVCONTROL_H +#define __NVCONTROL_H + +#define NV_CONTROL_ERRORS 0 +#define NV_CONTROL_EVENTS 5 +#define NV_CONTROL_NAME "NV-CONTROL" + +#define NV_CONTROL_MAJOR 1 +#define NV_CONTROL_MINOR 28 + +#define X_nvCtrlQueryExtension 0 +#define X_nvCtrlIsNv 1 +#define X_nvCtrlQueryAttribute 2 +#define X_nvCtrlSetAttribute 3 +#define X_nvCtrlQueryStringAttribute 4 +#define X_nvCtrlQueryValidAttributeValues 5 +#define X_nvCtrlSelectNotify 6 +#define X_nvCtrlSetGvoColorConversionDeprecated 7 +#define X_nvCtrlQueryGvoColorConversionDeprecated 8 +#define X_nvCtrlSetStringAttribute 9 +/* STUB X_nvCtrlQueryDDCCILutSize 10 */ +/* STUB X_nvCtrlQueryDDCCISinglePointLutOperation 11 */ +/* STUB X_nvCtrlSetDDCCISinglePointLutOperation 12 */ +/* STUB X_nvCtrlQueryDDCCIBlockLutOperation 13 */ +/* STUB X_nvCtrlSetDDCCIBlockLutOperation 14 */ +/* STUB X_nvCtrlSetDDCCIRemoteProcedureCall 15 */ +/* STUB X_nvCtrlQueryDDCCIDisplayControllerType 16 */ +/* STUB X_nvCtrlQueryDDCCICapabilities 17 */ +/* STUB X_nvCtrlQueryDDCCITimingReport 18 */ +#define X_nvCtrlSetAttributeAndGetStatus 19 +#define X_nvCtrlQueryBinaryData 20 +#define X_nvCtrlSetGvoColorConversion 21 +#define X_nvCtrlQueryGvoColorConversion 22 +#define X_nvCtrlSelectTargetNotify 23 +#define X_nvCtrlQueryTargetCount 24 +#define X_nvCtrlStringOperation 25 +#define X_nvCtrlQueryValidAttributeValues64 26 +#define X_nvCtrlQueryAttribute64 27 +#define X_nvCtrlQueryValidStringAttributeValues 28 +#define X_nvCtrlQueryAttributePermissions 29 +#define X_nvCtrlQueryStringAttributePermissions 30 +#define X_nvCtrlQueryBinaryDataAttributePermissions 31 +#define X_nvCtrlQueryStringOperationAttributePermissions 32 + +#define X_nvCtrlLastRequest (X_nvCtrlQueryStringOperationAttributePermissions + 1) + +/* Define 32 bit floats */ +typedef float FLOAT32; +#ifndef F32 +#define F32 +#endif + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; +} xnvCtrlQueryExtensionReq; +#define sz_xnvCtrlQueryExtensionReq 4 + +typedef struct +{ + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD16 major B16; + CARD16 minor B16; + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; + CARD32 padl8 B32; +} xnvCtrlQueryExtensionReply; +#define sz_xnvCtrlQueryExtensionReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; +} xnvCtrlIsNvReq; +#define sz_xnvCtrlIsNvReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 isnv B32; + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; + CARD32 padl8 B32; +} xnvCtrlIsNvReply; +#define sz_xnvCtrlIsNvReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 target_type B32; +} xnvCtrlQueryTargetCountReq; +#define sz_xnvCtrlQueryTargetCountReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 count B32; + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; + CARD32 padl8 B32; +} xnvCtrlQueryTargetCountReply; +#define sz_xnvCtrlQueryTargetCountReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; +} xnvCtrlQueryAttributeReq; +#define sz_xnvCtrlQueryAttributeReq 16 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + INT32 value B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlQueryAttributeReply; +#define sz_xnvCtrlQueryAttributeReply 32 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + CARD32 pad3 B32; + int64_t value_64; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlQueryAttribute64Reply; +#define sz_xnvCtrlQueryAttribute64Reply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; + CARD16 target_type B16; + CARD32 display_mask B32; + CARD32 attribute B32; + INT32 value B32; +} xnvCtrlSetAttributeReq; +#define sz_xnvCtrlSetAttributeReq 20 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; + CARD16 target_type B16; + CARD32 display_mask B32; + CARD32 attribute B32; + INT32 value B32; +} xnvCtrlSetAttributeAndGetStatusReq; +#define sz_xnvCtrlSetAttributeAndGetStatusReq 20 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlSetAttributeAndGetStatusReply; +#define sz_xnvCtrlSetAttributeAndGetStatusReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; +} xnvCtrlQueryStringAttributeReq; +#define sz_xnvCtrlQueryStringAttributeReq 16 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + CARD32 n B32; /* Length of string */ + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlQueryStringAttributeReply; +#define sz_xnvCtrlQueryStringAttributeReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; + CARD16 target_type B16; + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 num_bytes B32; +} xnvCtrlSetStringAttributeReq; +#define sz_xnvCtrlSetStringAttributeReq 20 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlSetStringAttributeReply; +#define sz_xnvCtrlSetStringAttributeReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; +} xnvCtrlQueryValidAttributeValuesReq; +#define sz_xnvCtrlQueryValidAttributeValuesReq 16 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + INT32 attr_type B32; + INT32 min B32; + INT32 max B32; + CARD32 bits B32; + CARD32 perms B32; +} xnvCtrlQueryValidAttributeValuesReply; +#define sz_xnvCtrlQueryValidAttributeValuesReply 32 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + INT32 attr_type B32; + int64_t min_64; + int64_t max_64; + CARD64 bits_64; + CARD32 perms B32; + CARD32 pad1 B32; +} xnvCtrlQueryValidAttributeValues64Reply; +#define sz_xnvCtrlQueryValidAttributeValues64Reply 48 +#define sz_xnvCtrlQueryValidAttributeValues64Reply_extra ((48 - 32) >> 2) + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 attribute B32; +} xnvCtrlQueryAttributePermissionsReq; +#define sz_xnvCtrlQueryAttributePermissionsReq 8 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + INT32 attr_type B32; + CARD32 perms B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xnvCtrlQueryAttributePermissionsReply; +#define sz_xnvCtrlQueryAttributePermissionsReply 32 + +/* Set GVO Color Conversion request (deprecated) */ +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; + FLOAT32 row1_col1 F32; + FLOAT32 row1_col2 F32; + FLOAT32 row1_col3 F32; + FLOAT32 row1_col4 F32; + FLOAT32 row2_col1 F32; + FLOAT32 row2_col2 F32; + FLOAT32 row2_col3 F32; + FLOAT32 row2_col4 F32; + FLOAT32 row3_col1 F32; + FLOAT32 row3_col2 F32; + FLOAT32 row3_col3 F32; + FLOAT32 row3_col4 F32; +} xnvCtrlSetGvoColorConversionDeprecatedReq; +#define sz_xnvCtrlSetGvoColorConversionDeprecatedReq 56 + +/* Query GVO Color Conversion request (deprecated) */ +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; +} xnvCtrlQueryGvoColorConversionDeprecatedReq; +#define sz_xnvCtrlQueryGvoColorConversionDeprecatedReq 8 + +/* Query GVO Color Conversion reply (deprecated) */ +typedef struct +{ + BYTE type; /* X_Reply */ + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xnvCtrlQueryGvoColorConversionDeprecatedReply; +#define sz_xnvCtrlQueryGvoColorConversionDeprecatedReply 32 + +/* Set GVO Color Conversion request */ +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; + + FLOAT32 cscMatrix_y_r F32; + FLOAT32 cscMatrix_y_g F32; + FLOAT32 cscMatrix_y_b F32; + + FLOAT32 cscMatrix_cr_r F32; + FLOAT32 cscMatrix_cr_g F32; + FLOAT32 cscMatrix_cr_b F32; + + FLOAT32 cscMatrix_cb_r F32; + FLOAT32 cscMatrix_cb_g F32; + FLOAT32 cscMatrix_cb_b F32; + + FLOAT32 cscOffset_y F32; + FLOAT32 cscOffset_cr F32; + FLOAT32 cscOffset_cb F32; + + FLOAT32 cscScale_y F32; + FLOAT32 cscScale_cr F32; + FLOAT32 cscScale_cb F32; + +} xnvCtrlSetGvoColorConversionReq; +#define sz_xnvCtrlSetGvoColorConversionReq 68 + +/* Query GVO Color Conversion request */ +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; +} xnvCtrlQueryGvoColorConversionReq; +#define sz_xnvCtrlQueryGvoColorConversionReq 8 + +/* Query GVO Color Conversion reply */ +typedef struct +{ + BYTE type; /* X_Reply */ + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xnvCtrlQueryGvoColorConversionReply; +#define sz_xnvCtrlQueryGvoColorConversionReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; +} xnvCtrlQueryBinaryDataReq; +#define sz_xnvCtrlQueryBinaryDataReq 16 + +typedef struct +{ + BYTE type; + BYTE pad0; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 flags B32; + CARD32 n B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xnvCtrlQueryBinaryDataReply; +#define sz_xnvCtrlQueryBinaryDataReply 32 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD32 screen B32; + CARD16 notifyType B16; + CARD16 onoff B16; +} xnvCtrlSelectNotifyReq; +#define sz_xnvCtrlSelectNotifyReq 12 + +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_id B16; /* X screen number or GPU number */ + CARD16 target_type B16; /* X screen or GPU */ + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 num_bytes B32; /* Length of string */ +} xnvCtrlStringOperationReq; +#define sz_xnvCtrlStringOperationReq 20 + +typedef struct +{ + BYTE type; /* X_Reply */ + CARD8 padb1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ret B32; + CARD32 num_bytes B32; /* Length of string */ + CARD32 padl4 B32; + CARD32 padl5 B32; + CARD32 padl6 B32; + CARD32 padl7 B32; +} xnvCtrlStringOperationReply; +#define sz_xnvCtrlStringOperationReply 32 + +typedef struct +{ + union + { + struct + { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + } u; + struct + { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + CARD32 time B32; + CARD32 screen B32; + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 value B32; + CARD32 pad0 B32; + CARD32 pad1 B32; + } attribute_changed; + } u; +} xnvctrlEvent; + +/* + * Leave target_type before target_id for the + * xnvCtrlSelectTargetNotifyReq and xnvctrlEventTarget + * structures, even though other request protocol structures + * store target_id in the bottom 16-bits of the second DWORD of the + * structures. The event-related structures were added in version + * 1.8, and so there is no prior version with which to maintain + * compatibility. + */ +typedef struct +{ + CARD8 reqType; + CARD8 nvReqType; + CARD16 length B16; + CARD16 target_type B16; /* Don't swap these */ + CARD16 target_id B16; + CARD16 notifyType B16; + CARD16 onoff B16; +} xnvCtrlSelectTargetNotifyReq; +#define sz_xnvCtrlSelectTargetNotifyReq 12 + +typedef struct +{ + union + { + struct + { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + } u; + struct + { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + CARD32 time B32; + CARD16 target_type B16; /* Don't swap these */ + CARD16 target_id B16; + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 value B32; + CARD32 pad0 B32; + CARD32 pad1 B32; + } attribute_changed; + struct + { + BYTE type; + BYTE detail; + CARD16 sequenceNumber B16; + CARD32 time B32; + CARD16 target_type B16; /* Don't swap these */ + CARD16 target_id B16; + CARD32 display_mask B32; + CARD32 attribute B32; + CARD32 value B32; + CARD8 availability; + CARD8 pad0; + CARD16 pad1 B16; + CARD32 pad2 B32; + } availability_changed; + } u; +} xnvctrlEventTarget; + +#endif /* __NVCONTROL_H */ diff --git a/src/3rdparty/angle/src/third_party/murmurhash/LICENSE b/src/3rdparty/angle/src/third_party/murmurhash/LICENSE deleted file mode 100644 index 6a385f0f07..0000000000 --- a/src/3rdparty/angle/src/third_party/murmurhash/LICENSE +++ /dev/null @@ -1,2 +0,0 @@ -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. \ No newline at end of file diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp deleted file mode 100644 index aa7982d3ee..0000000000 --- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp +++ /dev/null @@ -1,335 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -// Note - The x86 and x64 versions do _not_ produce the same results, as the -// algorithms are optimized for their respective platforms. You can still -// compile and run any of them on any platform, but your performance with the -// non-native version will be less than optimal. - -#include "MurmurHash3.h" - -//----------------------------------------------------------------------------- -// Platform-specific functions and macros - -// Microsoft Visual Studio - -#if defined(_MSC_VER) - -#define FORCE_INLINE __forceinline - -#include - -#define ROTL32(x,y) _rotl(x,y) -#define ROTL64(x,y) _rotl64(x,y) - -#define BIG_CONSTANT(x) (x) - -// Other compilers - -#else // defined(_MSC_VER) - -#define FORCE_INLINE inline __attribute__((always_inline)) - -inline uint32_t rotl32 ( uint32_t x, int8_t r ) -{ - return (x << r) | (x >> (32 - r)); -} - -inline uint64_t rotl64 ( uint64_t x, int8_t r ) -{ - return (x << r) | (x >> (64 - r)); -} - -#define ROTL32(x,y) rotl32(x,y) -#define ROTL64(x,y) rotl64(x,y) - -#define BIG_CONSTANT(x) (x##LLU) - -#endif // !defined(_MSC_VER) - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) -{ - return p[i]; -} - -FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i ) -{ - return p[i]; -} - -//----------------------------------------------------------------------------- -// Finalization mix - force all bits of a hash block to avalanche - -FORCE_INLINE uint32_t fmix32 ( uint32_t h ) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -//---------- - -FORCE_INLINE uint64_t fmix64 ( uint64_t k ) -{ - k ^= k >> 33; - k *= BIG_CONSTANT(0xff51afd7ed558ccd); - k ^= k >> 33; - k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); - k ^= k >> 33; - - return k; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x86_32 ( const void * key, int len, - uint32_t seed, void * out ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 4; - - uint32_t h1 = seed; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - //---------- - // body - - const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); - - for(int i = -nblocks; i; i++) - { - uint32_t k1 = getblock32(blocks,i); - - k1 *= c1; - k1 = ROTL32(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = ROTL32(h1,13); - h1 = h1*5+0xe6546b64; - } - - //---------- - // tail - - const uint8_t * tail = (const uint8_t*)(data + nblocks*4); - - uint32_t k1 = 0; - - switch(len & 3) - { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0]; - k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - - h1 = fmix32(h1); - - *(uint32_t*)out = h1; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x86_128 ( const void * key, const int len, - uint32_t seed, void * out ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 16; - - uint32_t h1 = seed; - uint32_t h2 = seed; - uint32_t h3 = seed; - uint32_t h4 = seed; - - const uint32_t c1 = 0x239b961b; - const uint32_t c2 = 0xab0e9789; - const uint32_t c3 = 0x38b34ae5; - const uint32_t c4 = 0xa1e38b93; - - //---------- - // body - - const uint32_t * blocks = (const uint32_t *)(data + nblocks*16); - - for(int i = -nblocks; i; i++) - { - 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; - - h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; - - k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; - - h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; - - k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; - - h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; - - k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; - - h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; - } - - //---------- - // tail - - const uint8_t * tail = (const uint8_t*)(data + nblocks*16); - - uint32_t k1 = 0; - uint32_t k2 = 0; - uint32_t k3 = 0; - uint32_t k4 = 0; - - switch(len & 15) - { - case 15: k4 ^= tail[14] << 16; - case 14: k4 ^= tail[13] << 8; - case 13: k4 ^= tail[12] << 0; - k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; - - case 12: k3 ^= tail[11] << 24; - case 11: k3 ^= tail[10] << 16; - case 10: k3 ^= tail[ 9] << 8; - case 9: k3 ^= tail[ 8] << 0; - k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; - - case 8: k2 ^= tail[ 7] << 24; - case 7: k2 ^= tail[ 6] << 16; - case 6: k2 ^= tail[ 5] << 8; - case 5: k2 ^= tail[ 4] << 0; - k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; - - case 4: k1 ^= tail[ 3] << 24; - case 3: k1 ^= tail[ 2] << 16; - case 2: k1 ^= tail[ 1] << 8; - case 1: k1 ^= tail[ 0] << 0; - k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; - - h1 += h2; h1 += h3; h1 += h4; - h2 += h1; h3 += h1; h4 += h1; - - h1 = fmix32(h1); - h2 = fmix32(h2); - h3 = fmix32(h3); - h4 = fmix32(h4); - - h1 += h2; h1 += h3; h1 += h4; - h2 += h1; h3 += h1; h4 += h1; - - ((uint32_t*)out)[0] = h1; - ((uint32_t*)out)[1] = h2; - ((uint32_t*)out)[2] = h3; - ((uint32_t*)out)[3] = h4; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x64_128 ( const void * key, const int len, - const uint32_t seed, void * out ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 16; - - uint64_t h1 = seed; - uint64_t h2 = seed; - - const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); - const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); - - //---------- - // body - - const uint64_t * blocks = (const uint64_t *)(data); - - for(int i = 0; i < nblocks; i++) - { - 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; - - h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; - - k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; - - h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; - } - - //---------- - // tail - - const uint8_t * tail = (const uint8_t*)(data + nblocks*16); - - uint64_t k1 = 0; - uint64_t k2 = 0; - - 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; - 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; - k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = fmix64(h1); - h2 = fmix64(h2); - - h1 += h2; - h2 += h1; - - ((uint64_t*)out)[0] = h1; - ((uint64_t*)out)[1] = h2; -} - -//----------------------------------------------------------------------------- - diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h deleted file mode 100644 index e1c6d34976..0000000000 --- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h +++ /dev/null @@ -1,37 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -#ifndef _MURMURHASH3_H_ -#define _MURMURHASH3_H_ - -//----------------------------------------------------------------------------- -// 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 ); - -void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); - -void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); - -//----------------------------------------------------------------------------- - -#endif // _MURMURHASH3_H_ diff --git a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp index fc05526681..97dfcaac51 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 && WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP +#if _WIN32_WINNT_WINBLUE #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 3c85d22efa..bdb8804428 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 @@ -690,27 +690,27 @@ 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 angle::Platform::TraceEventHandle addTraceEvent( - char phase, - const unsigned char* categoryEnabled, - const char* name, - unsigned long long id, - unsigned char flags) { +static inline angle::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 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) { +template +static inline angle::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]; @@ -721,17 +721,17 @@ static inline angle::Platform::TraceEventHandle addTraceEvent( flags); } -template -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) { +template +static inline angle::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